package fr.lteconsulting.hexa.databinding.gwt;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.ListBox;
import fr.lteconsulting.hexa.classinfo.gwt.ClazzBundle;
import fr.lteconsulting.hexa.databinding.gwt.propertyadapters.ListBoxPropertyAdapter;
import fr.lteconsulting.hexa.databinding.gwt.propertyadapters.ValuePropertyAdapter;
import fr.lteconsulting.hexa.databinding.propertyadapters.CompositePropertyAdapter;
import fr.lteconsulting.hexa.databinding.propertyadapters.ObjectAsValuePropertyAdapter;
import fr.lteconsulting.hexa.databinding.propertyadapters.PropertyAdapter;
/**
* Binder is a class providing a fluent api access to DataBinding.
* <br/>
* By default the data binding is:
* <ul>
* <li>in TwoWays mode,</li>
* <li>without data converter,</li>
* <li>direct activation, - not logged.</li>
* </ul>
* One can create and activate data binding in one line like this :
* <pre>
* // selectedPerson to person form
* Binder.bind(personListBox, "selectedPerson").mode(Mode.OneWay).log("PERSONFORM").to(personForm, "person");
*
* // selected person's category to category form
* Binder.bind(personListBox, "selectedPerson.category").mode(Mode.OneWay).to(categoryForm, "$DTOMap");
*
* // map selectedPerson to a person form
* Binder.bind(personListWidget, "selectedPerson").mapTo(personForm);
*
* // selected person's description to Window's title
* Binder.bind(personListWidget, "selectedPerson.description").mode(Mode.OneWay).to(new WriteOnlyPropertyAdapter())
* </pre>
* The second parameter of the Bind and To methods, which is a String, is the
* path to the desired property. It is '.' separated, so you can compose like
* this : "person.category.creationDate" and the binding tool will automatically
* follow the property's value.
* <br/><br/>
* In order to support the data binding engine, one has also to declare a
* {@link ClazzBundle} interface to process type information of the data-bounded
* classes. Check the samples for further details.
*
* @author Arnaud Tournier
*/
public class Binder
{
/**
* First step, accepts a data binding source definition and creates a binder
*
* The source value is searched as specified in the @param propertyPath, in
* the context of the @param source object.
*
* For example : <i>...To( customer, "company.address.city" )</i> can be
* used to access data at different depths. If all intermediary steps
* provide a correct implementation for the Data Binding mechanism, any
* change at any depth will be catch.
*
* @param source
* The source object
* @param propertyPath
* The source object's property path
* @return The Binder to continue specifying the data binding
*/
public static BindingCreation bind( Object source, String propertyPath )
{
return new BindingCreation( new CompositePropertyAdapter( source, propertyPath ) );
}
/**
* First step, accepts a data binding source definition and creates a binder
*
* This method accepts any implementation of PropertyAdapter, especially
* user ones so that is a good start to customize the data binding
* possibilities.
*
* @return The Binder to continue specifying the data binding
*/
public static BindingCreation bind( PropertyAdapter source )
{
return new BindingCreation( source );
}
/**
* First step, accepts a data binding source definition and creates a binder
*
* @param widget
* The HasValue widget, like a TextBox. The binding system will
* the use setValue, getValue and addValueChangeHandler methods to
* set, get and get change notifications on the widget.
* @return The Binder to continue specifying the data binding
*/
public static BindingCreation bind( HasValue<?> widget )
{
return bind( new ValuePropertyAdapter( widget ) );
}
/**
* First step, accepts a data binding source definition and creates a binder
*
* @param listBox
* The ListBox widget, like a TextBox. The binding system will
* use the setValue, getValue and addChangeHandler methods to
* set, get and get change notifications on the widget.
* @return The Binder to continue specifying the data binding
*/
public static BindingCreation bind( ListBox listBox )
{
return bind( new ListBoxPropertyAdapter( listBox ) );
}
/**
* First step, accepts a data binding source definition and creates a binder
*
* @param source
* Accepts a source object as the value provided for the binding.
* In that case, <b>note</b> that the provided source must be
* bound in one way mode, because the source cannot be modified
* in that mode.
* @return The Binder to continue specifying the data binding
*/
public static BindingCreation bindObject( final Object source )
{
return bind( new ObjectAsValuePropertyAdapter( source ) );
}
/**
* Maps two objects together. All matching fields will then be two-way
* data-bound.
*/
public static DataBinding map( Object source, Object destination )
{
return (DataBinding)bindObject(source).mapTo( destination );
}
}