Saturday, January 20, 2007

Data Binding Validation Story

In preparation for the 1.0 release the validation story has changed. Previously for a target observable value change the pipeline was:

  1. BindingEvent.PIPELINE_AFTER_GET - retrieve target value

  2. BindingEvent.PIPELINE_AFTER_VALIDATE - validate target value

  3. BindingEvent.PIPELINE_AFTER_CONVERT - convert target value to model type

  4. BindingEvent.PIPELINE_AFTER_BUSINESS_VALIDATE - validate converted value

  5. BindingEvent.PIPELINE_AFTER_CHANGE - set converted value on model



Validation occurred during PIPELINE_AFTER_VALIDATE and PIPELINE_AFTER_BUSINESS_VALIDATE.

The pipeline for value bindings has become:

  1. BindingEvent.PIPELINE_AFTER_GET - retrieve target value

  2. BindingEvent.PIPELINE_AFTER_CONVERT - convert target value

  3. BindingEvent.PIPELINE_BEFORE_CHANGE - a placeholder for expensive validation

  4. BindingEvent.PIPELINE_AFTER_CHANGE - set on model



Validators can now be registered for any position, multiples can be registered for a single position, and validation can occur on model to target changes as well as target to model.

Policies


Policies are the way to define when the model is to be updated. The currently supported policies are BindSpec.POLICY_AUTOMATIC and BindSpec.POLICY_EXPLICIT. A common need in dialogs is the ability to defer updating of a model until the user selects OK/Apply. Previously in order to accomplish this you had to create a temporary model to bind to the UI so that it wouldn't update the live model. Now you can specify BindSpec.POLICY_EXPLICIT for the update policy via the BindSpec and control when the model is updated. You can also specify the target validation policy so that the target is validated on change but the model is not updated until you invoke an explicit update.

There aren't any snippets of the functionality yet but hopefully I'll be able to create one soon. I just wanted to give a heads up for anyone using HEAD as there are some nonpassive changes in this.

Wednesday, January 10, 2007

Master Detail - Distilling the Pattern

Yesterday I went over master detail in the context of list selection. In the list selection post there were 3 steps that were required to setup the list selection master detail. But the guts of master detail were really just the first two, the third was to setup the viewing of the detail.

  1. Observe changes of the viewer's selection.

  2. Observe the name property of the selection.

  3. Bind the text of the Text widget to the name detail (selected person's name).


In the 2 steps we're concerned with we have 3 players:

  1. viewer - maintains a reference to the selection and provides change events when it changes

  2. selection (person)- maintains a reference to the name and provides change events when it changes

  3. name - value to display


If using dot notation we'd be able to access the value of the detail with something like the following (assuming the selection is not null)...
viewer.selection.name

If we genericize the roles a bit we get...
container.master.detail

The Pattern


The master detail APIs will satisfy your use case if...

  1. you need to observe container.master.detail

  2. AND the master instance can be replaced over time



Non Selection Use Case


A use case that arose recently on the newsgroup was how to setup the binding to a Person model that can be replaced over time. This was in the context of implementing presentation model. The following code was being used as the presentation model.
class ViewModel {
private Person person;

public void getPerson() {
return person;
}

public void setPerson(Person person) {
this.person = person;
}
}

Over time a new person would be set and the UI had to update. Expressed in dot notation this was viewModel.person.name. The only change that needed to occur to the code was that ViewModel needed to fire change events for Person and then the binding was wired up like normal.

class ViewModel {
private Person person;
private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);

public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
changeSupport.addPropertyChangeListener(propertyName, listener);
}

public Person getPerson() {
return person;
}

public void setPerson(Person person) {
changeSupport.firePropertyChange("person", this.person, this.person = person);
}
}

// Create an observable to observe changes in the view model
IObservableValue personValue = BeansObservables.observeValue(
viewModel, "person");

