changeset 90:6086085e153d

Added databinding snippets. unmodified java sources.
author Frank Benoit <benoit@tionex.de>
date Sun, 19 Apr 2009 11:33:55 +0200
parents 0ca1aee7decf
children 2755ef2c8ef8
files org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet001NestedSelectionWithCombo.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet002UpdateComboRetainSelection.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet003UpdateComboBindUsingViewer.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet004DataBindingContextErrorLabel.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet005MenuUpdater.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet006Spreadsheet.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet007ColorLabelProvider.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet008ComputedValue.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet009TableViewer.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet010MasterDetail.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet011ValidateMultipleBindingsSnippet.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet012CompositeUpdater.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet013TableViewerEditing.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet014WizardDialog.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet015DelayTextModifyEvents.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet016TableUpdater.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet017TableViewerWithDerivedColumns.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet018CheckboxTableViewerCheckedSelection.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet019TreeViewerWithListFactory.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet020TreeViewerWithSetFactory.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet021MultiFieldValidation.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet022ComputedListCombo.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet023ConditionalVisibility.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet024SelectObservableValue.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet025TableViewerWithPropertyDerivedColumns.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet026AnonymousBeanProperties.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet027ExternalValidator.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet028DuplexingObservableValue.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet029TreeViewerMultiListProperty.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet030DateAndTimeObservableValue.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet031JFaceObservable.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet032TableViewerColumnEditing.d org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet033CrossValidationControlDecoration.d
diffstat 33 files changed, 6788 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet001NestedSelectionWithCombo.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * Copyright (c) 2006 The Pampered Chef, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     The Pampered Chef, Inc. - initial API and implementation
+ *     Brad Reynolds - bug 116920
+ *     Matthew Hall - bug 260329
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayList;
+import java.util.HashSet;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeansObservables;
+import org.eclipse.core.databinding.observable.Observables;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.map.IObservableMap;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider;
+import org.eclipse.jface.databinding.viewers.ViewersObservables;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ListViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Demonstrates nested selection.<br>
+ * At the first level, user may select a person.<br>
+ * At the second level, user may select a city to associate with the selected<br>
+ * person or edit the person's name.
+ */
+public class Snippet001NestedSelectionWithCombo {
+	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.
+	// 
+	// This example implements full JavaBeans bound properties so that changes
+	// to instances of this class will automatically be propogated to the UI.
+	public static class Person extends AbstractModelObject {
+		// Constructor
+		public Person(String name, String city) {
+			this.name = name;
+			this.city = city;
+		}
+
+		// Some JavaBean bound properties...
+		String name;
+
+		String city;
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			String oldValue = this.name;
+			this.name = name;
+			firePropertyChange("name", oldValue, name);
+		}
+
+		public String getCity() {
+			return city;
+		}
+
+		public void setCity(String city) {
+			String oldValue = this.city;
+			this.city = city;
+			firePropertyChange("city", oldValue, city);
+		}
+	}
+
+	// The View's model--the root of our GUI's Model graph
+	//
+	// Typically each View class has a corresponding ViewModel class.
+	// The ViewModel is responsible for getting the objects to edit from the
+	// DAO. Since this snippet doesn't have any persistent objects to
+	// retrieve, this ViewModel just instantiates some objects to edit.
+	// 
+	// This ViewModel also implements JavaBean bound properties.
+	static class ViewModel extends AbstractModelObject {
+		// The model to bind
+		private ArrayList people = new ArrayList();
+		{
+			people.add(new Person("Wile E. Coyote", "Tucson"));
+			people.add(new Person("Road Runner", "Lost Horse"));
+			people.add(new Person("Bugs Bunny", "Forrest"));
+		}
+
+		// Choice of cities for the Combo
+		private ArrayList cities = new ArrayList();
+		{
+			cities.add("Tucson");
+			cities.add("AcmeTown");
+			cities.add("Lost Horse");
+			cities.add("Forrest");
+			cities.add("Lost Mine");
+		}
+
+		public ArrayList getPeople() {
+			return people;
+		}
+
+		public ArrayList getCities() {
+			return cities;
+		}
+	}
+
+	// The GUI view
+	static class View {
+		private ViewModel viewModel;
+
+		public View(ViewModel viewModel) {
+			this.viewModel = viewModel;
+		}
+
+		public Shell createShell() {
+			// Build a UI
+			Shell shell = new Shell(Display.getCurrent());
+			Realm realm = SWTObservables.getRealm(shell.getDisplay());
+
+			List peopleList = new List(shell, SWT.BORDER);
+			Text name = new Text(shell, SWT.BORDER);
+			Combo city = new Combo(shell, SWT.BORDER | SWT.READ_ONLY);
+
+			ListViewer peopleListViewer = new ListViewer(peopleList);
+			IObservableMap attributeMap = BeansObservables.observeMap(
+					Observables.staticObservableSet(realm, new HashSet(
+							viewModel.getPeople())), Person.class, "name");
+			peopleListViewer.setLabelProvider(new ObservableMapLabelProvider(
+					attributeMap));
+			peopleListViewer.setContentProvider(new ArrayContentProvider());
+			peopleListViewer.setInput(viewModel.getPeople());
+
+			DataBindingContext dbc = new DataBindingContext(realm);
+			IObservableValue selectedPerson = ViewersObservables
+					.observeSingleSelection(peopleListViewer);
+			dbc.bindValue(SWTObservables.observeText(name, SWT.Modify),
+					BeansObservables.observeDetailValue(selectedPerson,
+							"name", String.class));
+
+			ComboViewer cityViewer = new ComboViewer(city);
+			cityViewer.setContentProvider(new ArrayContentProvider());
+			cityViewer.setInput(viewModel.getCities());
+
+			IObservableValue citySelection = ViewersObservables
+					.observeSingleSelection(cityViewer);
+			dbc.bindValue(citySelection, BeansObservables.observeDetailValue(
+					selectedPerson, "city", String.class));
+
+			GridLayoutFactory.swtDefaults().applyTo(shell);
+			// Open and return the Shell
+			shell.pack();
+			shell.open();
+			return shell;
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet002UpdateComboRetainSelection.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * Copyright (c) 2006 The Pampered Chef, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     The Pampered Chef, Inc. - initial API and implementation
+ *     Brad Reynolds - bug 116920
+ *     Matthew Hall - bug 260329
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeansObservables;
+import org.eclipse.core.databinding.observable.IObservable;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.databinding.observable.list.WritableList;
+import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
+import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Shows how to bind a Combo so that when update its items, the selection is
+ * retained if at all possible.
+ * 
+ * @since 3.2
+ */
+public class Snippet002UpdateComboRetainSelection {
+    public static void main(String[] args) {
+    	final Display display = new Display();
+    	Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+    		public void run() {
+    			ViewModel viewModel = new ViewModel();
+    			Shell shell = new View(viewModel).createShell();
+    			
+    			// The SWT event loop
+    			while (!shell.isDisposed()) {
+    				if (!display.readAndDispatch()) {
+    					display.sleep();
+    				}
+    			}
+    			
+    			// Print the results
+    			System.out.println(viewModel.getText());
+    		}
+    	});
+    	display.dispose();
+    }
+
+    // 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 View's model--the root of our Model graph for this particular GUI.
+    public static class ViewModel extends AbstractModelObject {
+        private String text = "beef";
+
+        private List choices = new ArrayList();
+        {
+            choices.add("pork");
+            choices.add("beef");
+            choices.add("poultry");
+            choices.add("vegatables");
+        }
+
+        public List getChoices() {
+            return choices;
+        }
+
+        public void setChoices(List choices) {
+            List old = this.choices;
+            this.choices = choices;
+            firePropertyChange("choices", old, choices);
+        }
+
+        public String getText() {
+            return text;
+        }
+
+        public void setText(String text) {
+            String oldValue = this.text;
+            this.text = text;
+            firePropertyChange("text", oldValue, text);
+        }
+    }
+
+    // The GUI view
+    static class View {
+        private ViewModel viewModel;
+        /**
+         * used to make a new choices array unique
+         */
+        static int count;
+
+        public View(ViewModel viewModel) {
+            this.viewModel = viewModel;
+        }
+
+        public Shell createShell() {
+            // Build a UI
+            Shell shell = new Shell(Display.getCurrent());
+            shell.setLayout(new RowLayout(SWT.VERTICAL));
+
+            Combo combo = new Combo(shell, SWT.BORDER | SWT.READ_ONLY);
+            Button reset = new Button(shell, SWT.NULL);
+            reset.setText("reset collection");
+            reset.addSelectionListener(new SelectionAdapter() {
+                public void widgetSelected(SelectionEvent e) {
+                    List newList = new ArrayList();
+                    newList.add("Chocolate");
+                    newList.add("Vanilla");
+                    newList.add("Mango Parfait");
+                    newList.add("beef");
+                    newList.add("Cheesecake");
+                    newList.add(Integer.toString(++count));
+                    viewModel.setChoices(newList);
+                }
+            });
+
+            // Print value out first
+            System.out.println(viewModel.getText());
+
+            DataBindingContext dbc = new DataBindingContext();
+            
+            IObservableList list = MasterDetailObservables.detailList(BeansObservables.observeValue(viewModel, "choices"),
+                    getListDetailFactory(),
+                    String.class);
+            dbc.bindList(SWTObservables.observeItems(combo), list); 
+            dbc.bindValue(SWTObservables.observeText(combo), BeansObservables.observeValue(viewModel, "text"));
+            
+            // Open and return the Shell
+            shell.pack();
+            shell.open();
+            return shell;
+        }
+    }
+
+    private static IObservableFactory getListDetailFactory() {
+        return new IObservableFactory() {
+            public IObservable createObservable(Object target) {
+                WritableList list = WritableList.withElementType(String.class);
+                list.addAll((Collection) target);
+                return list;
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet003UpdateComboBindUsingViewer.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2006 The Pampered Chef, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     The Pampered Chef, Inc. - initial API and implementation
+ *     Brad Reynolds - bug 116920
+ *     Matthew Hall - bugs 260329, 260337
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeansObservables;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.property.Properties;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.viewers.ViewerSupport;
+import org.eclipse.jface.databinding.viewers.ViewersObservables;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Shows how to bind a Combo so that when update its items, the selection is
+ * retained if at all possible.
+ * 
+ * @since 3.2
+ */
+public class Snippet003UpdateComboBindUsingViewer {
+	public static void main(String[] args) {
+		final Display display = new Display();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				ViewModel viewModel = new ViewModel();
+				Shell shell = new View(viewModel).createShell();
+
+				// The SWT event loop
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch()) {
+						display.sleep();
+					}
+				}
+				// Print the results
+				System.out.println(viewModel.getText());
+			}
+		});
+		display.dispose();
+	}
+
+	// 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 View's model--the root of our Model graph for this particular GUI.
+	public static class ViewModel extends AbstractModelObject {
+		private String text = "beef";
+
+		private List choices = new ArrayList();
+		{
+			choices.add("pork");
+			choices.add("beef");
+			choices.add("poultry");
+			choices.add("vegatables");
+		}
+
+		public List getChoices() {
+			return choices;
+		}
+
+		public void setChoices(List choices) {
+			this.choices = choices;
+			firePropertyChange("choices", null, null);
+		}
+
+		public String getText() {
+			return text;
+		}
+
+		public void setText(String text) {
+			String oldValue = this.text;
+			this.text = text;
+			firePropertyChange("text", oldValue, text);
+		}
+	}
+
+	// The GUI view
+	static class View {
+		private ViewModel viewModel;
+
+		public View(ViewModel viewModel) {
+			this.viewModel = viewModel;
+		}
+
+		public Shell createShell() {
+			// Build a UI
+			Shell shell = new Shell(Display.getCurrent());
+			shell.setLayout(new RowLayout(SWT.VERTICAL));
+
+			Combo combo = new Combo(shell, SWT.BORDER | SWT.READ_ONLY);
+			ComboViewer viewer = new ComboViewer(combo);
+			Button reset = new Button(shell, SWT.NULL);
+			reset.setText("reset collection");
+			reset.addSelectionListener(new SelectionAdapter() {
+				public void widgetSelected(SelectionEvent e) {
+					List newList = new ArrayList();
+					newList.add("Chocolate");
+					newList.add("Vanilla");
+					newList.add("Mango Parfait");
+					newList.add("beef");
+					newList.add("Cheesecake");
+					viewModel.setChoices(newList);
+				}
+			});
+
+			// Print value out first
+			System.out.println(viewModel.getText());
+
+			DataBindingContext dbc = new DataBindingContext();
+			ViewerSupport.bind(viewer, BeansObservables.observeList(viewModel,
+					"choices", String.class), Properties
+					.selfValue(String.class));
+
+			dbc.bindValue(ViewersObservables.observeSingleSelection(viewer),
+					BeansObservables.observeValue(viewModel, "text"));
+
+			// Open and return the Shell
+			shell.pack();
+			shell.open();
+			return shell;
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet004DataBindingContextErrorLabel.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Brad Reynolds and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Brad Reynolds - initial API and implementation
+ *     Brad Reynolds - bug 116920, 159768
+ *     Matthew Hall - bug 260329
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import org.eclipse.core.databinding.AggregateValidationStatus;
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.core.databinding.validation.IValidator;
+import org.eclipse.core.databinding.validation.ValidationStatus;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Snippet that displays how to bind the validation error of the
+ * {@link DataBindingContext} to a label. http://www.eclipse.org
+ * 
+ * @since 3.2
+ */
+public class Snippet004DataBindingContextErrorLabel {
+	public static void main(String[] args) {
+		final Display display = new Display();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				Shell shell = new Shell(display);
+				shell.setText("Data Binding Snippet 004");
+				shell.setLayout(new GridLayout(2, false));
+
+				new Label(shell, SWT.NONE).setText("Enter '5' to be valid:");
+
+				Text text = new Text(shell, SWT.BORDER);
+				WritableValue value = WritableValue.withValueType(String.class);
+				new Label(shell, SWT.NONE).setText("Error:");
+
+				Label errorLabel = new Label(shell, SWT.BORDER);
+				errorLabel.setForeground(display.getSystemColor(SWT.COLOR_RED));
+				GridDataFactory.swtDefaults().hint(200, SWT.DEFAULT).applyTo(
+						errorLabel);
+
+				DataBindingContext dbc = new DataBindingContext();
+
+				// Bind the text to the value.
+				dbc.bindValue(
+						SWTObservables.observeText(text, SWT.Modify),
+						value,
+						new UpdateValueStrategy().setAfterConvertValidator(new FiveValidator()),
+						null);
+
+				// Bind the error label to the validation error on the dbc.
+				dbc.bindValue(SWTObservables.observeText(errorLabel),
+						new AggregateValidationStatus(dbc.getBindings(),
+								AggregateValidationStatus.MAX_SEVERITY));
+
+				shell.pack();
+				shell.open();
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch())
+						display.sleep();
+				}
+			}
+		});
+		display.dispose();
+	}
+
+	/**
+	 * Validator that returns validation errors for any value other than 5.
+	 * 
+	 * @since 3.2
+	 */
+	private static class FiveValidator implements IValidator {
+		public IStatus validate(Object value) {
+			return ("5".equals(value)) ? Status.OK_STATUS : ValidationStatus
+					.error("the value was '" + value + "', not '5'");
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet005MenuUpdater.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Brad Reynolds - bug 116920
+ *******************************************************************************/
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.util.Date;
+import java.util.Iterator;
+
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.WritableList;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.internal.databinding.provisional.swt.MenuUpdater;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ */
+public class Snippet005MenuUpdater {
+	public static void main(String[] args) {
+		final Display display = new Display();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				Shell shell = new Shell(display);
+
+				final WritableList menuItemStrings = new WritableList();
+				display.asyncExec(new Runnable() {
+					public void run() {
+						System.out.println("adding item");
+						menuItemStrings.add(new Date().toString());
+						display.timerExec(5000, this);
+					}
+				});
+
+				Menu bar = new Menu(shell, SWT.BAR);
+				shell.setMenuBar(bar);
+				MenuItem fileItem = new MenuItem(bar, SWT.CASCADE);
+				fileItem.setText("&Test Menu");
+				final Menu submenu = new Menu(shell, SWT.DROP_DOWN);
+				fileItem.setMenu(submenu);
+				new MenuUpdater(submenu) {
+					protected void updateMenu() {
+						System.out.println("updating menu");
+						MenuItem[] items = submenu.getItems();
+						int itemIndex = 0;
+						for (Iterator it = menuItemStrings.iterator(); it
+								.hasNext();) {
+							MenuItem item;
+							if (itemIndex < items.length) {
+								item = items[itemIndex++];
+							} else {
+								item = new MenuItem(submenu, SWT.NONE);
+							}
+							String string = (String) it.next();
+							item.setText(string);
+						}
+						while (itemIndex < items.length) {
+							items[itemIndex++].dispose();
+						}
+					}
+				};
+
+				shell.open();
+
+				// The SWT event loop
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch()) {
+						display.sleep();
+					}
+				}
+			}
+		});
+		display.dispose();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet006Spreadsheet.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,315 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Brad Reynolds - bug 116920
+ *******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.text.NumberFormat;
+import java.text.ParseException;
+
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.WritableList;
+import org.eclipse.core.databinding.observable.value.ComputedValue;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.internal.databinding.provisional.swt.TableUpdater;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ControlEditor;
+import org.eclipse.swt.custom.TableCursor;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * @since 1.1
+ * 
+ */
+public class Snippet006Spreadsheet {
+
+	private static final int COUNTER_UPDATE_DELAY = 1000;
+
+	private static final int NUM_COLUMNS = 6;
+
+	private static final int NUM_ROWS = 16;
+
+	/**
+	 * 0 for no output, 1 for some, 2 for more
+	 */
+	private static int DEBUG_LEVEL = 0;
+
+	/**
+	 * If true, there will be a automatic counter at B1.
+	 */
+	private static boolean FUNKY_COUNTER = false;
+
+	/**
+	 * // * If true, all formulas (except for row 1 and column A) will be the
+	 * sum of the values of their left and top neighbouring cells.
+	 */
+	private static boolean FUNKY_FORMULAS = true;
+
+	static WritableValue[][] cellFormulas = new WritableValue[NUM_ROWS][NUM_COLUMNS];
+
+	static ComputedValue[][] cellValues = new ComputedValue[NUM_ROWS][NUM_COLUMNS];
+
+	static class ComputedCellValue extends ComputedValue {
+		private final IObservableValue cellFormula;
+
+		private boolean calculating;
+
+		ComputedCellValue(IObservableValue cellFormula) {
+			this.cellFormula = cellFormula;
+		}
+
+		protected Object calculate() {
+			if (calculating) {
+				return "#cycle";
+			}
+			try {
+				calculating = true;
+				return evaluate(cellFormula.getValue());
+			} finally {
+				calculating = false;
+			}
+		}
+
+		private Object evaluate(Object value) {
+			if (DEBUG_LEVEL >= 2) {
+				System.out.println("evaluating " + this + " ...");
+			}
+			if (value == null) {
+				return "";
+			}
+			try {
+				String s = (String) value;
+				if (!s.startsWith("=")) {
+					return s;
+				}
+				String addition = s.substring(1);
+				int indexOfPlus = addition.indexOf('+');
+				String operand1 = addition.substring(0, indexOfPlus);
+				double value1 = eval(operand1);
+				String operand2 = addition.substring(indexOfPlus + 1);
+				double value2 = eval(operand2);
+				return NumberFormat.getNumberInstance().format(value1 + value2);
+			} catch (Exception ex) {
+				return ex.getMessage();
+			}
+		}
+
+		/**
+		 * @param s
+		 * @return
+		 * @throws ParseException
+		 */
+		private double eval(String s) throws ParseException {
+			if (s.length() == 0) {
+				return 0;
+			}
+			char character = s.charAt(0);
+			if (Character.isLetter(character)) {
+				character = Character.toLowerCase(character);
+				// reference to other cell
+				int columnIndex = character - 'a';
+				int rowIndex = 0;
+				rowIndex = NumberFormat.getNumberInstance().parse(
+						s.substring(1)).intValue() - 1;
+				String value = (String) cellValues[rowIndex][columnIndex]
+						.getValue();
+				return value.length() == 0 ? 0 : NumberFormat
+						.getNumberInstance().parse(value).doubleValue();
+			}
+			return NumberFormat.getNumberInstance().parse(s).doubleValue();
+		}
+	}
+
+	protected static int counter;
+
+	public static void main(String[] args) {
+
+		final Display display = new Display();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				Shell shell = new Shell(display);
+				shell.setText("Data Binding Snippet 006");
+
+				final Table table = new Table(shell, SWT.BORDER | SWT.MULTI
+						| SWT.FULL_SELECTION | SWT.VIRTUAL);
+				table.setLinesVisible(true);
+				table.setHeaderVisible(true);
+
+				for (int i = 0; i < NUM_COLUMNS; i++) {
+					TableColumn tableColumn = new TableColumn(table, SWT.NONE);
+					tableColumn.setText(Character.toString((char) ('A' + i)));
+					tableColumn.setWidth(60);
+				}
+				WritableList list = new WritableList();
+				for (int i = 0; i < NUM_ROWS; i++) {
+					list.add(new Object());
+					for (int j = 0; j < NUM_COLUMNS; j++) {
+						cellFormulas[i][j] = new WritableValue();
+						cellValues[i][j] = new ComputedCellValue(
+								cellFormulas[i][j]);
+						if (!FUNKY_FORMULAS || i == 0 || j == 0) {
+							cellFormulas[i][j].setValue("");
+						} else {
+							cellFormulas[i][j].setValue("="
+									+ cellReference(i - 1, j) + "+"
+									+ cellReference(i, j - 1));
+						}
+					}
+				}
+
+				new TableUpdater(table, list) {
+					protected void updateItem(int rowIndex, TableItem item, Object element) {
+						if (DEBUG_LEVEL >= 1) {
+							System.out.println("updating row " + rowIndex);
+						}
+						for (int j = 0; j < NUM_COLUMNS; j++) {
+							item.setText(j, (String) cellValues[rowIndex][j]
+									.getValue());
+						}
+					}
+				};
+
+				if (FUNKY_COUNTER) {
+					// counter in A1
+					display.asyncExec(new Runnable() {
+						public void run() {
+							cellFormulas[0][1].setValue("" + counter++);
+							display.timerExec(COUNTER_UPDATE_DELAY, this);
+						}
+					});
+				}
+
+				// create a TableCursor to navigate around the table
+				final TableCursor cursor = new TableCursor(table, SWT.NONE);
+				// create an editor to edit the cell when the user hits "ENTER"
+				// while over a cell in the table
+				final ControlEditor editor = new ControlEditor(cursor);
+				editor.grabHorizontal = true;
+				editor.grabVertical = true;
+
+				cursor.addSelectionListener(new SelectionAdapter() {
+					// when the TableEditor is over a cell, select the
+					// corresponding row
+					// in
+					// the table
+					public void widgetSelected(SelectionEvent e) {
+						table.setSelection(new TableItem[] { cursor.getRow() });
+					}
+
+					// when the user hits "ENTER" in the TableCursor, pop up a
+					// text
+					// editor so that
+					// they can change the text of the cell
+					public void widgetDefaultSelected(SelectionEvent e) {
+						final Text text = new Text(cursor, SWT.NONE);
+						TableItem row = cursor.getRow();
+						int rowIndex = table.indexOf(row);
+						int columnIndex = cursor.getColumn();
+						text
+								.setText((String) cellFormulas[rowIndex][columnIndex]
+										.getValue());
+						text.addKeyListener(new KeyAdapter() {
+							public void keyPressed(KeyEvent e) {
+								// close the text editor and copy the data over
+								// when the user hits "ENTER"
+								if (e.character == SWT.CR) {
+									TableItem row = cursor.getRow();
+									int rowIndex = table.indexOf(row);
+									int columnIndex = cursor.getColumn();
+									cellFormulas[rowIndex][columnIndex]
+											.setValue(text.getText());
+									text.dispose();
+								}
+								// close the text editor when the user hits
+								// "ESC"
+								if (e.character == SWT.ESC) {
+									text.dispose();
+								}
+							}
+						});
+						editor.setEditor(text);
+						text.setFocus();
+					}
+				});
+				// Hide the TableCursor when the user hits the "MOD1" or "MOD2"
+				// key.
+				// This alows the user to select multiple items in the table.
+				cursor.addKeyListener(new KeyAdapter() {
+					public void keyPressed(KeyEvent e) {
+						if (e.keyCode == SWT.MOD1 || e.keyCode == SWT.MOD2
+								|| (e.stateMask & SWT.MOD1) != 0
+								|| (e.stateMask & SWT.MOD2) != 0) {
+							cursor.setVisible(false);
+						}
+					}
+				});
+				// Show the TableCursor when the user releases the "MOD2" or
+				// "MOD1" key.
+				// This signals the end of the multiple selection task.
+				table.addKeyListener(new KeyAdapter() {
+					public void keyReleased(KeyEvent e) {
+						if (e.keyCode == SWT.MOD1
+								&& (e.stateMask & SWT.MOD2) != 0)
+							return;
+						if (e.keyCode == SWT.MOD2
+								&& (e.stateMask & SWT.MOD1) != 0)
+							return;
+						if (e.keyCode != SWT.MOD1
+								&& (e.stateMask & SWT.MOD1) != 0)
+							return;
+						if (e.keyCode != SWT.MOD2
+								&& (e.stateMask & SWT.MOD2) != 0)
+							return;
+
+						TableItem[] selection = table.getSelection();
+						TableItem row = (selection.length == 0) ? table
+								.getItem(table.getTopIndex()) : selection[0];
+						table.showItem(row);
+						cursor.setSelection(row, 0);
+						cursor.setVisible(true);
+						cursor.setFocus();
+					}
+				});
+
+				GridLayoutFactory.fillDefaults().generateLayout(shell);
+				shell.setSize(400, 300);
+				shell.open();
+
+				// The SWT event loop
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch()) {
+						display.sleep();
+					}
+				}
+			}
+		});
+		display.dispose();
+	}
+
+	private static String cellReference(int rowIndex, int columnIndex) {
+		String cellReference = "" + ((char) ('A' + columnIndex))
+				+ (rowIndex + 1);
+		return cellReference;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet007ColorLabelProvider.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Brad Reynolds and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Brad Reynolds - initial API and implementation
+ *     IBM Corporation - see bug 137934
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.databinding.beans.BeansObservables;
+import org.eclipse.core.databinding.observable.Observables;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.databinding.observable.map.IObservableMap;
+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.ILabelProvider;
+import org.eclipse.jface.viewers.ITableColorProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+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.graphics.Color;
+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.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+
+/**
+ * An example showing how to create a {@link ILabelProvider label provider} that
+ * to provide colors.
+ * 
+ * @since 3.2
+ */
+public class Snippet007ColorLabelProvider {
+	/**
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		final List persons = new ArrayList();
+		persons.add(new Person("Fiona Apple", Person.FEMALE));
+		persons.add(new Person("Elliot Smith", Person.MALE));
+		persons.add(new Person("Diana Krall", Person.FEMALE));
+		persons.add(new Person("David Gilmour", Person.MALE));
+
+		final Display display = new Display();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				Shell shell = new Shell(display);
+				shell.setText("Gender Bender");
+				shell.setLayout(new GridLayout());
+
+				Table table = new Table(shell, SWT.SINGLE | SWT.H_SCROLL
+						| SWT.V_SCROLL | SWT.BORDER);
+				GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+				table.setLayoutData(gridData);
+				table.setHeaderVisible(true);
+				table.setLinesVisible(true);
+				TableColumn column = new TableColumn(table, SWT.NONE);
+				column.setText("No");
+				column.setWidth(20);
+				column = new TableColumn(table, SWT.NONE);
+				column.setText("Name");
+				column.setWidth(100);
+				final TableViewer viewer = new TableViewer(table);
+
+				IObservableList observableList = Observables
+						.staticObservableList(persons);
+				ObservableListContentProvider contentProvider = new ObservableListContentProvider();
+
+				viewer.setContentProvider(contentProvider);
+
+				// this does not have to correspond to the columns in the table,
+				// we just list all attributes that affect the table content.
+				IObservableMap[] attributes = BeansObservables.observeMaps(
+						contentProvider.getKnownElements(), Person.class,
+						new String[] { "name", "gender" });
+
+				class ColorLabelProvider extends ObservableMapLabelProvider
+						implements ITableColorProvider {
+					Color male = display.getSystemColor(SWT.COLOR_BLUE);
+
+					Color female = new Color(display, 255, 192, 203);
+
+					ColorLabelProvider(IObservableMap[] attributes) {
+						super(attributes);
+					}
+
+					// to drive home the point that attributes does not have to
+					// match
+					// the columns
+					// in the table, we change the column text as follows:
+					public String getColumnText(Object element, int index) {
+						if (index == 0) {
+							return Integer
+									.toString(persons.indexOf(element) + 1);
+						}
+						return ((Person) element).getName();
+					}
+
+					public Color getBackground(Object element, int index) {
+						return null;
+					}
+
+					public Color getForeground(Object element, int index) {
+						if (index == 0)
+							return null;
+						Person person = (Person) element;
+						return (person.getGender() == Person.MALE) ? male
+								: female;
+					}
+
+					public void dispose() {
+						super.dispose();
+						female.dispose();
+					}
+				}
+				viewer.setLabelProvider(new ColorLabelProvider(attributes));
+
+				viewer.setInput(observableList);
+
+				table.getColumn(0).pack();
+
+				Button button = new Button(shell, SWT.PUSH);
+				button.setText("Toggle Gender");
+				button.addSelectionListener(new SelectionAdapter() {
+					public void widgetSelected(SelectionEvent arg0) {
+						StructuredSelection selection = (StructuredSelection) viewer
+								.getSelection();
+						if (selection != null && !selection.isEmpty()) {
+							Person person = (Person) selection
+									.getFirstElement();
+							person
+									.setGender((person.getGender() == Person.MALE) ? Person.FEMALE
+											: Person.MALE);
+						}
+					}
+				});
+
+				shell.setSize(300, 400);
+				shell.open();
+
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch())
+						display.sleep();
+				}
+			}
+		});
+		display.dispose();
+	}
+
+	static class Person {
+		static final int MALE = 0;
+
+		static final int FEMALE = 1;
+
+		private String name;
+
+		private int gender;
+
+		private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
+				this);
+
+		Person(String name, int gender) {
+			this.name = name;
+			this.gender = gender;
+		}
+
+		/**
+		 * Returns the name. Method declared public to satisfy Java bean
+		 * conventions
+		 * 
+		 * @return the name
+		 */
+		public String getName() {
+			return name;
+		}
+
+		/**
+		 * @param listener
+		 */
+		public void addPropertyChangeListener(PropertyChangeListener listener) {
+			changeSupport.addPropertyChangeListener(listener);
+		}
+
+		public void removePropertyChangeListener(PropertyChangeListener listener) {
+			changeSupport.removePropertyChangeListener(listener);
+		}
+
+		/**
+		 * Returns the gender. Method declared public to satisfy Java bean
+		 * conventions
+		 * 
+		 * @return the gender
+		 */
+		public int getGender() {
+			return gender;
+		}
+
+		void setGender(int gender) {
+			changeSupport.firePropertyChange("gender", this.gender,
+					this.gender = gender);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet008ComputedValue.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Brad Reynolds and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Brad Reynolds - initial API and implementation
+ *     Matthew Hall - bug 260329
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.observable.ObservableTracker;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.ComputedValue;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Snippet that demostrates a simple use case using ComputedValue to format a
+ * name as the user enters first and last name.
+ * 
+ * @since 3.2
+ */
+public class Snippet008ComputedValue {
+	/**
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		final Display display = new Display();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				Shell shell = new Shell(display);
+				shell.setLayout(new FillLayout());
+
+				final UI ui = new UI(shell);
+				final Data data = new Data();
+
+				// Bind the UI to the Data.
+				DataBindingContext dbc = new DataBindingContext();
+				dbc.bindValue(SWTObservables.observeText(ui.firstName,
+						SWT.Modify), data.firstName);
+				dbc.bindValue(SWTObservables.observeText(ui.lastName,
+						SWT.Modify), data.lastName);
+
+				// Construct the formatted name observable.
+				FormattedName formattedName = new FormattedName(data.firstName,
+						data.lastName);
+
+				// Bind the formatted name Text to the formatted name
+				// observable.
+				dbc.bindValue(SWTObservables.observeText(ui.formattedName,
+						SWT.None), formattedName, new UpdateValueStrategy(false, UpdateValueStrategy.POLICY_NEVER), null);
+
+				shell.pack();
+				shell.open();
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch())
+						display.sleep();
+				}
+			}
+		});
+		display.dispose();
+	}
+
+	/**
+	 * Creates the formatted name on change of the first or last name
+	 * observables.
+	 * <p>
+	 * The key to understanding ComputedValue is understanding that it knows of
+	 * the observables that are queried without being told. This is done with
+	 * {@link ObservableTracker} voodoo. When calculate() is invoked
+	 * <code>ObservableTracker</code> records the observables that are
+	 * queried. It then exposes those observables and <code>ComputedValue</code>
+	 * can listen to changes in those objects and react accordingly.
+	 * </p>
+	 * 
+	 * @since 3.2
+	 */
+	static class FormattedName extends ComputedValue {
+		private IObservableValue firstName;
+
+		private IObservableValue lastName;
+
+		FormattedName(IObservableValue firstName, IObservableValue lastName) {
+			this.firstName = firstName;
+			this.lastName = lastName;
+		}
+
+		protected Object calculate() {
+			String lastName = (String) this.lastName.getValue();
+			String firstName = (String) this.firstName.getValue();
+			lastName = (lastName != null && lastName.length() > 0) ? lastName
+					: "[Last Name]";
+			firstName = (firstName != null && firstName.length() > 0) ? firstName
+					: "[First Name]";
+
+			StringBuffer buffer = new StringBuffer();
+			buffer.append(lastName).append(", ").append(firstName);
+
+			return buffer.toString();
+		}
+	}
+
+	static class Data {
+		final WritableValue firstName;
+
+		final WritableValue lastName;
+
+		Data() {
+			firstName = new WritableValue("", String.class);
+			lastName = new WritableValue("", String.class);
+		}
+	}
+
+	/**
+	 * Composite that creates the UI.
+	 * 
+	 * @since 3.2
+	 */
+	static class UI extends Composite {
+		final Text firstName;
+
+		final Text lastName;
+
+		final Text formattedName;
+
+		UI(Composite parent) {
+			super(parent, SWT.NONE);
+
+			GridLayoutFactory.swtDefaults().numColumns(2).applyTo(this);
+
+			new Label(this, SWT.NONE).setText("First Name:");
+			new Label(this, SWT.NONE).setText("Last Name");
+
+			GridDataFactory gdf = GridDataFactory.swtDefaults().align(SWT.FILL,
+					SWT.FILL).grab(true, false);
+			firstName = new Text(this, SWT.BORDER);
+			gdf.applyTo(firstName);
+
+			lastName = new Text(this, SWT.BORDER);
+			gdf.applyTo(lastName);
+
+			gdf = GridDataFactory.swtDefaults().span(2, 1).grab(true, false)
+					.align(SWT.FILL, SWT.BEGINNING);
+			Label label = new Label(this, SWT.NONE);
+			label.setText("Formatted Name:");
+			gdf.applyTo(label);
+
+			formattedName = new Text(this, SWT.BORDER);
+			formattedName.setEditable(false);
+			gdf.applyTo(formattedName);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet009TableViewer.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2006 The Pampered Chef, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Coconut Palm Software, Inc. - Initial API and implementation
+ *     Matthew Hall - bug 260337
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.core.databinding.beans.BeanProperties;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.WritableList;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.viewers.ViewerSupport;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+
+/**
+ * Demonstrates binding a TableViewer to a collection.
+ */
+public class Snippet009TableViewer {
+	public static void main(String[] args) {
+		final Display display = Display.getDefault();
+
+		// 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() {
+
+				ViewModel viewModel = new ViewModel();
+				Shell shell = new View(viewModel).createShell();
+
+				// The SWT event loop
+				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);
+		}
+	}
+
+	// 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
+	static class View {
+		private ViewModel viewModel;
+		private Table committers;
+
+		public View(ViewModel viewModel) {
+			this.viewModel = viewModel;
+		}
+
+		public Shell createShell() {
+			// Build a UI
+			Display display = Display.getDefault();
+			Shell shell = new Shell(display);
+			shell.setLayout(new FillLayout());
+			committers = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
+			committers.setLinesVisible(true);
+			TableColumn column = new TableColumn(committers, SWT.NONE);
+
+			// Set up data binding.
+			TableViewer peopleViewer = new TableViewer(committers);
+			ViewerSupport.bind(peopleViewer, new WritableList(viewModel
+					.getPeople(), Person.class), BeanProperties.value(
+					Person.class, "name"));
+
+			column.pack();
+
+			// Open and return the Shell
+			shell.setSize(100, 300);
+			shell.open();
+			return shell;
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet010MasterDetail.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Brad Reynolds and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Brad Reynolds - initial API and implementation
+ *     Matthew Hall - bug 260329
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.beans.BeansObservables;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.viewers.ViewersObservables;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ListViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Snippet that displays a simple master detail use case. A list of persons is
+ * displayed in a list and upon selection the name of the selected person will
+ * be displayed in a Text widget.
+ */
+public class Snippet010MasterDetail {
+	public static void main(String[] args) {
+		final Display display = new Display();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				Shell shell = new Shell(display);
+				shell.setLayout(new GridLayout());
+
+				Person[] persons = new Person[] { new Person("Me"),
+						new Person("Myself"), new Person("I") };
+
+				ListViewer viewer = new ListViewer(shell);
+				viewer.setContentProvider(new ArrayContentProvider());
+				viewer.setInput(persons);
+
+				Text name = new Text(shell, SWT.BORDER | SWT.READ_ONLY);
+
+				// 1. Observe changes in selection.
+				IObservableValue selection = ViewersObservables
+						.observeSingleSelection(viewer);
+
+				// 2. Observe the name property of the current selection.
+				IObservableValue detailObservable = BeansObservables
+						.observeDetailValue(selection, "name", String.class);
+
+				// 3. Bind the Text widget to the name detail (selection's
+				// name).
+				new DataBindingContext().bindValue(SWTObservables.observeText(
+						name, SWT.None), detailObservable,
+						new UpdateValueStrategy(false,
+								UpdateValueStrategy.POLICY_NEVER), null);
+
+				shell.open();
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch())
+						display.sleep();
+				}
+			}
+		});
+		display.dispose();
+	}
+
+	public static class Person {
+		private String name;
+		private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
+
+		Person(String name) {
+			this.name = name;
+		}
+
+		public void addPropertyChangeListener(PropertyChangeListener listener) {
+			changeSupport.addPropertyChangeListener(listener);
+		}
+		
+		public void removePropertyChangeListener(PropertyChangeListener listener) {
+			changeSupport.removePropertyChangeListener(listener);
+		}
+		
+		/**
+		 * @return Returns the name.
+		 */
+		public String getName() {
+			return name;
+		}
+
+		public String toString() {
+			return name;
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet011ValidateMultipleBindingsSnippet.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,129 @@
+ /*******************************************************************************
+ * Copyright (c) 2007 Brad Reynolds and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Brad Reynolds - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.observable.value.IValueChangeListener;
+import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.core.databinding.validation.IValidator;
+import org.eclipse.core.databinding.validation.ValidationStatus;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Snippet that validates values across multiple bindings on change of each
+ * observable. If the values of the target observables are not equal the model
+ * is not updated. When the values are equal they will be written to sysout.
+ * 
+ * @author Brad Reynolds
+ */
+public class Snippet011ValidateMultipleBindingsSnippet {
+	public static void main(String[] args) {
+		Realm.runWithDefault(SWTObservables.getRealm(Display.getDefault()),
+				new Runnable() {
+					public void run() {
+						Snippet011ValidateMultipleBindingsSnippet.run();
+					}
+				});
+	}
+
+	private static void run() {
+		Shell shell = new Shell();
+
+		View view = new View(shell);
+		final Model model = new Model();
+
+		DataBindingContext dbc = new DataBindingContext();
+		dbc.bindValue(SWTObservables.observeText(view.text1, SWT.Modify),
+				model.value1, new UpdateValueStrategy()
+						.setAfterConvertValidator(new CrossFieldValidator(
+								model.value2)), null);
+		dbc.bindValue(SWTObservables.observeText(view.text2, SWT.Modify),
+				model.value2, new UpdateValueStrategy()
+						.setAfterConvertValidator(new CrossFieldValidator(
+								model.value1)), null);
+
+		// DEBUG - print to show value change
+		model.value1.addValueChangeListener(new IValueChangeListener() {
+			public void handleValueChange(ValueChangeEvent event) {
+				System.out.println("Value 1: " + model.value1.getValue());
+			}
+		});
+
+		// DEBUG - print to show value change
+		model.value2.addValueChangeListener(new IValueChangeListener() {
+			public void handleValueChange(ValueChangeEvent event) {
+				System.out.println("Value 2: " + model.value2.getValue());
+			}
+		});
+
+		shell.pack();
+		shell.open();
+		Display display = shell.getDisplay();
+		while (!shell.isDisposed()) {
+			if (!display.readAndDispatch())
+				display.sleep();
+		}
+		display.dispose();
+	}
+
+	/**
+	 * @since 3.2
+	 * 
+	 */
+	private static final class CrossFieldValidator implements IValidator {
+		/**
+		 * 
+		 */
+		private final IObservableValue other;
+
+		/**
+		 * @param model
+		 */
+		private CrossFieldValidator(IObservableValue other) {
+			this.other = other;
+		}
+
+		public IStatus validate(Object value) {
+			if (!value.equals(other.getValue())) {
+				return ValidationStatus.ok();
+			}
+			return ValidationStatus.error("values cannot be the same");
+		}
+	}
+
+	static class Model {
+		WritableValue value1 = new WritableValue();
+		WritableValue value2 = new WritableValue();
+	}
+
+	static class View {
+		Text text1;
+		Text text2;
+
+		View(Composite composite) {
+			composite.setLayout(new GridLayout(2, true));
+			text1 = new Text(composite, SWT.BORDER);
+			text2 = new Text(composite, SWT.BORDER);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet012CompositeUpdater.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.WritableList;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.internal.databinding.provisional.swt.CompositeUpdater;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * @since 3.2
+ * 
+ */
+public class Snippet012CompositeUpdater {
+
+	public static void main(String[] args) {
+		final Display display = new Display();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				Shell shell = new Shell(display);
+
+				final WritableList list = new WritableList();
+
+				Button button = new Button(shell, SWT.PUSH);
+				button.setText("add");
+				button.addSelectionListener(new SelectionAdapter() {
+					public void widgetSelected(
+							org.eclipse.swt.events.SelectionEvent e) {
+						list.add(0, new Counter());
+					}
+				});
+
+				final Composite composite = new Composite(shell, SWT.None);
+
+				new CompositeUpdater(composite, list) {
+					protected Widget createWidget(int index) {
+						Label label = new Label(composite, SWT.BORDER);
+						//requestLayout(label);
+						return label;
+					}
+
+					protected void updateWidget(Widget widget, Object element) {
+						((Label) widget).setText(((Counter) element).getValue()
+								+ "");
+						requestLayout((Label)widget);
+					}
+				};
+				GridLayoutFactory.fillDefaults().numColumns(10).generateLayout(composite);
+
+				GridDataFactory.fillDefaults().grab(true, true).applyTo(
+						composite);
+
+				GridLayoutFactory.fillDefaults().generateLayout(shell);
+				shell.pack();
+				shell.open();
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch())
+						display.sleep();
+				}
+			}
+		});
+		display.dispose();
+	}
+
+	static Timer timer = new Timer(true);
+
+	static class Counter extends WritableValue {
+		Counter() {
+			super(new Integer(0), Integer.class);
+			scheduleIncrementTask();
+		}
+
+		private void scheduleIncrementTask() {
+			timer.schedule(new TimerTask() {
+				public void run() {
+					// we have to get onto the realm (UI thread) to perform the
+					// increment
+					getRealm().asyncExec(new Runnable() {
+						public void run() {
+							Integer currentVal = (Integer) getValue();
+							setValue(new Integer(currentVal.intValue() + 1));
+						}
+					});
+					scheduleIncrementTask();
+				}
+			}, 1000);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet013TableViewerEditing.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,236 @@
+/*******************************************************************************
+ * Copyright (c) 2006 The Pampered Chef, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     The Pampered Chef, Inc. - initial API and implementation
+ *     Tom Schindl - cell editing
+ *     Matthew Hall - bugs 260329, 260337
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeanProperties;
+import org.eclipse.core.databinding.beans.BeansObservables;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.WritableList;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.viewers.ObservableValueEditingSupport;
+import org.eclipse.jface.databinding.viewers.ViewerSupport;
+import org.eclipse.jface.databinding.viewers.ViewersObservables;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+
+/**
+ * Demonstrates binding a TableViewer to a collection using the 3.3 Viewer APIs.
+ */
+public class Snippet013TableViewerEditing {
+	public static void main(String[] args) {
+		final Display display = new Display();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				ViewModel viewModel = new ViewModel();
+				Shell shell = new View(viewModel).createShell();
+
+				// The SWT event loop
+				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);
+		}
+	}
+
+	// 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;
+		}
+	}
+
+	/**
+	 * Editing support that uses JFace Data Binding to control the editing
+	 * lifecycle. The standard EditingSupport get/setValue(...) lifecycle is not
+	 * used.
+	 * 
+	 * @since 3.3
+	 */
+	private static class InlineEditingSupport extends
+			ObservableValueEditingSupport {
+		private CellEditor cellEditor;
+
+		/**
+		 * @param viewer
+		 * @param dbc
+		 */
+		public InlineEditingSupport(ColumnViewer viewer, DataBindingContext dbc) {
+
+			super(viewer, dbc);
+			cellEditor = new TextCellEditor((Composite) viewer.getControl());
+		}
+
+		protected CellEditor getCellEditor(Object element) {
+			return cellEditor;
+		}
+
+		protected IObservableValue doCreateCellEditorObservable(
+				CellEditor cellEditor) {
+
+			return SWTObservables.observeText(cellEditor.getControl(),
+					SWT.Modify);
+		}
+
+		protected IObservableValue doCreateElementObservable(Object element,
+				ViewerCell cell) {
+			return BeansObservables.observeValue(element, "name");
+		}
+	}
+
+	// The GUI view
+	static class View {
+		private ViewModel viewModel;
+		private Table committers;
+		private Label selectedCommitter;
+
+		public View(ViewModel viewModel) {
+			this.viewModel = viewModel;
+		}
+
+		public Shell createShell() {
+			// Build a UI
+			Display display = Display.getDefault();
+			Shell shell = new Shell(display);
+			shell.setLayout(new FillLayout(SWT.VERTICAL));
+			committers = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
+			committers.setLinesVisible(true);
+
+			selectedCommitter = new Label(shell, SWT.NONE);
+			// 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.
+			DataBindingContext bindingContext = new DataBindingContext();
+			bindGUI(bindingContext);
+
+			// Open and return the Shell
+			shell.setSize(100, 300);
+			shell.open();
+			return shell;
+		}
+
+		protected void bindGUI(DataBindingContext bindingContext) {
+			// Since we're using a JFace Viewer, we do first wrap our Table...
+			TableViewer peopleViewer = new TableViewer(committers);
+			TableViewerColumn column = new TableViewerColumn(peopleViewer,
+					SWT.NONE);
+			column.setEditingSupport(new InlineEditingSupport(peopleViewer,
+					bindingContext));
+			column.getColumn().setWidth(100);
+
+			// Bind viewer to model
+			ViewerSupport.bind(peopleViewer, new WritableList(viewModel
+					.getPeople(), Person.class), BeanProperties.value(
+					Person.class, "name"));
+
+			// bind selectedCommitter label to the name of the current selection
+			IObservableValue selection = ViewersObservables
+					.observeSingleSelection(peopleViewer);
+			bindingContext.bindValue(SWTObservables
+					.observeText(selectedCommitter), BeansObservables
+					.observeDetailValue(selection, "name", String.class));
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet014WizardDialog.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Boris Bokowski, IBM Corporation - initial API and implementation
+ *     Matthew Hall - bug 260329
+ *******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.util.Date;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.core.databinding.validation.IValidator;
+import org.eclipse.core.databinding.validation.ValidationStatus;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.wizard.WizardPageSupport;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Creates and opens a wizard dialog with two simple wizard pages.
+ */
+public class Snippet014WizardDialog {
+
+	static class FirstWizardPage extends WizardPage {
+		private final class SingleDigitValidator implements IValidator {
+			public IStatus validate(Object value) {
+				Integer i = (Integer) value;
+				if (i == null) {
+					return ValidationStatus
+							.info("Please enter a value.");
+				}
+				if (i.intValue() < 0 || i.intValue() > 9) {
+					return ValidationStatus
+							.error("Value must be between 0 and 9.");
+				}
+				return ValidationStatus.ok();
+			}
+		}
+
+		protected FirstWizardPage() {
+			super("First", "First Page", ImageDescriptor
+					.createFromImage(new Image(Display.getDefault(), 16, 16)));
+		}
+
+		public void createControl(Composite parent) {
+			DataBindingContext dbc = new DataBindingContext();
+			WizardPageSupport.create(this, dbc);
+			Composite composite = new Composite(parent, SWT.NONE);
+			Label label = new Label(composite, SWT.NONE);
+			label.setText("Enter a number between 0 and 9:");
+			Text text = new Text(composite, SWT.BORDER);
+			
+			dbc.bindValue(
+							SWTObservables.observeText(text, SWT.Modify),
+							((SampleWizard) getWizard()).getModel().intValue,
+							new UpdateValueStrategy().setAfterConvertValidator(new SingleDigitValidator()),
+							null);
+			
+			GridLayoutFactory.swtDefaults().numColumns(2).generateLayout(
+					composite);
+			setControl(composite);
+		}
+	}
+
+	static class SecondWizardPage extends WizardPage {
+		protected SecondWizardPage() {
+			super("Second", "Second Page", ImageDescriptor
+					.createFromImage(new Image(Display.getDefault(), 16, 16)));
+		}
+
+		public void createControl(Composite parent) {
+			DataBindingContext dbc = new DataBindingContext();
+			WizardPageSupport.create(this, dbc);
+			Composite composite = new Composite(parent, SWT.NONE);
+			Label label = new Label(composite, SWT.NONE);
+			label.setText("Enter a date:");
+			Text text = new Text(composite, SWT.BORDER);
+			
+			dbc.bindValue(
+							SWTObservables.observeText(text, SWT.Modify),
+							((SampleWizard) getWizard()).getModel().dateValue);
+
+			GridLayoutFactory.swtDefaults().numColumns(2).generateLayout(
+					composite);
+			setControl(composite);
+		}
+	}
+
+	static class SampleWizardModel {
+		IObservableValue intValue = new WritableValue(null, Integer.class);
+		IObservableValue dateValue = new WritableValue(null, Date.class);
+	}
+
+	static class SampleWizard extends Wizard {
+
+		private SampleWizardModel model = new SampleWizardModel();
+
+		public void addPages() {
+			addPage(new FirstWizardPage());
+			addPage(new SecondWizardPage());
+		}
+
+		public SampleWizardModel getModel() {
+			return model;
+		}
+		
+		public String getWindowTitle() {
+			return "Data Binding Snippet014";
+		}
+
+		public boolean performFinish() {
+			return true;
+		}
+
+	}
+
+	public static void main(String[] args) {
+		Display display = new Display();
+
+		// note that the "runWithDefault" will be done for you if you are using
+		// the
+		// Workbench as opposed to just JFace/SWT.
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				IWizard wizard = new SampleWizard();
+				WizardDialog dialog = new WizardDialog(null, wizard);
+				dialog.open();
+				// The SWT event loop
+				Display display = Display.getCurrent();
+				while (dialog.getShell() != null
+						&& !dialog.getShell().isDisposed()) {
+					if (!display.readAndDispatch()) {
+						display.sleep();
+					}
+				}
+			}
+		});
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet015DelayTextModifyEvents.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,119 @@
+/************************************************************************************************************
+ * Copyright (c) 2007 Matthew Hall and others. All rights reserved. This program and the
+ * accompanying materials are made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ * 		Matthew Hall - initial API and implementation (bug 180746)
+ * 		Boris Bokowski, IBM - initial API and implementation
+ *      Matthew Hall - bugs 260329, 264286
+ ***********************************************************************************************************/
+package org.eclipse.jface.examples.databinding.snippets;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.observable.Observables;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.jface.databinding.swt.ISWTObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.swt.WidgetProperties;
+import org.eclipse.jface.internal.databinding.provisional.swt.ControlUpdater;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.resource.FontDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+public class Snippet015DelayTextModifyEvents {
+
+	private static void createControls(Shell shell) {
+		final Label field1 = createLabel(shell, SWT.NONE, "Field 1 ");
+
+		Text text1 = new Text(shell, SWT.BORDER);
+		GridDataFactory.fillDefaults().grab(true, false).hint(200, SWT.DEFAULT)
+				.applyTo(text1);
+		createLabel(shell, SWT.NONE, "200ms delay");
+
+		final Label field2 = createLabel(shell, SWT.NONE, "Field 2 ");
+
+		Text text2 = new Text(shell, SWT.BORDER);
+		GridDataFactory.fillDefaults().grab(true, false).hint(200, SWT.DEFAULT)
+				.applyTo(text2);
+
+		createLabel(shell, SWT.NONE, "1000ms delay");
+
+		final ISWTObservableValue delayed1 = WidgetProperties.text(SWT.Modify)
+				.observeDelayed(200, text1);
+		final ISWTObservableValue delayed2 = WidgetProperties.text(SWT.Modify)
+				.observeDelayed(1000, text2);
+
+		// (In a real application,you would want to dispose the resource manager
+		// when you are done with it)
+		ResourceManager resourceManager = new LocalResourceManager(
+				JFaceResources.getResources());
+		final Font shellFont = shell.getFont();
+		final Font italicFont = resourceManager.createFont(FontDescriptor
+				.createFrom(shellFont).setStyle(SWT.ITALIC));
+
+		final IObservableValue stale1 = Observables.observeStale(delayed1);
+		new ControlUpdater(field2) {
+			protected void updateControl() {
+				boolean stale = ((Boolean) stale1.getValue()).booleanValue();
+				field2.setFont(stale ? italicFont : shellFont);
+			}
+		};
+
+		final IObservableValue stale2 = Observables.observeStale(delayed2);
+		new ControlUpdater(field1) {
+			protected void updateControl() {
+				boolean stale = ((Boolean) stale2.getValue()).booleanValue();
+				field1.setFont(stale ? italicFont : shellFont);
+			}
+		};
+
+		String info = "Pending changes are applied immediately if the observed control loses focus";
+		GridDataFactory.fillDefaults().span(3, 1).applyTo(
+				createLabel(shell, SWT.WRAP, info));
+
+		DataBindingContext dbc = new DataBindingContext();
+
+		dbc.bindValue(delayed1, delayed2);
+	}
+
+	private static Label createLabel(Composite parent, int style, String text) {
+		Label label = new Label(parent, style);
+		label.setText(text);
+		return label;
+	}
+
+	public static void main(String[] args) {
+		final Display display = new Display();
+
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				Shell shell = new Shell();
+				shell.setLayout(new GridLayout(3, false));
+
+				createControls(shell);
+
+				shell.pack();
+				shell.open();
+				while (!shell.isDisposed())
+					if (!display.readAndDispatch())
+						display.sleep();
+			}
+
+		});
+
+		display.dispose();
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet016TableUpdater.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.WritableList;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.internal.databinding.provisional.swt.TableUpdater;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+
+/**
+ * @since 3.2
+ * 
+ */
+public class Snippet016TableUpdater {
+	public static void main(String[] args) {
+		final Display display = new Display();
+
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				final Shell shell = createShell(display);
+				GridLayoutFactory.fillDefaults().generateLayout(shell);
+				shell.open();
+				// The SWT event loop
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch()) {
+						display.sleep();
+					}
+				}
+			}
+		});
+	}
+
+	static class Stuff {
+		private WritableValue counter = new WritableValue(new Integer(1), Integer.class);
+
+		public Stuff(final Display display) {
+			display.timerExec(1000, new Runnable() {
+				public void run() {
+					counter.setValue(new Integer(1 + ((Integer) counter
+							.getValue()).intValue()));
+					display.timerExec(1000, this);
+				}
+			});
+		}
+		
+		public String toString() {
+			return counter.getValue().toString();
+		}
+	}
+
+	protected static Shell createShell(final Display display) {
+		Shell shell = new Shell();
+		Table t = new Table(shell, SWT.VIRTUAL);
+		final WritableList list = new WritableList();
+		new TableUpdater(t, list) {
+
+			protected void updateItem(int index, TableItem item, Object element) {
+				item.setText(element.toString());
+			}
+		};
+		display.timerExec(2000, new Runnable() {
+			public void run() {
+				list.add(new Stuff(display));
+				display.timerExec(2000, this);
+			}
+		});
+		return shell;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet017TableViewerWithDerivedColumns.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * Copyright (c) 2006 The Pampered Chef, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Coconut Palm Software, Inc. - Initial API and implementation
+ *     Matthew Hall - bugs 260329, 260337
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeanProperties;
+import org.eclipse.core.databinding.beans.BeansObservables;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.databinding.observable.list.WritableList;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.viewers.ViewerSupport;
+import org.eclipse.jface.databinding.viewers.ViewersObservables;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Combo;
+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.TableColumn;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Demonstrates binding a TableViewer to a collection.
+ */
+public class Snippet017TableViewerWithDerivedColumns {
+	public static void main(String[] args) {
+		final Display display = new Display();
+
+		// 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, wrapping your binding
+		// method call.
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				ViewModel viewModel = new ViewModel();
+				Shell shell = new View(viewModel).createShell();
+
+				// The SWT event loop
+				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);
+		}
+	}
+
+	private static Person UNKNOWN = new Person("unknown", null, null);
+
+	// The data model class. This is normally a persistent class of some sort.
+	static class Person extends AbstractModelObject {
+		// A property...
+		String name = "Donald Duck";
+		Person mother;
+		Person father;
+
+		public Person(String name, Person mother, Person father) {
+			this.name = name;
+			this.mother = mother;
+			this.father = father;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			String oldValue = this.name;
+			this.name = name;
+			firePropertyChange("name", oldValue, name);
+		}
+
+		public Person getMother() {
+			return mother;
+		}
+
+		public void setMother(Person mother) {
+			firePropertyChange("mother", this.mother, this.mother = mother);
+		}
+
+		public Person getFather() {
+			return father;
+		}
+
+		public void setFather(Person father) {
+			firePropertyChange("father", this.father, this.father = father);
+		}
+
+		public String toString() {
+			return name;
+		}
+	}
+
+	// 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 IObservableList people = new WritableList();
+		{
+			Person fergus = new Person("Fergus McDuck", UNKNOWN, UNKNOWN);
+			Person downy = new Person("Downy O'Drake", UNKNOWN, UNKNOWN);
+			Person scrooge = new Person("Scrooge McDuck", downy, fergus);
+			Person hortense = new Person("Hortense McDuck", downy, fergus);
+			Person quackmore = new Person("Quackmore Duck", UNKNOWN, UNKNOWN);
+			Person della = new Person("Della Duck", hortense, quackmore);
+			Person donald = new Person("Donald Duck", hortense, quackmore);
+			donald.setFather(quackmore);
+			donald.setMother(hortense);
+			della.setFather(quackmore);
+			della.setMother(hortense);
+			hortense.setMother(downy);
+			hortense.setFather(fergus);
+			scrooge.setMother(downy);
+			scrooge.setFather(fergus);
+			people.add(UNKNOWN);
+			people.add(downy);
+			people.add(fergus);
+			people.add(scrooge);
+			people.add(quackmore);
+			people.add(hortense);
+			people.add(della);
+			people.add(donald);
+		}
+
+		public IObservableList getPeople() {
+			return people;
+		}
+	}
+
+	// The GUI view
+	static class View {
+		private ViewModel viewModel;
+		private Table duckFamily;
+		private Text nameText;
+		private Combo motherCombo;
+		private Combo fatherCombo;
+
+		public View(ViewModel viewModel) {
+			this.viewModel = viewModel;
+		}
+
+		public Shell createShell() {
+			// Build a UI
+			Display display = Display.getDefault();
+			Shell shell = new Shell(display);
+			duckFamily = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
+			duckFamily.setHeaderVisible(true);
+			GridDataFactory.defaultsFor(duckFamily).span(2, 1).applyTo(
+					duckFamily);
+			createColumn("Name");
+			createColumn("Mother");
+			createColumn("Father");
+			createColumn("Grandmother");
+			duckFamily.setLinesVisible(true);
+
+			new Label(shell, SWT.NONE).setText("Name:");
+			nameText = new Text(shell, SWT.BORDER);
+			GridDataFactory.defaultsFor(nameText).grab(true, false).applyTo(
+					nameText);
+
+			new Label(shell, SWT.NONE).setText("Mother:");
+			motherCombo = new Combo(shell, SWT.READ_ONLY);
+
+			new Label(shell, SWT.NONE).setText("Father:");
+			fatherCombo = new Combo(shell, SWT.READ_ONLY);
+
+			DataBindingContext bindingContext = new DataBindingContext();
+			bindGUI(bindingContext);
+
+			GridLayoutFactory.swtDefaults().numColumns(2).applyTo(shell);
+			// Open and return the Shell
+			shell.setSize(500, 300);
+			shell.open();
+			return shell;
+		}
+
+		private void createColumn(String string) {
+			final TableColumn column = new TableColumn(duckFamily, SWT.NONE);
+			column.setWidth(100);
+			column.setText(string);
+		}
+
+		protected void bindGUI(DataBindingContext bindingContext) {
+			// Since we're using a JFace Viewer, we do first wrap our Table...
+			TableViewer peopleViewer = new TableViewer(duckFamily);
+			peopleViewer.addFilter(new ViewerFilter() {
+				public boolean select(Viewer viewer, Object parentElement,
+						Object element) {
+					return element != UNKNOWN;
+				}
+			});
+
+			// Bind viewers to model
+			ViewerSupport.bind(peopleViewer, viewModel.getPeople(),
+					BeanProperties.values(new String[] { "name", "mother.name",
+							"father.name", "mother.mother.name" }));
+
+			// Bind viewer selection to detail fields
+			IObservableValue selection = ViewersObservables
+					.observeSingleSelection(peopleViewer);
+			bindingContext.bindValue(SWTObservables.observeText(nameText,
+					SWT.Modify), BeansObservables.observeDetailValue(selection,
+					"name", String.class));
+
+			ComboViewer mothercomboViewer = new ComboViewer(motherCombo);
+			ViewerSupport.bind(mothercomboViewer, viewModel.getPeople(),
+					BeanProperties.value("name"));
+			bindingContext.bindValue(ViewersObservables
+					.observeSingleSelection(mothercomboViewer),
+					BeansObservables.observeDetailValue(selection, "mother",
+							Person.class));
+
+			ComboViewer fatherComboViewer = new ComboViewer(fatherCombo);
+			ViewerSupport.bind(fatherComboViewer, viewModel.getPeople(),
+					BeanProperties.value("name"));
+			bindingContext.bindValue(ViewersObservables
+					.observeSingleSelection(fatherComboViewer),
+					BeansObservables.observeDetailValue(selection, "father",
+							Person.class));
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet018CheckboxTableViewerCheckedSelection.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,362 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Matthew Hall and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Matthew Hall - initial API and implementation (bug 124684)
+ *     Matthew Hall - bugs 260329, 260337
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeanProperties;
+import org.eclipse.core.databinding.beans.BeansObservables;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.databinding.observable.value.ComputedValue;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.viewers.ViewerSupport;
+import org.eclipse.jface.databinding.viewers.ViewersObservables;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Snippet 018: Binding to the checked elements in a CheckboxTableViewer.
+ */
+public class Snippet018CheckboxTableViewerCheckedSelection {
+	public static void main(String[] args) {
+		// The SWT event loop
+		final Display display = Display.getDefault();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				ViewModel viewModel = createSampleModel();
+
+				Shell shell = new View(viewModel).createShell();
+				shell.open();
+				while (!shell.isDisposed())
+					if (!display.readAndDispatch())
+						display.sleep();
+			}
+		});
+		display.dispose();
+	}
+
+	private static ViewModel createSampleModel() {
+		ViewModel viewModel = new ViewModel();
+
+		Person stan = createPerson("Stan");
+		Person kyle = createPerson("Kyle");
+		Person eric = createPerson("Eric");
+		Person kenny = createPerson("Kenny");
+		Person wendy = createPerson("Wendy");
+		Person butters = createPerson("Butters");
+
+		setFriends(stan, new Person[] { kyle, eric, kenny, wendy });
+		setFriends(kyle, new Person[] { stan, eric, kenny });
+		setFriends(eric, new Person[] { eric });
+		setFriends(kenny, new Person[] { stan, kyle, eric });
+		setFriends(wendy, new Person[] { stan });
+		setFriends(butters, new Person[0]);
+
+		Person[] people = new Person[] { stan, kyle, eric, kenny, wendy,
+				butters };
+		viewModel.setPeople(Arrays.asList(people));
+		return viewModel;
+	}
+
+	private static Person createPerson(String name) {
+		Person person = new Person();
+		person.setName(name);
+		return person;
+	}
+
+	private static void setFriends(Person person, Person[] friends) {
+		person.setFriends(new HashSet(Arrays.asList(friends)));
+	}
+
+	// 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.
+	static class Person extends AbstractModelObject {
+		private String name;
+		private Set friends = new HashSet();
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			firePropertyChange("name", this.name, this.name = name);
+		}
+
+		public Set getFriends() {
+			return new HashSet(friends);
+		}
+
+		public void setFriends(Set friends) {
+			firePropertyChange("friends", this.friends,
+					this.friends = new HashSet(friends));
+		}
+
+		public String toString() {
+			return name;
+		}
+	}
+
+	// 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
+	// to retrieve, this ViewModel just instantiates a model object to edit.
+	static class ViewModel extends AbstractModelObject {
+		private List people = new ArrayList();
+
+		public List getPeople() {
+			return new ArrayList(people);
+		}
+
+		public void setPeople(List people) {
+			firePropertyChange("people", this.people,
+					this.people = new ArrayList(people));
+		}
+	}
+
+	// The GUI view
+	static class View {
+		private ViewModel viewModel;
+
+		private Shell shell;
+
+		private Button addPersonButton;
+		private Button removePersonButton;
+		private TableViewer peopleViewer;
+		private Text personName;
+		private CheckboxTableViewer friendsViewer;
+
+		public View(ViewModel viewModel) {
+			this.viewModel = viewModel;
+		}
+
+		public Shell createShell() {
+			// Build a UI
+			final Display display = Display.getCurrent();
+			shell = new Shell(display);
+
+			createUI(shell);
+
+			// Bind UI
+			bindUI();
+
+			// Open and return the Shell
+			shell.setSize(shell.computeSize(400, SWT.DEFAULT));
+			shell.open();
+			return shell;
+		}
+
+		private void createUI(Shell shell) {
+			shell.setText("Binding checked elements in CheckboxTableViewer");
+			shell.setLayout(new GridLayout(2, false));
+
+			new Label(shell, SWT.NONE).setText("People");
+
+			Composite buttons = new Composite(shell, SWT.NONE);
+			GridDataFactory.swtDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(
+					buttons);
+			GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(true)
+					.applyTo(buttons);
+			addPersonButton = new Button(buttons, SWT.PUSH);
+			addPersonButton.setText("Add");
+			GridDataFactory.fillDefaults().applyTo(addPersonButton);
+			removePersonButton = new Button(buttons, SWT.PUSH);
+			removePersonButton.setText("Remove");
+			GridDataFactory.fillDefaults().applyTo(removePersonButton);
+
+			Composite peopleComposite = new Composite(shell, SWT.NONE);
+			GridDataFactory.fillDefaults().grab(true, true).span(2, 1).applyTo(
+					peopleComposite);
+			TableColumnLayout peopleColumnLayout = new TableColumnLayout();
+			peopleComposite.setLayout(peopleColumnLayout);
+
+			peopleViewer = new TableViewer(peopleComposite, SWT.SINGLE
+					| SWT.BORDER | SWT.FULL_SELECTION);
+
+			Table peopleTable = peopleViewer.getTable();
+			peopleTable.setHeaderVisible(true);
+			peopleTable.setLinesVisible(true);
+
+			TableColumn nameColumn = new TableColumn(peopleTable, SWT.NONE);
+			nameColumn.setText("Name");
+			peopleColumnLayout.setColumnData(nameColumn,
+					new ColumnWeightData(1));
+
+			TableColumn friendsColumn = new TableColumn(peopleTable, SWT.NONE);
+			friendsColumn.setText("Friends");
+			peopleColumnLayout.setColumnData(friendsColumn,
+					new ColumnWeightData(3));
+
+			new Label(shell, SWT.NONE).setText("Name");
+
+			personName = new Text(shell, SWT.BORDER);
+			GridDataFactory.fillDefaults().grab(true, false)
+					.applyTo(personName);
+
+			new Label(shell, SWT.NONE).setText("Friends");
+
+			Composite friendsComposite = new Composite(shell, SWT.NONE);
+			GridDataFactory.fillDefaults().grab(true, true).applyTo(
+					friendsComposite);
+			TableColumnLayout friendsColumnLayout = new TableColumnLayout();
+			friendsComposite.setLayout(friendsColumnLayout);
+
+			friendsViewer = CheckboxTableViewer.newCheckList(friendsComposite,
+					SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION);
+
+			Table friendsTable = friendsViewer.getTable();
+			friendsTable.setHeaderVisible(true);
+			friendsTable.setLinesVisible(true);
+			TableColumn friendNameColumn = new TableColumn(friendsTable,
+					SWT.NONE);
+			friendNameColumn.setText("Name");
+			friendsColumnLayout.setColumnData(friendNameColumn,
+					new ColumnWeightData(1));
+
+			GridDataFactory.fillDefaults().grab(true, true).applyTo(
+					friendsViewer.getTable());
+		}
+
+		private void bindUI() {
+			DataBindingContext dbc = new DataBindingContext();
+
+			final IObservableList people = BeansObservables.observeList(Realm
+					.getDefault(), viewModel, "people");
+
+			addPersonButton.addListener(SWT.Selection, new Listener() {
+				public void handleEvent(Event event) {
+					InputDialog dlg = new InputDialog(shell, "Add Person",
+							"Enter name:", "<Name>", new IInputValidator() {
+								public String isValid(String newText) {
+									if (newText == null
+											|| newText.length() == 0)
+										return "Name cannot be empty";
+									return null;
+								}
+							});
+					if (dlg.open() == Window.OK) {
+						Person person = new Person();
+						person.setName(dlg.getValue());
+						people.add(person);
+						peopleViewer.setSelection(new StructuredSelection(
+								person));
+					}
+				}
+			});
+
+			removePersonButton.addListener(SWT.Selection, new Listener() {
+				public void handleEvent(Event event) {
+					IStructuredSelection selected = (IStructuredSelection) peopleViewer
+							.getSelection();
+					if (selected.isEmpty())
+						return;
+					Person person = (Person) selected.getFirstElement();
+					if (MessageDialog.openConfirm(shell, "Remove person",
+							"Remove " + person.getName() + "?"))
+						people.remove(person);
+				}
+			});
+
+			ViewerSupport.bind(peopleViewer, people, BeanProperties.values(
+					Person.class, new String[] { "name", "friends" }));
+
+			final IObservableValue selectedPerson = ViewersObservables
+					.observeSingleSelection(peopleViewer);
+
+			IObservableValue personSelected = new ComputedValue(Boolean.TYPE) {
+				protected Object calculate() {
+					return Boolean.valueOf(selectedPerson.getValue() != null);
+				}
+			};
+			dbc.bindValue(SWTObservables.observeEnabled(removePersonButton),
+					personSelected);
+			dbc.bindValue(SWTObservables.observeEnabled(friendsViewer
+					.getTable()), personSelected);
+
+			dbc.bindValue(SWTObservables.observeText(personName, SWT.Modify),
+					BeansObservables.observeDetailValue(selectedPerson, "name",
+							String.class));
+
+			ViewerSupport.bind(friendsViewer, people, BeanProperties.value(
+					Person.class, "name"));
+
+			dbc.bindSet(ViewersObservables.observeCheckedElements(
+					friendsViewer, Person.class), BeansObservables
+					.observeDetailSet(selectedPerson, "friends", Person.class));
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet019TreeViewerWithListFactory.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,326 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Matthew Hall - bugs 260329, 260337
+ *******************************************************************************/
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeanProperties;
+import org.eclipse.core.databinding.beans.BeansObservables;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.ComputedValue;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.viewers.ViewerSupport;
+import org.eclipse.jface.databinding.viewers.ViewersObservables;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+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.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+public class Snippet019TreeViewerWithListFactory {
+
+	private Button pasteButton;
+	private Button copyButton;
+	private Shell shell;
+	private Button addChildBeanButton;
+	private Button removeBeanButton;
+	private TreeViewer beanViewer;
+	private Tree tree;
+	private Text beanText;
+	private DataBindingContext m_bindingContext;
+
+	private Bean input = createBean("input");
+	private IObservableValue clipboard;
+
+	/**
+	 * Launch the application
+	 * 
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		Display display = Display.getDefault();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				try {
+					Snippet019TreeViewerWithListFactory window = new Snippet019TreeViewerWithListFactory();
+					window.open();
+				} catch (Exception e) {
+					e.printStackTrace();
+				}
+			}
+		});
+	}
+
+	/**
+	 * Open the window
+	 */
+	public void open() {
+		final Display display = Display.getDefault();
+		createContents();
+		shell.open();
+		shell.layout();
+		while (!shell.isDisposed()) {
+			if (!display.readAndDispatch())
+				display.sleep();
+		}
+	}
+
+	/**
+	 * Create contents of the window
+	 */
+	protected void createContents() {
+		shell = new Shell();
+		final GridLayout gridLayout_1 = new GridLayout();
+		gridLayout_1.numColumns = 2;
+		shell.setLayout(gridLayout_1);
+		shell.setSize(535, 397);
+		shell.setText("SWT Application");
+
+		final Composite group = new Composite(shell, SWT.NONE);
+		final RowLayout rowLayout = new RowLayout();
+		rowLayout.marginTop = 0;
+		rowLayout.marginRight = 0;
+		rowLayout.marginLeft = 0;
+		rowLayout.marginBottom = 0;
+		rowLayout.pack = false;
+		group.setLayout(rowLayout);
+		group
+				.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false,
+						2, 1));
+
+		final Button addRootButton = new Button(group, SWT.NONE);
+		addRootButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(final SelectionEvent e) {
+				List list = input.getList();
+				Bean root = createBean("root");
+				list.add(root);
+				input.setList(list);
+
+				beanViewer.setSelection(new StructuredSelection(root));
+				beanText.selectAll();
+				beanText.setFocus();
+			}
+		});
+		addRootButton.setText("Add Root");
+
+		addChildBeanButton = new Button(group, SWT.NONE);
+		addChildBeanButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(final SelectionEvent e) {
+				Bean parent = getSelectedBean();
+				List list = new ArrayList(parent.getList());
+				Bean child = createBean("child");
+				list.add(child);
+				parent.setList(list);
+
+				beanViewer.setSelection(new StructuredSelection(child));
+				beanText.selectAll();
+				beanText.setFocus();
+			}
+		});
+		addChildBeanButton.setText("Add Child");
+
+		removeBeanButton = new Button(group, SWT.NONE);
+		removeBeanButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(final SelectionEvent e) {
+				TreeItem selectedItem = beanViewer.getTree().getSelection()[0];
+				TreeItem parentItem = selectedItem.getParentItem();
+				Bean parent;
+				int index;
+				if (parentItem == null) {
+					parent = input;
+					index = beanViewer.getTree().indexOf(selectedItem);
+				} else {
+					parent = (Bean) parentItem.getData();
+					index = parentItem.indexOf(selectedItem);
+				}
+
+				List list = new ArrayList(parent.getList());
+				list.remove(index);
+				parent.setList(list);
+			}
+		});
+		removeBeanButton.setText("Remove");
+
+		copyButton = new Button(group, SWT.NONE);
+		copyButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(final SelectionEvent e) {
+				clipboard.setValue(getSelectedBean());
+			}
+		});
+		copyButton.setText("Copy");
+
+		pasteButton = new Button(group, SWT.NONE);
+		pasteButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(final SelectionEvent e) {
+				Bean copy = (Bean) clipboard.getValue();
+				if (copy == null)
+					return;
+				Bean parent = getSelectedBean();
+				if (parent == null)
+					parent = input;
+
+				List list = new ArrayList(parent.getList());
+				list.add(copy);
+				parent.setList(list);
+
+				beanViewer.setSelection(new StructuredSelection(copy));
+				beanText.selectAll();
+				beanText.setFocus();
+			}
+		});
+		pasteButton.setText("Paste");
+
+		final Button refreshButton = new Button(group, SWT.NONE);
+		refreshButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(final SelectionEvent e) {
+				beanViewer.refresh();
+			}
+		});
+		refreshButton.setText("Refresh");
+
+		beanViewer = new TreeViewer(shell, SWT.FULL_SELECTION | SWT.BORDER);
+		beanViewer.setUseHashlookup(true);
+		tree = beanViewer.getTree();
+		tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+
+		final Label itemNameLabel = new Label(shell, SWT.NONE);
+		itemNameLabel.setText("Item Name");
+
+		beanText = new Text(shell, SWT.BORDER);
+		final GridData gd_beanValue = new GridData(SWT.FILL, SWT.CENTER, true,
+				false);
+		beanText.setLayoutData(gd_beanValue);
+		m_bindingContext = initDataBindings();
+		//
+		initExtraBindings(m_bindingContext);
+	}
+
+	private static Bean createBean(String name) {
+		return new Bean(name);
+	}
+
+	protected DataBindingContext initDataBindings() {
+		IObservableValue treeViewerSelectionObserveSelection = ViewersObservables
+				.observeSingleSelection(beanViewer);
+		IObservableValue textTextObserveWidget = SWTObservables.observeText(
+				beanText, SWT.Modify);
+		IObservableValue treeViewerValueObserveDetailValue = BeansObservables
+				.observeDetailValue(treeViewerSelectionObserveSelection,
+						"text", String.class);
+		//
+		//
+		DataBindingContext bindingContext = new DataBindingContext();
+		//
+		bindingContext.bindValue(textTextObserveWidget,
+				treeViewerValueObserveDetailValue);
+		//
+		return bindingContext;
+	}
+
+	private Bean getSelectedBean() {
+		IStructuredSelection selection = (IStructuredSelection) beanViewer
+				.getSelection();
+		if (selection.isEmpty())
+			return null;
+		return (Bean) selection.getFirstElement();
+	}
+
+	private void initExtraBindings(DataBindingContext dbc) {
+		final IObservableValue beanViewerSelection = ViewersObservables
+				.observeSingleSelection(beanViewer);
+		IObservableValue beanSelected = new ComputedValue(Boolean.TYPE) {
+			protected Object calculate() {
+				return Boolean.valueOf(beanViewerSelection.getValue() != null);
+			}
+		};
+		dbc.bindValue(SWTObservables.observeEnabled(addChildBeanButton),
+				beanSelected);
+		dbc.bindValue(SWTObservables.observeEnabled(removeBeanButton),
+				beanSelected);
+
+		clipboard = new WritableValue();
+		dbc.bindValue(SWTObservables.observeEnabled(copyButton), beanSelected);
+		dbc.bindValue(SWTObservables.observeEnabled(pasteButton),
+				new ComputedValue(Boolean.TYPE) {
+					protected Object calculate() {
+						return Boolean.valueOf(clipboard.getValue() != null);
+					}
+				});
+
+		ViewerSupport.bind(beanViewer, input, BeanProperties.list("list",
+				Bean.class), BeanProperties.value(Bean.class, "text"));
+	}
+
+	static class Bean {
+		/* package */PropertyChangeSupport changeSupport = new PropertyChangeSupport(
+				this);
+		private String text;
+		private List list;
+
+		public Bean(String text) {
+			this.text = text;
+			list = new ArrayList();
+		}
+
+		public void addPropertyChangeListener(PropertyChangeListener listener) {
+			changeSupport.addPropertyChangeListener(listener);
+		}
+
+		public void removePropertyChangeListener(PropertyChangeListener listener) {
+			changeSupport.removePropertyChangeListener(listener);
+		}
+
+		public String getText() {
+			return text;
+		}
+
+		public void setText(String value) {
+			changeSupport.firePropertyChange("text", this.text,
+					this.text = value);
+		}
+
+		public List getList() {
+			if (list == null)
+				return null;
+			return new ArrayList(list);
+		}
+
+		public void setList(List list) {
+			if (list != null)
+				list = new ArrayList(list);
+			changeSupport.firePropertyChange("list", this.list,
+					this.list = list);
+		}
+
+		public boolean hasListeners(String propertyName) {
+			return changeSupport.hasListeners(propertyName);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet020TreeViewerWithSetFactory.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,325 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Matthew Hall - bugs 260329, 260337
+ *******************************************************************************/
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeanProperties;
+import org.eclipse.core.databinding.beans.BeansObservables;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.ComputedValue;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.viewers.ViewerSupport;
+import org.eclipse.jface.databinding.viewers.ViewersObservables;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+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.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+public class Snippet020TreeViewerWithSetFactory {
+
+	private Button pasteButton;
+	private Button copyButton;
+	private Shell shell;
+	private Button addChildBeanButton;
+	private Button removeBeanButton;
+	private TreeViewer beanViewer;
+	private Tree tree;
+	private Text beanText;
+	private DataBindingContext m_bindingContext;
+
+	private Bean input = createBean("input");
+	private IObservableValue clipboard;
+	static int counter = 0;
+
+	/**
+	 * Launch the application
+	 * 
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		Display display = Display.getDefault();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				try {
+					Snippet020TreeViewerWithSetFactory window = new Snippet020TreeViewerWithSetFactory();
+					window.open();
+				} catch (Exception e) {
+					e.printStackTrace();
+				}
+			}
+		});
+	}
+
+	/**
+	 * Open the window
+	 */
+	public void open() {
+		final Display display = Display.getDefault();
+		createContents();
+		shell.open();
+		shell.layout();
+		while (!shell.isDisposed()) {
+			if (!display.readAndDispatch())
+				display.sleep();
+		}
+	}
+
+	/**
+	 * Create contents of the window
+	 */
+	protected void createContents() {
+		shell = new Shell();
+		final GridLayout gridLayout_1 = new GridLayout();
+		gridLayout_1.numColumns = 2;
+		shell.setLayout(gridLayout_1);
+		shell.setSize(535, 397);
+		shell.setText("SWT Application");
+
+		final Composite group = new Composite(shell, SWT.NONE);
+		final RowLayout rowLayout = new RowLayout();
+		rowLayout.marginTop = 0;
+		rowLayout.marginRight = 0;
+		rowLayout.marginLeft = 0;
+		rowLayout.marginBottom = 0;
+		rowLayout.pack = false;
+		group.setLayout(rowLayout);
+		group
+				.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false,
+						2, 1));
+
+		final Button addRootButton = new Button(group, SWT.NONE);
+		addRootButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(final SelectionEvent e) {
+				Set set = input.getSet();
+				Bean root = createBean("root");
+				set.add(root);
+				input.setSet(set);
+
+				beanViewer.setSelection(new StructuredSelection(root));
+				beanText.selectAll();
+				beanText.setFocus();
+			}
+		});
+		addRootButton.setText("Add Root");
+
+		addChildBeanButton = new Button(group, SWT.NONE);
+		addChildBeanButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(final SelectionEvent e) {
+				Bean parent = getSelectedBean();
+				Set set = new HashSet(parent.getSet());
+				Bean child = createBean("child" + (counter++));
+				set.add(child);
+				parent.setSet(set);
+
+				// beanViewer.setSelection(new StructuredSelection(parent));
+				// beanText.selectAll();
+				// beanText.setFocus();
+			}
+		});
+		addChildBeanButton.setText("Add Child");
+
+		removeBeanButton = new Button(group, SWT.NONE);
+		removeBeanButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(final SelectionEvent e) {
+				TreeItem selectedItem = beanViewer.getTree().getSelection()[0];
+				Bean bean = (Bean) selectedItem.getData();
+				TreeItem parentItem = selectedItem.getParentItem();
+				Bean parent;
+				if (parentItem == null)
+					parent = input;
+				else
+					parent = (Bean) parentItem.getData();
+
+				Set set = new HashSet(parent.getSet());
+				set.remove(bean);
+				parent.setSet(set);
+			}
+		});
+		removeBeanButton.setText("Remove");
+
+		copyButton = new Button(group, SWT.NONE);
+		copyButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(final SelectionEvent e) {
+				clipboard.setValue(getSelectedBean());
+			}
+		});
+		copyButton.setText("Copy");
+
+		pasteButton = new Button(group, SWT.NONE);
+		pasteButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(final SelectionEvent e) {
+				Bean copy = (Bean) clipboard.getValue();
+				if (copy == null)
+					return;
+				Bean parent = getSelectedBean();
+				if (parent == null)
+					parent = input;
+
+				Set set = new HashSet(parent.getSet());
+				set.add(copy);
+				parent.setSet(set);
+
+				beanViewer.setSelection(new StructuredSelection(copy));
+				beanText.selectAll();
+				beanText.setFocus();
+			}
+		});
+		pasteButton.setText("Paste");
+
+		final Button refreshButton = new Button(group, SWT.NONE);
+		refreshButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(final SelectionEvent e) {
+				beanViewer.refresh();
+			}
+		});
+		refreshButton.setText("Refresh");
+
+		beanViewer = new TreeViewer(shell, SWT.FULL_SELECTION | SWT.BORDER);
+		beanViewer.setUseHashlookup(true);
+		beanViewer.setComparator(new ViewerComparator());
+		tree = beanViewer.getTree();
+		tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+
+		final Label itemNameLabel = new Label(shell, SWT.NONE);
+		itemNameLabel.setText("Item Name");
+
+		beanText = new Text(shell, SWT.BORDER);
+		final GridData gd_beanValue = new GridData(SWT.FILL, SWT.CENTER, true,
+				false);
+		beanText.setLayoutData(gd_beanValue);
+		m_bindingContext = initDataBindings();
+		//
+		initExtraBindings(m_bindingContext);
+	}
+
+	private static Bean createBean(String name) {
+		return new Bean(name);
+	}
+
+	protected DataBindingContext initDataBindings() {
+		IObservableValue treeViewerSelectionObserveSelection = ViewersObservables
+				.observeSingleSelection(beanViewer);
+		IObservableValue textTextObserveWidget = SWTObservables.observeText(
+				beanText, SWT.Modify);
+		IObservableValue treeViewerValueObserveDetailValue = BeansObservables
+				.observeDetailValue(treeViewerSelectionObserveSelection,
+						"text", String.class);
+		//
+		//
+		DataBindingContext bindingContext = new DataBindingContext();
+		//
+		bindingContext.bindValue(textTextObserveWidget,
+				treeViewerValueObserveDetailValue);
+		//
+		return bindingContext;
+	}
+
+	private Bean getSelectedBean() {
+		IStructuredSelection selection = (IStructuredSelection) beanViewer
+				.getSelection();
+		if (selection.isEmpty())
+			return null;
+		return (Bean) selection.getFirstElement();
+	}
+
+	private void initExtraBindings(DataBindingContext dbc) {
+		final IObservableValue beanViewerSelection = ViewersObservables
+				.observeSingleSelection(beanViewer);
+		IObservableValue beanSelected = new ComputedValue(Boolean.TYPE) {
+			protected Object calculate() {
+				return Boolean.valueOf(beanViewerSelection.getValue() != null);
+			}
+		};
+		dbc.bindValue(SWTObservables.observeEnabled(addChildBeanButton),
+				beanSelected);
+		dbc.bindValue(SWTObservables.observeEnabled(removeBeanButton),
+				beanSelected);
+
+		clipboard = new WritableValue();
+		dbc.bindValue(SWTObservables.observeEnabled(copyButton), beanSelected);
+		dbc.bindValue(SWTObservables.observeEnabled(pasteButton),
+				new ComputedValue(Boolean.TYPE) {
+					protected Object calculate() {
+						return Boolean.valueOf(clipboard.getValue() != null);
+					}
+				});
+
+		ViewerSupport.bind(beanViewer, input, BeanProperties.set("set",
+				Bean.class), BeanProperties.value(Bean.class, "text"));
+	}
+
+	static class Bean {
+		/* package */PropertyChangeSupport changeSupport = new PropertyChangeSupport(
+				this);
+		private String text;
+		private Set set;
+
+		public Bean(String text) {
+			this.text = text;
+			set = new HashSet();
+		}
+
+		public void addPropertyChangeListener(PropertyChangeListener listener) {
+			changeSupport.addPropertyChangeListener(listener);
+		}
+
+		public void removePropertyChangeListener(PropertyChangeListener listener) {
+			changeSupport.removePropertyChangeListener(listener);
+		}
+
+		public String getText() {
+			return text;
+		}
+
+		public void setText(String value) {
+			changeSupport.firePropertyChange("text", this.text,
+					this.text = value);
+		}
+
+		public Set getSet() {
+			if (set == null)
+				return null;
+			return new HashSet(set);
+		}
+
+		public void setSet(Set set) {
+			if (set != null)
+				set = new HashSet(set);
+			changeSupport.firePropertyChange("set", this.set, this.set = set);
+		}
+
+		public boolean hasListeners(String propertyName) {
+			return changeSupport.hasListeners(propertyName);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet021MultiFieldValidation.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,357 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Matthew Hall and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Matthew Hall - initial API and implementation (bug 218269)
+ *     Matthew Hall - bug 260329
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.databinding.observable.list.WritableList;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.core.databinding.validation.MultiValidator;
+import org.eclipse.core.databinding.validation.ValidationStatus;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
+import org.eclipse.jface.databinding.wizard.WizardPageSupport;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ListViewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.jface.wizard.WizardPage;
+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.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * @since 3.2
+ * 
+ */
+public class Snippet021MultiFieldValidation extends WizardPage {
+
+	private List list_1;
+	private List list;
+	private Button addAddendButton;
+	private Button removeAddendButton;
+	private Text sumModelValue;
+	private Text field2ModelValue;
+	private Text field1ModelValue;
+	private Text sumTarget;
+	private Text field2Target;
+	private Text field1Target;
+	private ListViewer addendsTarget;
+	private ListViewer addendsModelValue;
+
+	/**
+	 * Create the wizard
+	 */
+	public Snippet021MultiFieldValidation() {
+		super("snippet021");
+		setTitle("Snippet 021 - Multi-field Validators");
+		setDescription("Enter values which satisfy the cross-field constraints");
+	}
+
+	/**
+	 * Create contents of the wizard
+	 * 
+	 * @param parent
+	 */
+	public void createControl(Composite parent) {
+		Composite container = new Composite(parent, SWT.NULL);
+		final GridLayout gridLayout = new GridLayout();
+		gridLayout.numColumns = 2;
+		container.setLayout(gridLayout);
+		//
+		setControl(container);
+
+		final Group bothEvenOrGroup = new Group(container, SWT.NONE);
+		bothEvenOrGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false,
+				false));
+		bothEvenOrGroup.setText("Numbers must be both even or both odd");
+		final GridLayout gridLayout_1 = new GridLayout();
+		gridLayout_1.numColumns = 3;
+		bothEvenOrGroup.setLayout(gridLayout_1);
+		new Label(bothEvenOrGroup, SWT.NONE);
+
+		final Label targetLabel = new Label(bothEvenOrGroup, SWT.NONE);
+		targetLabel.setText("Target");
+
+		final Label modelLabel = new Label(bothEvenOrGroup, SWT.NONE);
+		modelLabel.setText("Model");
+
+		final Label field1Label = new Label(bothEvenOrGroup, SWT.NONE);
+		field1Label.setText("Field 1");
+
+		field1Target = new Text(bothEvenOrGroup, SWT.BORDER);
+		final GridData gd_field1Target = new GridData(SWT.FILL, SWT.CENTER,
+				true, false);
+		field1Target.setLayoutData(gd_field1Target);
+
+		field1ModelValue = new Text(bothEvenOrGroup, SWT.READ_ONLY | SWT.BORDER);
+		final GridData gd_field1ModelValue = new GridData(SWT.FILL, SWT.CENTER,
+				true, false);
+		field1ModelValue.setLayoutData(gd_field1ModelValue);
+
+		final Label field2Label = new Label(bothEvenOrGroup, SWT.NONE);
+		field2Label.setText("Field 2");
+
+		field2Target = new Text(bothEvenOrGroup, SWT.BORDER);
+		final GridData gd_field2Target = new GridData(SWT.FILL, SWT.CENTER,
+				true, false);
+		field2Target.setLayoutData(gd_field2Target);
+
+		field2ModelValue = new Text(bothEvenOrGroup, SWT.READ_ONLY | SWT.BORDER);
+		final GridData gd_field2ModelValue = new GridData(SWT.FILL, SWT.CENTER,
+				true, false);
+		field2ModelValue.setLayoutData(gd_field2ModelValue);
+
+		final Group sumOfAllGroup = new Group(container, SWT.NONE);
+		sumOfAllGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false,
+				true));
+		sumOfAllGroup.setText("Addends must add up to sum");
+		final GridLayout gridLayout_2 = new GridLayout();
+		gridLayout_2.numColumns = 3;
+		sumOfAllGroup.setLayout(gridLayout_2);
+		new Label(sumOfAllGroup, SWT.NONE);
+
+		final Label targetLabel_1 = new Label(sumOfAllGroup, SWT.NONE);
+		targetLabel_1.setText("Target");
+
+		final Label modelLabel_1 = new Label(sumOfAllGroup, SWT.NONE);
+		modelLabel_1.setText("Model");
+
+		final Label expectedSumLabel = new Label(sumOfAllGroup, SWT.NONE);
+		expectedSumLabel.setText("Sum");
+
+		sumTarget = new Text(sumOfAllGroup, SWT.BORDER);
+		final GridData gd_sumTarget = new GridData(SWT.FILL, SWT.CENTER, true,
+				false);
+		sumTarget.setLayoutData(gd_sumTarget);
+
+		sumModelValue = new Text(sumOfAllGroup, SWT.READ_ONLY | SWT.BORDER);
+		final GridData gd_sumModelValue = new GridData(SWT.FILL, SWT.CENTER,
+				true, false);
+		sumModelValue.setLayoutData(gd_sumModelValue);
+
+		final Label addendsLabel = new Label(sumOfAllGroup, SWT.NONE);
+		addendsLabel.setText("Addends");
+
+		addendsTarget = new ListViewer(sumOfAllGroup, SWT.V_SCROLL | SWT.BORDER);
+		list_1 = addendsTarget.getList();
+		list_1
+				.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true, 1,
+						2));
+
+		addendsModelValue = new ListViewer(sumOfAllGroup, SWT.V_SCROLL
+				| SWT.BORDER);
+		list = addendsModelValue.getList();
+		list.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true, 1, 2));
+
+		final Composite composite = new Composite(sumOfAllGroup, SWT.NONE);
+		composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+		final GridLayout gridLayout_3 = new GridLayout();
+		gridLayout_3.marginWidth = 0;
+		gridLayout_3.marginHeight = 0;
+		composite.setLayout(gridLayout_3);
+
+		addAddendButton = new Button(composite, SWT.NONE);
+		addAddendButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
+				false));
+		addAddendButton.setText("Add");
+
+		removeAddendButton = new Button(composite, SWT.NONE);
+		removeAddendButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
+				false, false));
+		removeAddendButton.setText("Remove");
+
+		bindUI();
+	}
+
+	private void bindUI() {
+		DataBindingContext dbc = new DataBindingContext();
+
+		bindEvensAndOddsGroup(dbc);
+		bindSumAndAddendsGroup(dbc);
+
+		WizardPageSupport.create(this, dbc);
+	}
+
+	private void bindEvensAndOddsGroup(DataBindingContext dbc) {
+		IObservableValue targetField1 = SWTObservables.observeText(
+				field1Target, SWT.Modify);
+		final IObservableValue middleField1 = new WritableValue(null,
+				Integer.TYPE);
+		dbc.bindValue(targetField1, middleField1);
+
+		IObservableValue targetField2 = SWTObservables.observeText(
+				field2Target, SWT.Modify);
+		final IObservableValue middleField2 = new WritableValue(null,
+				Integer.TYPE);
+		dbc.bindValue(targetField2, middleField2);
+
+		MultiValidator validator = new MultiValidator() {
+			protected IStatus validate() {
+				Integer field1 = (Integer) middleField1.getValue();
+				Integer field2 = (Integer) middleField2.getValue();
+				if (Math.abs(field1.intValue()) % 2 != Math.abs(field2
+						.intValue()) % 2)
+					return ValidationStatus
+							.error("Fields 1 and 2 must be both even or both odd");
+				return null;
+			}
+		};
+		dbc.addValidationStatusProvider(validator);
+
+		IObservableValue modelField1 = new WritableValue(new Integer(1),
+				Integer.TYPE);
+		IObservableValue modelField2 = new WritableValue(new Integer(4),
+				Integer.TYPE);
+		dbc.bindValue(validator.observeValidatedValue(middleField1),
+				modelField1);
+		dbc.bindValue(validator.observeValidatedValue(middleField2),
+				modelField2);
+
+		dbc.bindValue(SWTObservables.observeText(field1ModelValue, SWT.Modify),
+				modelField1);
+		dbc.bindValue(SWTObservables.observeText(field2ModelValue, SWT.Modify),
+				modelField2);
+	}
+
+	private void bindSumAndAddendsGroup(DataBindingContext dbc) {
+		IObservableValue targetSum = SWTObservables.observeText(sumTarget,
+				SWT.Modify);
+		final IObservableValue middleSum = new WritableValue(null, Integer.TYPE);
+		dbc.bindValue(targetSum, middleSum);
+
+		final IObservableList targetAddends = new WritableList(new ArrayList(),
+				Integer.TYPE);
+		addendsTarget.setContentProvider(new ObservableListContentProvider());
+		addendsTarget.setInput(targetAddends);
+
+		addAddendButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(final SelectionEvent e) {
+				InputDialog dialog = new InputDialog(getShell(),
+						"Input addend", "Enter an integer addend", "0",
+						new IInputValidator() {
+							public String isValid(String newText) {
+								try {
+									Integer.valueOf(newText);
+									return null;
+								} catch (NumberFormatException e) {
+									return "Enter a number between "
+											+ Integer.MIN_VALUE + " and "
+											+ Integer.MAX_VALUE;
+								}
+							}
+						});
+				if (dialog.open() == Window.OK) {
+					targetAddends.add(Integer.valueOf(dialog.getValue()));
+				}
+			}
+		});
+
+		removeAddendButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent e) {
+				IStructuredSelection selection = (IStructuredSelection) addendsTarget
+						.getSelection();
+				if (!selection.isEmpty())
+					targetAddends.remove(selection.getFirstElement());
+			}
+		});
+
+		IObservableValue modelSum = new WritableValue(new Integer(5),
+				Integer.TYPE);
+		dbc.bindValue(SWTObservables.observeText(sumModelValue, SWT.Modify),
+				modelSum);
+
+		IObservableList modelAddends = new WritableList(new ArrayList(),
+				Integer.TYPE);
+
+		MultiValidator validator = new MultiValidator() {
+			protected IStatus validate() {
+				Integer sum = (Integer) middleSum.getValue();
+				int actualSum = 0;
+				for (Iterator iterator = targetAddends.iterator(); iterator
+						.hasNext();) {
+					actualSum += ((Integer) iterator.next()).intValue();
+				}
+				if (sum.intValue() != actualSum)
+					return ValidationStatus.error("Sum of addends is "
+							+ actualSum + ", expecting " + sum);
+				return ValidationStatus.ok();
+			}
+		};
+		dbc.addValidationStatusProvider(validator);
+
+		addendsModelValue
+				.setContentProvider(new ObservableListContentProvider());
+		addendsModelValue.setInput(modelAddends);
+
+		dbc.bindValue(validator.observeValidatedValue(middleSum), modelSum);
+		dbc.bindList(validator.observeValidatedList(targetAddends),
+				modelAddends);
+	}
+
+	static class MultiFieldValidationWizard extends Wizard {
+		public void addPages() {
+			addPage(new Snippet021MultiFieldValidation());
+		}
+
+		public String getWindowTitle() {
+			return "Snippet 021 - Multi-field Validation";
+		}
+
+		public boolean performFinish() {
+			return true;
+		}
+	}
+
+	public static void main(String[] args) {
+		Display display = new Display();
+
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				IWizard wizard = new MultiFieldValidationWizard();
+				WizardDialog dialog = new WizardDialog(null, wizard);
+				dialog.open();
+
+				// The SWT event loop
+				Display display = Display.getCurrent();
+				while (dialog.getShell() != null
+						&& !dialog.getShell().isDisposed()) {
+					if (!display.readAndDispatch()) {
+						display.sleep();
+					}
+				}
+			}
+		});
+
+		display.dispose();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet022ComputedListCombo.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.ComputedList;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.databinding.observable.list.WritableList;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * @since 3.2
+ * 
+ */
+public class Snippet022ComputedListCombo {
+	private static WritableList model;
+
+	public static void main(String[] args) {
+		Display display = new Display();
+		final Shell shell = new Shell(display);
+		shell.setLayout(new GridLayout(1, false));
+
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				Snippet022ComputedListCombo snippet = new Snippet022ComputedListCombo();
+				snippet.createModel();
+				snippet.createControls(shell);
+			}
+		});
+
+		shell.pack();
+		shell.open();
+		while (!shell.isDisposed()) {
+			if (!display.readAndDispatch())
+				display.sleep();
+		}
+		display.dispose();
+	}
+
+	/**
+	 * 
+	 */
+	protected void createModel() {
+		model = new WritableList();
+		model.add(new Thing("Alice", true, false));
+		model.add(new Thing("Beth", true, false));
+		model.add(new Thing("Cathy", true, false));
+		model.add(new Thing("Arthur", false, true));
+		model.add(new Thing("Bob", false, true));
+		model.add(new Thing("Curtis", false, true));
+		model.add(new Thing("Snail", true, true));
+		model.add(new Thing("Nail", false, false));
+	}
+
+	/**
+	 * @param shell
+	 */
+	protected void createControls(Shell shell) {
+		Composite composite = new Composite(shell, SWT.NONE);
+		Group group = new Group(composite, SWT.NONE);
+		group.setText("Filter");
+		Button male = new Button(group, SWT.CHECK);
+		male.setText("Male");
+		Button female = new Button(group, SWT.CHECK);
+		female.setText("Female");
+		final IObservableValue femaleObservable = SWTObservables
+				.observeSelection(female);
+		final IObservableValue maleObservable = SWTObservables
+				.observeSelection(male);
+		Combo combo = new Combo(composite, SWT.DROP_DOWN | SWT.READ_ONLY);
+		GridDataFactory.defaultsFor(combo).align(SWT.BEGINNING, SWT.BEGINNING)
+				.applyTo(combo);
+		ComboViewer viewer = new ComboViewer(combo);
+		viewer.setContentProvider(new ObservableListContentProvider());
+		// We should really have an out-of-the box filtered list...
+		IObservableList filteredList = new ComputedList() {
+			protected List calculate() {
+				ArrayList result = new ArrayList();
+				for (Iterator it = model.iterator(); it.hasNext();) {
+					Thing thing = (Thing) it.next();
+					if (((Boolean) femaleObservable.getValue()).booleanValue()
+							&& !thing.female)
+						continue;
+					if (((Boolean) maleObservable.getValue()).booleanValue()
+							&& !thing.male)
+						continue;
+					result.add(thing);
+				}
+				return result;
+			}
+		};
+		viewer.setInput(filteredList);
+		GridLayoutFactory.swtDefaults().applyTo(group);
+		GridLayoutFactory.swtDefaults().applyTo(composite);
+	}
+
+	static class Thing {
+		String name;
+		boolean male;
+		boolean female;
+
+		public Thing(String name, boolean female, boolean male) {
+			this.name = name;
+			this.female = female;
+			this.male = male;
+		}
+
+		public String toString() {
+			return name;
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet023ConditionalVisibility.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.jface.databinding.swt.ISWTObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.internal.databinding.provisional.swt.ControlUpdater;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StackLayout;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * @since 3.2
+ * 
+ */
+public class Snippet023ConditionalVisibility {
+	public static void main(String[] args) {
+		Display display = new Display();
+		final Shell shell = new Shell(display);
+		shell.setLayout(new GridLayout(1, false));
+
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				new Snippet023ConditionalVisibility().createControls(shell);
+			}
+		});
+
+		shell.pack();
+		shell.open();
+		while (!shell.isDisposed()) {
+			if (!display.readAndDispatch())
+				display.sleep();
+		}
+		display.dispose();
+	}
+
+	Text text;
+	Text toText;
+	Text fromText;
+
+	/**
+	 * @param shell
+	 */
+	private void createControls(Shell shell) {
+		Composite composite = new Composite(shell, SWT.NONE);
+		Group radioGroup = new Group(composite, SWT.NONE);
+		radioGroup.setText("Type");
+		Button textButton = new Button(radioGroup, SWT.RADIO);
+		textButton.setText("Text");
+		Button rangeButton = new Button(radioGroup, SWT.RADIO);
+		rangeButton.setText("Range");
+		GridLayoutFactory.swtDefaults().generateLayout(radioGroup);
+
+		final Composite oneOfTwo = new Composite(composite, SWT.NONE);
+		final StackLayout stackLayout = new StackLayout();
+		oneOfTwo.setLayout(stackLayout);
+
+		final Group rangeGroup = new Group(oneOfTwo, SWT.NONE);
+		rangeGroup.setText("Range");
+		Label fromLabel = new Label(rangeGroup, SWT.NONE);
+		fromLabel.setText("From:");
+		fromText = new Text(rangeGroup, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
+
+		Label toLabel = new Label(rangeGroup, SWT.NONE);
+		toLabel.setText("To:");
+		toText = new Text(rangeGroup, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
+		GridLayoutFactory.swtDefaults().numColumns(2)
+				.generateLayout(rangeGroup);
+
+		final Group textGroup = new Group(oneOfTwo, SWT.NONE);
+		textGroup.setText("Text");
+		Label label = new Label(textGroup, SWT.NONE);
+		label.setText("Text:");
+		text = new Text(textGroup, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
+		GridLayoutFactory.swtDefaults().numColumns(2).generateLayout(textGroup);
+
+		GridLayoutFactory.swtDefaults().numColumns(2).generateLayout(composite);
+
+		final ISWTObservableValue rangeSelected = SWTObservables
+				.observeSelection(rangeButton);
+		final ISWTObservableValue textSelected = SWTObservables
+				.observeSelection(textButton);
+
+		// Note that ControlUpdater is not API.
+		new ControlUpdater(oneOfTwo) {
+			protected void updateControl() {
+				if (((Boolean) rangeSelected.getValue()).booleanValue()) {
+					stackLayout.topControl = rangeGroup;
+					oneOfTwo.layout();
+				} else if (((Boolean) textSelected.getValue()).booleanValue()) {
+					stackLayout.topControl = textGroup;
+					oneOfTwo.layout();
+				}
+			}
+		};
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet024SelectObservableValue.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Matthew Hall and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Matthew Hall - initial API and implementation (bug 249992)
+ *     Matthew Hall - bug 260329
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.SelectObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.viewers.IViewerObservableValue;
+import org.eclipse.jface.databinding.viewers.ViewersObservables;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ListViewer;
+import org.eclipse.swt.SWT;
+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.Group;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Demonstrate usage of SelectObservableValue
+ * 
+ * @since 3.2
+ */
+public class Snippet024SelectObservableValue {
+	protected Shell shell;
+
+	public static void main(String[] args) {
+		final Display display = Display.getDefault();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				try {
+					Snippet024SelectObservableValue window = new Snippet024SelectObservableValue();
+					window.open();
+				} catch (Exception e) {
+					e.printStackTrace();
+				}
+			}
+		});
+	}
+
+	public void open() {
+		final Display display = Display.getDefault();
+		createContents();
+		shell.open();
+		shell.layout();
+		while (!shell.isDisposed()) {
+			if (!display.readAndDispatch())
+				display.sleep();
+		}
+	}
+
+	protected void createContents() {
+		shell = new Shell();
+		shell.setSize(400, 300);
+		shell.setLayout(new GridLayout(2, true));
+		shell.setText("Snippet024SelectObservableValue");
+
+		final ListViewer listViewer = new ListViewer(shell, SWT.BORDER);
+		listViewer.setContentProvider(new ArrayContentProvider());
+		listViewer.getList().setLayoutData(
+				new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		final Group group = new Group(shell, SWT.NONE);
+		group.setText("Radio Group");
+		group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+		group.setLayout(new GridLayout());
+
+		// Data Binding
+		Color[] colors = Color.values();
+
+		listViewer.setInput(colors);
+		IViewerObservableValue listViewerSelection = ViewersObservables
+				.observeSingleSelection(listViewer);
+
+		SelectObservableValue radioGroup = new SelectObservableValue();
+		for (int i = 0; i < colors.length; i++) {
+			Button button = new Button(group, SWT.RADIO);
+			button.setText(colors[i].toString());
+			radioGroup.addOption(colors[i], SWTObservables
+					.observeSelection(button));
+		}
+
+		DataBindingContext dbc = new DataBindingContext();
+		dbc.bindValue(radioGroup, listViewerSelection);
+	}
+
+	public static class Color {
+		public static final Color RED = new Color("Red");
+		public static final Color ORANGE = new Color("Orange");
+		public static final Color YELLOW = new Color("Yellow");
+		public static final Color GREEN = new Color("Green");
+		public static final Color BLUE = new Color("Blue");
+		public static final Color INDIGO = new Color("Indigo");
+		public static final Color VIOLET = new Color("Violet");
+
+		private final String name;
+
+		private Color(String name) {
+			this.name = name;
+		}
+
+		public String toString() {
+			return name;
+		}
+
+		public static Color[] values() {
+			return new Color[] { RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO,
+					VIOLET };
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet025TableViewerWithPropertyDerivedColumns.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,272 @@
+/*******************************************************************************
+ * Copyright (c) 2006 The Pampered Chef, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Coconut Palm Software, Inc. - Initial API and implementation
+ *     Matthew Hall - bug 195222, 261843, 260337
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeanProperties;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.databinding.observable.list.WritableList;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.swt.WidgetProperties;
+import org.eclipse.jface.databinding.viewers.ViewerSupport;
+import org.eclipse.jface.databinding.viewers.ViewerProperties;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Combo;
+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.TableColumn;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Demonstrates binding a TableViewer to a collection.
+ */
+public class Snippet025TableViewerWithPropertyDerivedColumns {
+	public static void main(String[] args) {
+		final Display display = new Display();
+
+		// 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, wrapping your binding
+		// method call.
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				ViewModel viewModel = new ViewModel();
+				Shell shell = new View(viewModel).createShell();
+
+				// The SWT event loop
+				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);
+		}
+	}
+
+	private static Person UNKNOWN = new Person("unknown", null, null);
+
+	// The data model class. This is normally a persistent class of some sort.
+	static class Person extends AbstractModelObject {
+		// A property...
+		String name = "Donald Duck";
+		Person mother;
+		Person father;
+
+		public Person(String name, Person mother, Person father) {
+			this.name = name;
+			this.mother = mother;
+			this.father = father;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			firePropertyChange("name", this.name, this.name = name);
+		}
+
+		public Person getMother() {
+			return mother;
+		}
+
+		public void setMother(Person mother) {
+			firePropertyChange("mother", this.mother, this.mother = mother);
+		}
+
+		public Person getFather() {
+			return father;
+		}
+
+		public void setFather(Person father) {
+			firePropertyChange("father", this.father, this.father = father);
+		}
+	}
+
+	// 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 IObservableList people = new WritableList();
+		{
+			Person fergus = new Person("Fergus McDuck", UNKNOWN, UNKNOWN);
+			Person downy = new Person("Downy O'Drake", UNKNOWN, UNKNOWN);
+			Person scrooge = new Person("Scrooge McDuck", downy, fergus);
+			Person hortense = new Person("Hortense McDuck", downy, fergus);
+			Person quackmore = new Person("Quackmore Duck", UNKNOWN, UNKNOWN);
+			Person della = new Person("Della Duck", hortense, quackmore);
+			Person donald = new Person("Donald Duck", hortense, quackmore);
+			people.add(UNKNOWN);
+			people.add(downy);
+			people.add(fergus);
+			people.add(scrooge);
+			people.add(quackmore);
+			people.add(hortense);
+			people.add(della);
+			people.add(donald);
+		}
+
+		public IObservableList getPeople() {
+			return people;
+		}
+	}
+
+	// The GUI view
+	static class View {
+		private ViewModel viewModel;
+		private Table duckFamily;
+		private Text nameText;
+		private Combo motherCombo;
+		private Combo fatherCombo;
+
+		public View(ViewModel viewModel) {
+			this.viewModel = viewModel;
+		}
+
+		public Shell createShell() {
+			// Build a UI
+			Display display = Display.getDefault();
+			Shell shell = new Shell(display);
+			duckFamily = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
+			duckFamily.setHeaderVisible(true);
+			GridDataFactory.defaultsFor(duckFamily).span(2, 1).applyTo(
+					duckFamily);
+			createColumn("Name");
+			createColumn("Mother");
+			createColumn("Father");
+			createColumn("Maternal Grandmother");
+			createColumn("Maternal Grandfather");
+			createColumn("Paternal Grandmother");
+			createColumn("Paternal Grandfather");
+
+			duckFamily.setLinesVisible(true);
+
+			new Label(shell, SWT.NONE).setText("Name:");
+			nameText = new Text(shell, SWT.BORDER);
+			GridDataFactory.defaultsFor(nameText).grab(true, false).applyTo(
+					nameText);
+
+			new Label(shell, SWT.NONE).setText("Mother:");
+			motherCombo = new Combo(shell, SWT.READ_ONLY);
+
+			new Label(shell, SWT.NONE).setText("Father:");
+			fatherCombo = new Combo(shell, SWT.READ_ONLY);
+
+			DataBindingContext bindingContext = new DataBindingContext();
+			bindGUI(bindingContext);
+
+			GridLayoutFactory.swtDefaults().numColumns(2).applyTo(shell);
+			// Open and return the Shell
+			shell.setSize(800, 300);
+			shell.open();
+			return shell;
+		}
+
+		private void createColumn(String string) {
+			final TableColumn column = new TableColumn(duckFamily, SWT.NONE);
+			column.setText(string);
+			column.pack();
+			if (column.getWidth() < 100)
+				column.setWidth(100);
+		}
+
+		protected void bindGUI(DataBindingContext dbc) {
+			// Since we're using a JFace Viewer, we do first wrap our Table...
+			TableViewer peopleViewer = new TableViewer(duckFamily);
+			peopleViewer.addFilter(new ViewerFilter() {
+				public boolean select(Viewer viewer, Object parentElement,
+						Object element) {
+					return element != UNKNOWN;
+				}
+			});
+
+			ViewerSupport.bind(peopleViewer, viewModel.getPeople(),
+					BeanProperties.values(Person.class, new String[] { "name",
+							"mother.name", "father.name", "mother.mother.name",
+							"mother.father.name", "father.mother.name",
+							"father.father.name" }));
+
+			IObservableValue masterSelection = ViewerProperties
+					.singleSelection().observe(peopleViewer);
+
+			dbc.bindValue(WidgetProperties.text(SWT.Modify).observe(nameText),
+					BeanProperties.value(Person.class, "name").observeDetail(
+							masterSelection));
+
+			ComboViewer mothercomboViewer = new ComboViewer(motherCombo);
+			ViewerSupport.bind(mothercomboViewer, viewModel.getPeople(),
+					BeanProperties.value(Person.class, "name"));
+
+			dbc.bindValue(ViewerProperties.singleSelection().observe(
+					mothercomboViewer), BeanProperties.value(Person.class,
+					"mother").observeDetail(masterSelection));
+
+			ComboViewer fatherComboViewer = new ComboViewer(fatherCombo);
+			ViewerSupport.bind(fatherComboViewer, viewModel.getPeople(),
+					BeanProperties.value(Person.class, "name"));
+
+			dbc.bindValue(ViewerProperties.singleSelection().observe(
+					fatherComboViewer), BeanProperties.value(Person.class,
+					"father").observeDetail(masterSelection));
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet026AnonymousBeanProperties.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,400 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Matthew Hall and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Matthew Hall - initial API and implementation (bug 247997)
+ *     Matthew Hall - bugs 261843, 260337, 265561
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeanProperties;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.set.SetDiff;
+import org.eclipse.core.databinding.observable.value.ComputedValue;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.property.INativePropertyListener;
+import org.eclipse.core.databinding.property.IProperty;
+import org.eclipse.core.databinding.property.ISimplePropertyListener;
+import org.eclipse.core.databinding.property.NativePropertyListener;
+import org.eclipse.core.databinding.property.set.DelegatingSetProperty;
+import org.eclipse.core.databinding.property.set.ISetProperty;
+import org.eclipse.core.databinding.property.set.SimpleSetProperty;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.swt.WidgetProperties;
+import org.eclipse.jface.databinding.viewers.ViewerProperties;
+import org.eclipse.jface.databinding.viewers.ViewerSupport;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+
+/**
+ * @since 3.2
+ * 
+ */
+public class Snippet026AnonymousBeanProperties {
+	private ComboViewer statusViewer;
+	private Combo combo;
+	private Text nameText;
+	private TreeViewer contactViewer;
+
+	public static void main(String[] args) {
+		Display display = new Display();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				try {
+					Snippet026AnonymousBeanProperties window = new Snippet026AnonymousBeanProperties();
+					window.open();
+				} catch (Exception e) {
+					e.printStackTrace();
+				}
+			}
+		});
+	}
+
+	private ApplicationModel model;
+	private Shell shell;
+	private Tree tree;
+
+	// 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);
+		}
+	}
+
+	public static class ContactGroup extends AbstractModelObject implements
+			Comparable {
+		private String name;
+		private Set contacts = new TreeSet();
+
+		ContactGroup(String name) {
+			this.name = checkNull(name);
+		}
+
+		private String checkNull(String string) {
+			if (string == null)
+				throw new NullPointerException();
+			return string;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			firePropertyChange("name", this.name, this.name = checkNull(name));
+		}
+
+		public Set getContacts() {
+			return new TreeSet(contacts);
+		}
+
+		public void addContact(Contact contact) {
+			Set oldValue = getContacts();
+			contacts.add(contact);
+			Set newValue = getContacts();
+			firePropertyChange("contacts", oldValue, newValue);
+		}
+
+		public void removeContact(Contact contact) {
+			Set oldValue = getContacts();
+			contacts.remove(contact);
+			Set newValue = getContacts();
+			firePropertyChange("contacts", oldValue, newValue);
+		}
+
+		public int compareTo(Object o) {
+			ContactGroup that = (ContactGroup) o;
+			return this.name.compareTo(that.name);
+		}
+	}
+
+	public static class Contact extends AbstractModelObject implements
+			Comparable {
+		private String name;
+		private String status;
+
+		private String checkNull(String string) {
+			if (string == null)
+				throw new NullPointerException();
+			return string;
+		}
+
+		public Contact(String name, String status) {
+			this.name = checkNull(name);
+			this.status = checkNull(status);
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			firePropertyChange("name", this.name, this.name = checkNull(name));
+		}
+
+		public String getStatus() {
+			return status;
+		}
+
+		public void setStatus(String status) {
+			firePropertyChange("status", this.status,
+					this.status = checkNull(status));
+		}
+
+		public int compareTo(Object o) {
+			Contact that = (Contact) o;
+			int result = this.name.compareTo(that.name);
+			if (result == 0)
+				result = this.status.compareTo(that.status);
+			return result;
+		}
+	}
+
+	public static class ApplicationModel extends AbstractModelObject {
+		private Set groups = new TreeSet();
+
+		public Set getGroups() {
+			return new TreeSet(groups);
+		}
+
+		public void setGroups(Set groups) {
+			Set oldValue = getGroups();
+			this.groups = new TreeSet(groups);
+			Set newValue = getGroups();
+			firePropertyChange("groups", oldValue, newValue);
+		}
+	}
+
+	/**
+	 * Set property for the "contacts" property of a ContactGroup. Since
+	 * ContactGroup does not have a setContacts() method we have to write our
+	 * own property to apply set changes incrementally through the addContact
+	 * and removeContact methods.
+	 */
+	public static class ContactGroupContactsProperty extends SimpleSetProperty {
+		public Object getElementType() {
+			return Contact.class;
+		}
+
+		protected Set doGetSet(Object source) {
+			if (source == null)
+				return Collections.EMPTY_SET;
+			return ((ContactGroup) source).getContacts();
+		}
+
+		protected void doSetSet(Object source, Set set, SetDiff diff) {
+			ContactGroup group = (ContactGroup) source;
+			for (Iterator it = diff.getRemovals().iterator(); it.hasNext();) {
+				Contact contact = (Contact) it.next();
+				group.removeContact(contact);
+			}
+			for (Iterator it = diff.getAdditions().iterator(); it.hasNext();) {
+				Contact contact = (Contact) it.next();
+				group.addContact(contact);
+			}
+		}
+
+		public INativePropertyListener adaptListener(
+				final ISimplePropertyListener listener) {
+			return new Listener(this, listener);
+		}
+
+		private class Listener extends NativePropertyListener implements
+				PropertyChangeListener {
+			Listener(IProperty property, ISimplePropertyListener listener) {
+				super(property, listener);
+			}
+
+			public void propertyChange(PropertyChangeEvent evt) {
+				fireChange(evt.getSource(), null);
+			}
+
+			protected void doAddTo(Object source) {
+				((ContactGroup) source).addPropertyChangeListener("contacts",
+						this);
+			}
+
+			protected void doRemoveFrom(Object source) {
+				((ContactGroup) source).removePropertyChangeListener(
+						"contacts", this);
+			}
+		}
+	}
+
+	public void open() {
+		model = createDefaultModel();
+
+		final Display display = Display.getDefault();
+		createContents();
+		bindUI();
+		shell.open();
+		shell.layout();
+		while (!shell.isDisposed()) {
+			if (!display.readAndDispatch())
+				display.sleep();
+		}
+	}
+
+	private static final String[] statuses = new String[] { "Online", "Idle",
+			"Busy", "Offline" };
+
+	/**
+	 * @return
+	 */
+	private ApplicationModel createDefaultModel() {
+		ContactGroup swtGroup = new ContactGroup("SWT");
+		swtGroup.addContact(new Contact("Steve Northover", "Busy"));
+		swtGroup.addContact(new Contact("Grant Gayed", "Online"));
+		swtGroup.addContact(new Contact("Veronika Irvine", "Offline"));
+		swtGroup.addContact(new Contact("Mike Wilson", "Online"));
+		swtGroup.addContact(new Contact("Christophe Cornu", "Idle"));
+		swtGroup.addContact(new Contact("Lynne Kues", "Online"));
+		swtGroup.addContact(new Contact("Silenio Quarti", "Idle"));
+
+		ContactGroup jdbGroup = new ContactGroup("JFace Data Binding");
+		jdbGroup.addContact(new Contact("Boris Bokowski", "Online"));
+		jdbGroup.addContact(new Contact("Matthew Hall", "Idle"));
+
+		Set groups = new TreeSet();
+		groups.add(swtGroup);
+		groups.add(jdbGroup);
+		ApplicationModel model = new ApplicationModel();
+		model.setGroups(groups);
+
+		return model;
+	}
+
+	/**
+	 * Create contents of the window
+	 */
+	protected void createContents() {
+		shell = new Shell();
+		shell.setSize(379, 393);
+		shell.setText("Snippet026AnonymousBeanProperties");
+		final GridLayout gridLayout = new GridLayout();
+		gridLayout.numColumns = 4;
+		shell.setLayout(gridLayout);
+
+		contactViewer = new TreeViewer(shell, SWT.BORDER);
+		tree = contactViewer.getTree();
+		tree.setHeaderVisible(true);
+		tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1));
+
+		final TreeColumn nameColumn = new TreeColumn(tree, SWT.NONE);
+		nameColumn.setWidth(163);
+		nameColumn.setText("Name");
+
+		final TreeColumn newColumnTreeColumn = new TreeColumn(tree, SWT.NONE);
+		newColumnTreeColumn.setWidth(100);
+		newColumnTreeColumn.setText("Status");
+
+		final Label nameLabel = new Label(shell, SWT.NONE);
+		nameLabel.setText("Name");
+
+		nameText = new Text(shell, SWT.BORDER);
+		final GridData gd_nameText = new GridData(SWT.FILL, SWT.CENTER, true,
+				false);
+		nameText.setLayoutData(gd_nameText);
+
+		final Label statusLabel = new Label(shell, SWT.NONE);
+		statusLabel.setLayoutData(new GridData());
+		statusLabel.setText("Status");
+
+		statusViewer = new ComboViewer(shell, SWT.READ_ONLY);
+		combo = statusViewer.getCombo();
+		combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+	}
+
+	private void bindUI() {
+		ISetProperty treeChildrenProperty = new DelegatingSetProperty() {
+			ISetProperty modelGroups = BeanProperties.set(
+					ApplicationModel.class, "groups");
+			ISetProperty groupContacts = BeanProperties.set(ContactGroup.class,
+					"contacts");
+
+			protected ISetProperty doGetDelegate(Object source) {
+				if (source instanceof ApplicationModel)
+					return modelGroups;
+				if (source instanceof ContactGroup)
+					return groupContacts;
+				return null;
+			}
+		};
+
+		ViewerSupport.bind(contactViewer, model, treeChildrenProperty,
+				BeanProperties.values(new String[] { "name", "status" }));
+
+		contactViewer.expandAll();
+
+		final IObservableValue selection = ViewerProperties.singleSelection()
+				.observe(contactViewer);
+
+		DataBindingContext dbc = new DataBindingContext();
+
+		dbc.bindValue(WidgetProperties.text(SWT.Modify).observe(nameText),
+				BeanProperties.value("name").observeDetail(selection));
+
+		statusViewer.setContentProvider(new ArrayContentProvider());
+		statusViewer.setInput(statuses);
+
+		dbc.bindValue(ViewerProperties.singleSelection().observe(statusViewer),
+				BeanProperties.value("status").observeDetail(selection));
+
+		dbc.bindValue(WidgetProperties.enabled().observe(
+				statusViewer.getControl()), new ComputedValue() {
+			protected Object calculate() {
+				return Boolean.valueOf(selection.getValue() instanceof Contact);
+			}
+		});
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet027ExternalValidator.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,262 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2009 Code 9 Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Chris Aniszczyk <zx@code9.com> - initial API and implementation
+ *     Boris Bokowski, IBM - minor changes
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeansObservables;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.validation.MultiValidator;
+import org.eclipse.core.databinding.validation.ValidationStatus;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.wizard.WizardPageSupport;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * This snippet demonstrates how to integrate an external validator
+ * 
+ * @since 3.5
+ */
+public class Snippet027ExternalValidator extends WizardPage {
+
+	private Text nameValue;
+	private Text emailValue;
+	private Text phoneNumberValue;
+
+	private Contact contact;
+
+	// 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);
+		}
+	}
+
+	static class Contact extends AbstractModelObject {
+		String name;
+		String email;
+		String phoneNumber;
+
+		public Contact(String name, String email, String number) {
+			this.name = name;
+			this.email = email;
+			this.phoneNumber = number;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			String oldValue = this.name;
+			this.name = name;
+			firePropertyChange("name", oldValue, name);
+		}
+
+		public String getEmail() {
+			return email;
+		}
+
+		public void setEmail(String email) {
+			String oldValue = this.email;
+			this.email = email;
+			firePropertyChange("email", oldValue, email);
+		}
+
+		public String getPhoneNumber() {
+			return phoneNumber;
+		}
+
+		public void setPhoneNumber(String number) {
+			String oldValue = this.phoneNumber;
+			this.phoneNumber = number;
+			firePropertyChange("phoneNumber", oldValue, number);
+		}
+
+		public IStatus validate() {
+			if (name.indexOf(' ') == -1) {
+				return ValidationStatus
+						.error("Please enter both first and last name separated by a space.");
+			}
+			if (email.indexOf('@') == -1) {
+				return ValidationStatus
+				.error("Please enter a valid email address containing '@'.");
+			}
+			if (!phoneNumber.startsWith("+")) {
+				return ValidationStatus
+				.error("Please enter the phone number in international format starting with '+'.");
+			}
+			return Status.OK_STATUS;
+		}
+
+	}
+
+	/**
+	 * Create the wizard
+	 */
+	public Snippet027ExternalValidator() {
+		super("snippet024");
+		setTitle("Snippet 024 - External Validation");
+		setDescription("Please enter contact details.");
+	}
+
+	/**
+	 * Create contents of the wizard
+	 * 
+	 * @param parent
+	 */
+	public void createControl(Composite parent) {
+		Composite container = new Composite(parent, SWT.NULL);
+		final GridLayout gridLayout = new GridLayout();
+		gridLayout.numColumns = 2;
+		container.setLayout(gridLayout);
+		setControl(container);
+
+		final Label nameLabel = new Label(container, SWT.NONE);
+		nameLabel.setText("Name");
+
+		nameValue = new Text(container, SWT.BORDER);
+		final GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		nameValue.setLayoutData(gd);
+
+		final Label emailLabel = new Label(container, SWT.NONE);
+		emailLabel.setText("Email");
+
+		emailValue = new Text(container, SWT.BORDER);
+		emailValue.setLayoutData(gd);
+
+		final Label phoneLabel = new Label(container, SWT.NONE);
+		phoneLabel.setText("Phone");
+
+		phoneNumberValue = new Text(container, SWT.BORDER);
+		phoneNumberValue.setLayoutData(gd);
+
+		contact = new Contact("BorisBokowski", "boris.at.somecompany.com",
+				"1-123-456-7890");
+
+		bindUI();
+	}
+
+	private void bindUI() {
+		DataBindingContext dbc = new DataBindingContext();
+
+		final IObservableValue name = BeansObservables.observeValue(contact,
+				"name");
+		dbc.bindValue(SWTObservables.observeText(nameValue, SWT.Modify), name,
+				null, null);
+
+		final IObservableValue email = BeansObservables.observeValue(contact,
+				"email");
+		dbc.bindValue(SWTObservables.observeText(emailValue, SWT.Modify),
+				email, null, null);
+
+		final IObservableValue phone = BeansObservables.observeValue(contact,
+				"phoneNumber");
+		dbc.bindValue(SWTObservables.observeText(phoneNumberValue, SWT.Modify),
+				phone, null, null);
+
+		MultiValidator validator = new MultiValidator() {
+			protected IStatus validate() {
+
+				// Everything accessed here will trigger re-validation.
+				name.getValue();
+				email.getValue();
+				phone.getValue();
+
+				System.out.println("Validating...");
+
+				return contact.validate();
+			}
+		};
+		dbc.addValidationStatusProvider(validator);
+
+		WizardPageSupport.create(this, dbc);
+	}
+
+	static class ExternalValidationWizard extends Wizard {
+		public void addPages() {
+			addPage(new Snippet027ExternalValidator());
+		}
+
+		public String getWindowTitle() {
+			return "Snippet 024 - External Validation";
+		}
+
+		public boolean performFinish() {
+			return true;
+		}
+	}
+
+	public static void main(String[] args) {
+		Display display = new Display();
+
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				IWizard wizard = new ExternalValidationWizard();
+				WizardDialog dialog = new WizardDialog(null, wizard);
+				dialog.open();
+
+				// The SWT event loop
+				Display display = Display.getCurrent();
+				while (dialog.getShell() != null
+						&& !dialog.getShell().isDisposed()) {
+					if (!display.readAndDispatch()) {
+						display.sleep();
+					}
+				}
+			}
+		});
+
+		display.dispose();
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet028DuplexingObservableValue.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,297 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Matthew Hall and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Matthew Hall - initial API and implementation (bug 175735)
+ *     Matthew Hall - bugs 262407, 260337
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeanProperties;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.databinding.observable.list.WritableList;
+import org.eclipse.core.databinding.observable.value.DuplexingObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.swt.WidgetProperties;
+import org.eclipse.jface.databinding.viewers.ViewerSupport;
+import org.eclipse.jface.databinding.viewers.ViewerProperties;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+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.TableColumn;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * @since 3.2
+ * 
+ */
+public class Snippet028DuplexingObservableValue {
+	protected Shell shell;
+	private TableViewer viewer;
+	private Table table;
+	private Text releaseDate;
+	private Text title;
+	private Text director;
+	private Text writer;
+
+	/**
+	 * Launch the application
+	 * 
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		try {
+			Snippet028DuplexingObservableValue window = new Snippet028DuplexingObservableValue();
+			window.open();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Open the window
+	 */
+	public void open() {
+		final Display display = Display.getDefault();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				createContents();
+				shell.open();
+				shell.layout();
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch())
+						display.sleep();
+				}
+			}
+		});
+	}
+
+	protected void createContents() {
+		shell = new Shell();
+		shell.setSize(509, 375);
+		shell.setText("Snippet028DuplexingObservableValue.java");
+		final GridLayout gridLayout = new GridLayout();
+		gridLayout.makeColumnsEqualWidth = true;
+		gridLayout.numColumns = 4;
+		shell.setLayout(gridLayout);
+
+		viewer = new TableViewer(shell, SWT.FULL_SELECTION | SWT.MULTI
+				| SWT.BORDER);
+		table = viewer.getTable();
+		table.setLinesVisible(true);
+		table.setHeaderVisible(true);
+		table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1));
+
+		final TableColumn newColumnTableColumn_1 = new TableColumn(table,
+				SWT.NONE);
+		newColumnTableColumn_1.setWidth(120);
+		newColumnTableColumn_1.setText("Movie");
+
+		final TableColumn newColumnTableColumn = new TableColumn(table,
+				SWT.NONE);
+
+		newColumnTableColumn.setWidth(120);
+		newColumnTableColumn.setText("Release Date");
+
+		final TableColumn newColumnTableColumn_2 = new TableColumn(table,
+				SWT.NONE);
+		newColumnTableColumn_2.setWidth(120);
+		newColumnTableColumn_2.setText("Director");
+
+		final TableColumn newColumnTableColumn_3 = new TableColumn(table,
+				SWT.NONE);
+		newColumnTableColumn_3.setWidth(120);
+		newColumnTableColumn_3.setText("Writer");
+
+		final Label movieLabel = new Label(shell, SWT.NONE);
+		movieLabel.setText("Movie");
+
+		final Label directorLabel = new Label(shell, SWT.NONE);
+		directorLabel.setLayoutData(new GridData());
+		directorLabel.setText("Release Date");
+
+		final Label producerLabel = new Label(shell, SWT.NONE);
+		producerLabel.setText("Director");
+
+		final Label scoreLabel = new Label(shell, SWT.NONE);
+		scoreLabel.setText("Writer");
+
+		title = new Text(shell, SWT.BORDER);
+		final GridData gd_title = new GridData(SWT.FILL, SWT.CENTER, true,
+				false);
+		title.setLayoutData(gd_title);
+
+		releaseDate = new Text(shell, SWT.BORDER);
+		final GridData gd_releaseDate = new GridData(SWT.FILL, SWT.CENTER,
+				true, false);
+		releaseDate.setLayoutData(gd_releaseDate);
+
+		director = new Text(shell, SWT.BORDER);
+		final GridData gd_director = new GridData(SWT.FILL, SWT.CENTER, true,
+				false);
+		director.setLayoutData(gd_director);
+
+		writer = new Text(shell, SWT.BORDER);
+		final GridData gd_writer = new GridData(SWT.FILL, SWT.CENTER, true,
+				false);
+		writer.setLayoutData(gd_writer);
+
+		bindUI();
+	}
+
+	// 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);
+		}
+	}
+
+	public static class MovieInfo extends AbstractModelObject {
+		private String title;
+		private String releaseDate;
+		private String director;
+		private String writer;
+
+		public MovieInfo(String title, String releaseDate, String director,
+				String writer) {
+			this.title = title;
+			this.releaseDate = releaseDate;
+			this.director = director;
+			this.writer = writer;
+		}
+
+		public String getTitle() {
+			return title;
+		}
+
+		public void setTitle(String title) {
+			firePropertyChange("title", this.title, this.title = title);
+		}
+
+		public String getReleaseDate() {
+			return releaseDate;
+		}
+
+		public void setReleaseDate(String releaseDate) {
+			firePropertyChange("releaseDate", this.releaseDate,
+					this.releaseDate = releaseDate);
+		}
+
+		public String getDirector() {
+			return director;
+		}
+
+		public void setDirector(String director) {
+			firePropertyChange("director", this.director,
+					this.director = director);
+		}
+
+		public String getWriter() {
+			return writer;
+		}
+
+		public void setWriter(String writer) {
+			firePropertyChange("writer", this.writer, this.writer = writer);
+		}
+	}
+
+	private void bindUI() {
+		IObservableList movies = new WritableList();
+		movies.add(new MovieInfo("007: Quantum of Solace", "October 31, 2008",
+				"Marc Forster", "Robert Wade"));
+		movies.add(new MovieInfo("Batman Begins", "June 15, 2005",
+				"Christopher Nolan", "David S. Goyer"));
+		movies.add(new MovieInfo("Cloverfield", "January 18, 2008",
+				"Matt Reeves", "Drew Goddard"));
+		movies.add(new MovieInfo("The Dark Knight", "July 18, 2008",
+				"Christopher Nolan", "David S. Goyer"));
+		movies.add(new MovieInfo("Finding Nemo", "May 30, 2003",
+				"Andrew Stanton", "Andrew Stanton"));
+		movies.add(new MovieInfo("Get Smart", "June 20, 2008", "Peter Segal",
+				"Tom J. Astle"));
+		movies.add(new MovieInfo(
+				"Indiana Jones and the Kingdom of the Crystal Skull",
+				"May 22, 2008", "Steven Spielberg", "Drunken Lemurs"));
+		movies.add(new MovieInfo("Iron Man", "May 2, 2008", "Jon Favreau",
+				"Mark Fergus"));
+		movies.add(new MovieInfo("Raiders of the Lost Ark", "June 12, 1981",
+				"Steven Spielberg", "George Lucas"));
+		movies.add(new MovieInfo("Valkyrie", "December 25, 2008",
+				"Bryan Singer", "Christopher McQuarrie"));
+		movies.add(new MovieInfo("Wall-E", "June 27, 2008", "Andrew Stanton",
+				"Andrew Stanton"));
+		movies.add(new MovieInfo("Wanted", "June 27, 2008",
+				"Timur Bekmambetov", "Michael Brandt"));
+
+		ViewerSupport.bind(viewer, movies, BeanProperties.values(
+				MovieInfo.class, new String[] { "title", "releaseDate",
+						"director", "writer" }));
+
+		// Select Batman Begins and The Dark Knight, which have the same
+		// director and writer
+		viewer.setSelection(new StructuredSelection(new Object[] {
+				movies.get(1), movies.get(3) }));
+
+		DataBindingContext dbc = new DataBindingContext();
+
+		IObservableList selections = ViewerProperties.multipleSelection()
+				.observe(viewer);
+		dbc.bindValue(WidgetProperties.text(SWT.Modify).observe(title),
+				DuplexingObservableValue.withDefaults(BeanProperties.value(
+						"title").observeDetail(selections), "",
+						"<Multiple titles>"));
+		dbc.bindValue(WidgetProperties.text(SWT.Modify).observe(releaseDate),
+				DuplexingObservableValue.withDefaults(BeanProperties.value(
+						"releaseDate").observeDetail(selections), "",
+						"<Multiple dates>"));
+		dbc.bindValue(WidgetProperties.text(SWT.Modify).observe(director),
+				DuplexingObservableValue.withDefaults(BeanProperties.value(
+						"director").observeDetail(selections), "",
+						"<Multiple directors>"));
+		dbc.bindValue(WidgetProperties.text(SWT.Modify).observe(writer),
+				DuplexingObservableValue.withDefaults(BeanProperties.value(
+						"writer").observeDetail(selections), "",
+						"<Multiple writers>"));
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet029TreeViewerMultiListProperty.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,257 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Matthew Hall and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Matthew Hall - initial API and implementation (bug 175735)
+ *     Matthew Hall - bugs 262407, 260337
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.databinding.beans.BeanProperties;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.property.list.IListProperty;
+import org.eclipse.core.databinding.property.list.MultiListProperty;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.viewers.ObservableListTreeContentProvider;
+import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * @since 3.2
+ * 
+ */
+public class Snippet029TreeViewerMultiListProperty {
+	protected Shell shell;
+	private TreeViewer viewer;
+
+	/**
+	 * Launch the application
+	 * 
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		try {
+			Snippet029TreeViewerMultiListProperty window = new Snippet029TreeViewerMultiListProperty();
+			window.open();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Open the window
+	 */
+	public void open() {
+		final Display display = Display.getDefault();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				createContents();
+				shell.open();
+				shell.layout();
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch())
+						display.sleep();
+				}
+			}
+		});
+	}
+
+	protected void createContents() {
+		shell = new Shell();
+		shell.setSize(509, 375);
+		shell.setText("Snippet028DuplexingObservableValue.java");
+		final GridLayout gridLayout = new GridLayout();
+		gridLayout.makeColumnsEqualWidth = true;
+		gridLayout.numColumns = 4;
+		shell.setLayout(new FillLayout());
+
+		viewer = new TreeViewer(shell, SWT.FULL_SELECTION | SWT.MULTI
+				| SWT.BORDER);
+
+		bindUI();
+	}
+
+	// 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);
+		}
+	}
+
+	public static class Catalog extends AbstractModelObject {
+		private String name;
+		private List catalogs = new ArrayList();
+		private List items = new ArrayList();
+
+		public Catalog(String name) {
+			this.name = name;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			firePropertyChange("name", this.name, this.name = name);
+		}
+
+		public List getCatalogs() {
+			return catalogs;
+		}
+
+		public void setCatalogs(List catalogs) {
+			firePropertyChange("catalogs", this.catalogs,
+					this.catalogs = catalogs);
+		}
+
+		public List getItems() {
+			return items;
+		}
+
+		public void setItems(List items) {
+			firePropertyChange("items", this.items, this.items = items);
+		}
+	}
+
+	public static class CatalogItem extends AbstractModelObject {
+		private String name;
+
+		public CatalogItem(String name) {
+			this.name = name;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			firePropertyChange("name", this.name, this.name = name);
+		}
+	}
+
+	private void bindUI() {
+		List items;
+
+		Catalog fruits = new Catalog("Fruits");
+		items = new ArrayList();
+		items.add(new CatalogItem("Apple"));
+		items.add(new CatalogItem("Orange"));
+		fruits.setCatalogs(items);
+
+		Catalog vegetables = new Catalog("Vegetables");
+		items = new ArrayList();
+		items.add(new CatalogItem("Peas"));
+		items.add(new CatalogItem("Carrots"));
+		items.add(new CatalogItem("Potatoes"));
+		vegetables.setItems(items);
+
+		Catalog foods = new Catalog("Foods");
+		items = new ArrayList();
+		items.add(fruits);
+		items.add(vegetables);
+		foods.setCatalogs(items);
+
+		items = new ArrayList();
+		items.add(new CatalogItem("Own Hand"));
+		foods.setItems(items);
+
+		Catalog catalog = new Catalog("Main Catalog");
+		items = new ArrayList();
+		items.add(foods);
+		catalog.setCatalogs(items);
+
+		IListProperty childrenProperty = new MultiListProperty(
+				new IListProperty[] { BeanProperties.list("catalogs"),
+						BeanProperties.list("items") });
+
+		ObservableListTreeContentProvider contentProvider = new ObservableListTreeContentProvider(
+				childrenProperty.listFactory(), null);
+		viewer.setContentProvider(contentProvider);
+
+		ObservableMapLabelProvider labelProvider = new ObservableMapLabelProvider(
+				BeanProperties.value("name").observeDetail(
+						contentProvider.getKnownElements())) {
+			Image catalogImage = createCatalogImage();
+			Image catalogItemImage = createCatalogItemImage();
+
+			public Image getImage(Object element) {
+				if (element instanceof Catalog)
+					return catalogImage;
+				if (element instanceof CatalogItem)
+					return catalogItemImage;
+				return super.getImage(element);
+			}
+
+			public void dispose() {
+				catalogImage.dispose();
+				catalogItemImage.dispose();
+				super.dispose();
+			}
+
+			private Image createCatalogImage() {
+				Display display = Display.getCurrent();
+				Image catalogImage = new Image(display, 12, 12);
+				GC gc = new GC(catalogImage);
+				gc.setBackground(display.getSystemColor(SWT.COLOR_GREEN));
+				gc.fillArc(1, 1, 10, 10, 0, 360);
+				gc.dispose();
+				return catalogImage;
+			}
+
+			private Image createCatalogItemImage() {
+				Display display = Display.getCurrent();
+				Image catalogImage = new Image(display, 12, 12);
+				GC gc = new GC(catalogImage);
+				gc.setBackground(display.getSystemColor(SWT.COLOR_CYAN));
+				gc.fillPolygon(new int[] { 1, 10, 5, 1, 6, 1, 10, 10, 1, 10 });
+				gc.dispose();
+				return catalogImage;
+			}
+		};
+		viewer.setLabelProvider(labelProvider);
+
+		viewer.setInput(catalog);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet030DateAndTimeObservableValue.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Matthew Hall and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Matthew Hall - initial API and implementation (bug 169876)
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.util.Date;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.DateAndTimeObservableValue;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.swt.WidgetProperties;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.DateTime;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * @since 3.2
+ * 
+ */
+public class Snippet030DateAndTimeObservableValue {
+	protected Shell shell;
+	private Text modelText;
+	private DateTime date;
+	private DateTime calendar;
+	private DateTime time;
+	private Button syncTime;
+
+	/**
+	 * Launch the application
+	 * 
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		try {
+			Snippet030DateAndTimeObservableValue window = new Snippet030DateAndTimeObservableValue();
+			window.open();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Open the window
+	 */
+	public void open() {
+		final Display display = Display.getDefault();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				createContents();
+				shell.pack();
+				shell.open();
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch())
+						display.sleep();
+				}
+			}
+		});
+	}
+
+	protected void createContents() {
+		shell = new Shell();
+		GridLayout layout = new GridLayout();
+		layout.numColumns = 3;
+		shell.setLayout(layout);
+		shell.setText("Snippet030DateAndTimeObservableValue.java");
+
+		new Label(shell, SWT.NONE).setText("Model date + time");
+		modelText = new Text(shell, SWT.BORDER);
+		modelText.setEditable(false);
+		modelText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
+				2, 1));
+
+		new Label(shell, SWT.NONE).setText("Target date (SWT.DATE)");
+		date = new DateTime(shell, SWT.DATE | SWT.BORDER);
+		date.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2,
+				1));
+
+		new Label(shell, SWT.NONE).setText("Target date (SWT.CALENDAR)");
+		calendar = new DateTime(shell, SWT.CALENDAR);
+		calendar.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false,
+				2, 1));
+
+		new Label(shell, SWT.NONE).setText("Target time");
+		time = new DateTime(shell, SWT.TIME | SWT.BORDER);
+
+		syncTime = new Button(shell, SWT.CHECK);
+		syncTime.setLayoutData(new GridData());
+		syncTime.setText("Sync with system time");
+
+		bindUI();
+	}
+
+	private void bindUI() {
+		DataBindingContext dbc = new DataBindingContext();
+
+		IObservableValue model = WritableValue.withValueType(Date.class);
+		model.setValue(new Date());
+
+		dbc.bindValue(WidgetProperties.text().observe(modelText), model);
+
+		final IObservableValue timeSelection = WidgetProperties.selection()
+				.observe(time);
+
+		dbc.bindValue(new DateAndTimeObservableValue(WidgetProperties
+				.selection().observe(date), timeSelection), model);
+		dbc.bindValue(new DateAndTimeObservableValue(WidgetProperties
+				.selection().observe(calendar), timeSelection), model);
+
+		syncTime.addListener(SWT.Selection, new Listener() {
+			Runnable runnable = new Runnable() {
+				public void run() {
+					if (syncTime.getSelection()) {
+						timeSelection.setValue(new Date());
+						Display.getCurrent().timerExec(100, this);
+					}
+				}
+			};
+
+			public void handleEvent(Event event) {
+				time.setEnabled(!syncTime.getSelection());
+				if (syncTime.getSelection()) {
+					runnable.run();
+				}
+			}
+		});
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet031JFaceObservable.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.property.value.IValueProperty;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.util.JFaceProperties;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+public class Snippet031JFaceObservable {
+
+	public static final String NAME_PROPERTY = "name_property";
+
+	public static void main(String[] args) {
+		Display display = new Display();
+		final ViewModel viewModel = new ViewModel();
+
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				final Shell shell = new View(viewModel).createShell();
+				// The SWT event loop
+				Display display = Display.getCurrent();
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch()) {
+						display.sleep();
+					}
+				}
+			}
+		});
+		// Print the results
+		System.out.println("person.getName() = "
+				+ viewModel.getPerson().getName());
+	}
+
+	// The data model class. This is normally a persistent class of some sort.
+	// 
+	// In this example, we extend the EventManager class
+	// to manage our listeners and we fire a property change
+	// event when the object state changes.
+	public static class Person extends EventManager {
+		// A property...
+		String name = "HelloWorld";
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			fireChange(new PropertyChangeEvent(this, NAME_PROPERTY, this.name,
+					this.name = name));
+		}
+
+		public void addPropertyChangeListener(IPropertyChangeListener listener) {
+			addListenerObject(listener);
+		}
+
+		public void removePropertyChangeListener(
+				IPropertyChangeListener listener) {
+			removeListenerObject(listener);
+		}
+
+		private void fireChange(PropertyChangeEvent event) {
+			final Object[] list = getListeners();
+			for (int i = 0; i < list.length; ++i) {
+				((IPropertyChangeListener) list[i]).propertyChange(event);
+			}
+		}
+
+	}
+
+	// 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
+	// DAO. Since this snippet doesn't have any persistent objects to
+	// retrieve, this ViewModel just instantiates a model object to edit.
+	static class ViewModel {
+		// The model to bind
+		private Person person = new Person();
+
+		public Person getPerson() {
+			return person;
+		}
+	}
+
+	// The GUI view
+	static class View {
+		private ViewModel viewModel;
+		private Text name;
+
+		public View(ViewModel viewModel) {
+			this.viewModel = viewModel;
+		}
+
+		public Shell createShell() {
+			// Build a UI
+			Display display = Display.getDefault();
+			Shell shell = new Shell(display);
+			shell.setLayout(new RowLayout(SWT.VERTICAL));
+			name = new Text(shell, SWT.BORDER);
+
+			// Bind it
+			DataBindingContext bindingContext = new DataBindingContext();
+			Person person = viewModel.getPerson();
+
+			IValueProperty nameProperty = JFaceProperties.value(Person.class,
+					"name", NAME_PROPERTY);
+
+			bindingContext.bindValue(SWTObservables.observeText(name,
+					SWT.Modify), nameProperty.observe(person), null, null);
+
+			Label label = new Label(shell, SWT.NONE);
+			bindingContext.bindValue(SWTObservables.observeText(label),
+					nameProperty.observe(person), null, null);
+
+			// Open and return the Shell
+			shell.pack();
+			shell.open();
+			return shell;
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet032TableViewerColumnEditing.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,255 @@
+/*******************************************************************************
+ * Copyright (c) 2006 The Pampered Chef, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     The Pampered Chef, Inc. - initial API and implementation
+ *     Tom Schindl - cell editing
+ *     Matthew Hall - bugs 260329, 260337
+ *     Heiko Ahlig - bug 267712
+ *******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.beans.BeanProperties;
+import org.eclipse.core.databinding.beans.BeansObservables;
+import org.eclipse.core.databinding.beans.IBeanValueProperty;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.WritableList;
+import org.eclipse.core.databinding.observable.map.IObservableMap;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.property.Properties;
+import org.eclipse.core.databinding.property.value.IValueProperty;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.swt.WidgetProperties;
+import org.eclipse.jface.databinding.viewers.CellEditorProperties;
+import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
+import org.eclipse.jface.databinding.viewers.ObservableMapCellLabelProvider;
+import org.eclipse.jface.databinding.viewers.ObservableValueEditingSupport;
+import org.eclipse.jface.databinding.viewers.ViewersObservables;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+
+/**
+ * Demonstrates binding a TableViewer with multiple columns to a collection.
+ */
+public class Snippet032TableViewerColumnEditing {
+	public static void main(String[] args) {
+		final Display display = new Display();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				ViewModel viewModel = new ViewModel();
+				Shell shell = new View(viewModel).createShell();
+
+				// The SWT event loop
+				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;
+		String firstName;
+
+		public Person(String firstName, String name) {
+			this.name = name;
+			this.firstName = firstName;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			firePropertyChange("name", this.name, this.name = name);
+		}
+
+		public String getFirstName() {
+			return firstName;
+		}
+
+		public void setFirstName(String firstName) {
+			firePropertyChange("firstName", this.firstName,
+					this.firstName = firstName);
+		}
+	}
+
+	// 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("Dave", "Orme"));
+			people.add(new Person("Gili", "Mendel"));
+			people.add(new Person("Joe", "Winchester"));
+			people.add(new Person("Boris", "Bokowski"));
+			people.add(new Person("Brad", "Reynolds"));
+			people.add(new Person("Matthew", "Hall"));
+		}
+
+		public List getPeople() {
+			return people;
+		}
+	}
+
+	// The GUI view
+	static class View {
+		private ViewModel viewModel;
+		private Table committers;
+		private Label selectedCommitterName;
+		private Label selectedCommitterFirstName;
+
+		public View(ViewModel viewModel) {
+			this.viewModel = viewModel;
+		}
+
+		public Shell createShell() {
+			// Build a UI
+			Display display = Display.getDefault();
+			Shell shell = new Shell(display);
+			shell.setLayout(new GridLayout(2, true));
+			committers = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
+			committers.setLinesVisible(true);
+			committers.setHeaderVisible(true);
+			GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
+			layoutData.horizontalSpan = 2;
+			committers.setLayoutData(layoutData);
+
+			GridData fieldLayoutData = new GridData(SWT.FILL, SWT.BEGINNING,
+					true, false);
+			selectedCommitterName = new Label(shell, SWT.NONE);
+			selectedCommitterName.setLayoutData(fieldLayoutData);
+
+			selectedCommitterFirstName = new Label(shell, SWT.NONE);
+			selectedCommitterFirstName.setLayoutData(fieldLayoutData);
+
+			DataBindingContext bindingContext = new DataBindingContext();
+			bindGUI(bindingContext);
+
+			// Open and return the Shell
+			shell.setSize(250, 300);
+			shell.open();
+			return shell;
+		}
+
+		protected void bindGUI(DataBindingContext bindingContext) {
+			// Since we're using a JFace Viewer, we do first wrap our Table...
+			TableViewer peopleViewer = new TableViewer(committers);
+
+			TableViewerColumn columnName = new TableViewerColumn(peopleViewer,
+					SWT.NONE);
+			columnName.getColumn().setText("Name");
+			columnName.getColumn().setWidth(100);
+
+			TableViewerColumn columnFirstName = new TableViewerColumn(
+					peopleViewer, SWT.NONE);
+			columnFirstName.getColumn().setText("FirstName");
+			columnFirstName.getColumn().setWidth(100);
+
+			// Bind viewer to model
+			IBeanValueProperty propName = BeanProperties.value(Person.class,
+					"name");
+			IBeanValueProperty propFirstname = BeanProperties.value(
+					Person.class, "firstName");
+
+			IValueProperty cellEditorControlText = CellEditorProperties
+					.control().value(WidgetProperties.text());
+
+			columnName.setEditingSupport(ObservableValueEditingSupport.create(
+					peopleViewer, bindingContext,
+					new TextCellEditor(committers), cellEditorControlText,
+					propName));
+			columnFirstName.setEditingSupport(ObservableValueEditingSupport
+					.create(peopleViewer, bindingContext, new TextCellEditor(
+							committers), cellEditorControlText, propFirstname));
+
+			ObservableListContentProvider contentProvider = new ObservableListContentProvider();
+			peopleViewer.setContentProvider(contentProvider);
+
+			// Bind the LabelProviders to the model and columns
+			IObservableMap[] result = Properties.observeEach(contentProvider
+					.getKnownElements(), new IBeanValueProperty[] { propName,
+					propFirstname });
+
+			columnName.setLabelProvider(new ObservableMapCellLabelProvider(
+					result[0]));
+			columnFirstName
+					.setLabelProvider(new ObservableMapCellLabelProvider(
+							result[1]));
+
+			peopleViewer.setInput(new WritableList(viewModel.getPeople(),
+					Person.class));
+
+			// bind selectedCommitter labels to the name and forname of the
+			// current selection
+			IObservableValue selection = ViewersObservables
+					.observeSingleSelection(peopleViewer);
+			bindingContext.bindValue(SWTObservables
+					.observeText(selectedCommitterName), BeansObservables
+					.observeDetailValue(selection, "name", String.class));
+			bindingContext.bindValue(SWTObservables
+					.observeText(selectedCommitterFirstName), BeansObservables
+					.observeDetailValue(selection, "firstName", String.class));
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet033CrossValidationControlDecoration.d	Sun Apr 19 11:33:55 2009 +0200
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Matthew Hall and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Matthew Hall - initial API and implementation (bug 268472)
+ ******************************************************************************/
+
+package org.eclipse.jface.examples.databinding.snippets;
+
+import java.util.Date;
+
+import org.eclipse.core.databinding.observable.Observables;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.validation.MultiValidator;
+import org.eclipse.core.databinding.validation.ValidationStatus;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.swt.WidgetProperties;
+import org.eclipse.jface.internal.databinding.provisional.fieldassist.ControlDecorationSupport;
+import org.eclipse.jface.internal.databinding.provisional.fieldassist.ControlDecorationUpdater;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DateTime;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * @since 3.2
+ * 
+ */
+public class Snippet033CrossValidationControlDecoration {
+	protected Shell shell;
+	private DateTime startDate;
+	private DateTime endDate;
+
+	/**
+	 * Launch the application
+	 * 
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		try {
+			Snippet033CrossValidationControlDecoration window = new Snippet033CrossValidationControlDecoration();
+			window.open();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Open the window
+	 */
+	public void open() {
+		final Display display = Display.getDefault();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				createContents();
+				shell.pack();
+				shell.open();
+				while (!shell.isDisposed()) {
+					if (!display.readAndDispatch())
+						display.sleep();
+				}
+			}
+		});
+	}
+
+	protected void createContents() {
+		shell = new Shell();
+		GridLayout layout = new GridLayout();
+		layout.numColumns = 4;
+		shell.setLayout(layout);
+		shell.setText("Snippet033CrossValidationControlDecoration.java");
+
+		final Label label = new Label(shell, SWT.NONE);
+		label.setLayoutData(new GridData());
+		label.setText("Start date");
+		startDate = new DateTime(shell, SWT.CALENDAR);
+		final GridData gd_startDate = new GridData();
+		gd_startDate.horizontalIndent = 10;
+		startDate.setLayoutData(gd_startDate);
+
+		final Label startDateLabel = new Label(shell, SWT.NONE);
+		startDateLabel.setLayoutData(new GridData());
+		startDateLabel.setText("End date");
+		endDate = new DateTime(shell, SWT.CALENDAR);
+		final GridData gd_endDate = new GridData();
+		gd_endDate.horizontalIndent = 10;
+		endDate.setLayoutData(gd_endDate);
+
+		bindUI();
+	}
+
+	private void bindUI() {
+		IObservableValue startDateObservable = WidgetProperties.selection()
+				.observe(startDate);
+		IObservableValue endDateObservable = WidgetProperties.selection()
+				.observe(endDate);
+
+		ControlDecorationSupport.create(new DateRangeValidator(
+				startDateObservable, endDateObservable,
+				"Start date must be on or before end date"), SWT.LEFT
+				| SWT.CENTER);
+
+		// Customize the decoration's description text and image
+		ControlDecorationUpdater decorationUpdater = new ControlDecorationUpdater() {
+			protected String getDescriptionText(IStatus status) {
+				return "ERROR: " + super.getDescriptionText(status);
+			}
+
+			protected Image getImage(IStatus status) {
+				return status.isOK() ? null : Display.getCurrent()
+						.getSystemImage(SWT.ICON_ERROR);
+			}
+		};
+		ControlDecorationSupport.create(new DateRangeValidator(Observables
+				.constantObservableValue(new Date()), startDateObservable,
+				"Choose a starting date later than today"), SWT.LEFT | SWT.TOP,
+				(Composite) null, decorationUpdater);
+	}
+
+	private static class DateRangeValidator extends MultiValidator {
+		private final IObservableValue start;
+		private final IObservableValue end;
+		private final String errorMessage;
+
+		public DateRangeValidator(IObservableValue start, IObservableValue end,
+				String errorMessage) {
+			this.start = start;
+			this.end = end;
+			this.errorMessage = errorMessage;
+		}
+
+		protected IStatus validate() {
+			Date startDate = (Date) start.getValue();
+			Date endDate = (Date) end.getValue();
+			if (startDate.compareTo(endDate) > 0)
+				return ValidationStatus.error(errorMessage);
+			return ValidationStatus.ok();
+		}
+	}
+}