//Bind to the name detail of the current person
dbc.bindValue(SWTObservables.observeText(form.getTextName(),
SWT.Modify), BeansObservables.observeDetailValue(Realm
.getDefault(), personValue, "name",
String.class), null);


WritableValue, for those looking for a shortcut


If you're in a position where it doesn't matter if your model is a java bean, look into one of my favorite classes WritableValue. Your code then becomes...

class ViewModel {
/**
* observable value to maintain the person instance
*/
private IObservableValue personObservable = new WritableValue(Person.class);

public IObservableValue getPersonObservable() {
return personObservable;
}
}

//Observe the detail.
IObservableValue detailObservable = BeansObservables
.observeDetailValue(Realm.getDefault(), viewModel.getPersonObservable(), "name",
String.class);

Code to set the person would be...

viewModel.getPersonObservable().setValue(person);

Asking JFace Data Binding questions

Today was the data binding webinar and from what I can tell it went well. There were quite a few questions and I think most if not all got answered. But if you attended or not and have any questions about data binding feel free to ask them on the eclipse.platform newsgroup. You should always be able to find the latest information on how to get in contact with us on the FAQ.

Also in the evenings and on weekends I try to be on IRC on #eclipse and #eclipse-dev. I'm bradleyjames. Feel free to stop by and say hello.

Tuesday, January 09, 2007

Master Detail - Selection

I find myself answering quite a few questions on the newsgroup hinting that the solution is the master detail APIs. I figured that a verbose explanation couldn't hurt the cause. The stereotypical master detail use case contains a list and upon selection in the list details will be displayed in a separate set of widgets. I'll attempt to explain the core concepts involved.

To explain we'll use the master detail snippet available in the data binding examples project. The snippet displays an SWT List filled with Persons. The Person model has one property, name. Upon selection in the List the name of the currently selected person is displayed in a Text widget.



The relevant data binding code is copied and pasted below...
// 1. Observe changes in selection.
IObservableValue selectionObservable = ViewersObservables
.observeSingleSelection(viewer);

// 2. Observe the name property of the current selection.
IObservableValue detailObservable = BeansObservables
.observeDetailValue(Realm.getDefault(), selectionObservable, "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 BindSpec().setUpdateModel(false));


If you follow the comments in the snippet you'll see that we need to perform 3 steps:

  1. Observe changes of the viewer's selection.

  2. Observe the name property of the selection.

  3. Bind the text of the Text widget to the name detail (selected person's name).


1. Observe changes in the viewer's selection


IObservableValue has a value. I know, rocket science. But what IObservableValue provides us is a reference to a transient instance and we can observe changes from one instance to the next. If the selection of the viewer is a person the value of the selection observable will be this person. If the selection is null the value of the selection observable will be null. Regardless of the value we have a reference to an object that will contain the viewer's selection. Change events will fire when a new person, or null, is set as the value of this observable. This is the master.

2. Observe the detail of the master (name of the selected person)


When we observe a detail of the master we're effectively saying...
"observe the value of a property of the value contained in an observable".


Translated into our use case we're saying...
"observe the value of the name property of the person contained in the selection"


If the selection of the the Viewer is a Person with the name "mickey mouse" the following will be true...

  • selectionObservable.getValue() == Person("mickey mouse")

  • detailObservable.getValue() == "mickey mouse"


When the selection changes to a Person with the name of "daffy duck" the following will be true...

  • selectionObservable.getValue() == Person("daffy duck")

  • detailObservable.getValue() == "daffy duck"


When the selection changes to null the following will be true...

  • selectionObservable.getValue() == null

  • detailObservable.getValue() == null


When the master value changes the detail populates itself with the value from the master. This gives us the master detail behavior. To finish it off we need to...

3. Bind the detail to the Text widget


The last step is to bind the detail observable to the Text widget in order to display the detail. Enough said.

Tomorrow night I'll describe a use case that explains how this fits into using JFace Data Binding and the presentation model design pattern.