/*
* Ext GWT 2.2.4 - Ext for GWT
* Copyright(c) 2007-2010, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
package com.extjs.gxt.ui.client.binding;
import com.extjs.gxt.ui.client.data.ChangeEvent;
import com.extjs.gxt.ui.client.data.ChangeEventSource;
import com.extjs.gxt.ui.client.data.ChangeListener;
import com.extjs.gxt.ui.client.data.Model;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.PropertyChangeEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.FieldEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.store.Record;
import com.extjs.gxt.ui.client.store.Store;
import com.extjs.gxt.ui.client.widget.form.Field;
/**
* A two-way binding between a ModelData and Field instance. The binding will be
* 1-way when the bound model does not support change events.
*
* @see ModelData
* @see Field
*/
@SuppressWarnings({"unchecked","rawtypes"})
public class FieldBinding {
protected Field field;
protected ModelData model;
protected String property;
protected Store store;
private Listener<FieldEvent> changeListener;
private ChangeListener modelListener;
private Converter converter;
private boolean updateOriginalValue = false;
/**
* Creates a new binding instance.
*
* @param field the bound field for the binding
*/
public FieldBinding(Field field, String property) {
this.field = field;
this.property = property;
changeListener = new Listener<FieldEvent>() {
public void handleEvent(FieldEvent be) {
onFieldChange(be);
}
};
modelListener = new ChangeListener() {
public void modelChanged(ChangeEvent event) {
if (event.getType() == ChangeEventSource.Update) {
onModelChange((PropertyChangeEvent) event);
}
}
};
}
/**
* Binds the model and field. This method also updates the fields original
* value which controls the dirty state of the field.
*
* @param model the model to be bound
*/
public void bind(ModelData model) {
if (this.model != null) {
unbind();
}
this.model = model;
field.addListener(Events.Change, changeListener);
if (model instanceof Model) {
((Model) model).addChangeListener(modelListener);
}
updateField(updateOriginalValue);
}
/**
* Returns the bindings converter.
*
* @return the converter
*/
public Converter getConverter() {
return converter;
}
/**
* Returns the bound field.
*
* @return the field
*/
public Field<Object> getField() {
return field;
}
/**
* Returns the bound model instance.
*
* @return the model
*/
public ModelData getModel() {
return model;
}
/**
* Returns the model's bound property name.
*
* @return the property name
*/
public String getProperty() {
return property;
}
/**
* Returns the binding's store.
*
* @return the store or null
*/
public Store getStore() {
return store;
}
/**
* Returns true if the field's original value is updated when the field is
* bound.
*
* @return true if original value is updated
*/
public boolean isUpdateOriginalValue() {
return updateOriginalValue;
}
/**
* Sets the converter which is used to translate data types when updating
* either the field or model.
*
* @param converter the converter
*/
public void setConverter(Converter converter) {
this.converter = converter;
}
/**
* Sets the store for the binding. When a store is specified edits are done
* via Records instances obtained from the Store.
*
* @param store the store
*/
public void setStore(Store<? extends ModelData> store) {
this.store = store;
}
/**
* True to update the field's original value when bound (defaults to false).
*
* @param updateOriginalValue true to update the original value
*/
public void setUpdateOriginalValue(boolean updateOriginalValue) {
this.updateOriginalValue = updateOriginalValue;
}
/**
* Unbinds the model and field by removing all listeners.
*/
public void unbind() {
if (model != null) {
if (model instanceof Model) {
((Model) model).removeChangeListener(modelListener);
}
model = null;
}
field.removeListener(Events.Change, changeListener);
if (updateOriginalValue) {
field.setOriginalValue(null);
}
field.clear();
}
/**
* Updates the field's value with the model value.
*/
public void updateField() {
updateField(false);
}
/**
* Updates the field's value and original value with the model value. Updating
* the original value will reset the field to a non-dirty state.
*
* @param updateOriginalValue true to update the original value
*/
public void updateField(boolean updateOriginalValue) {
Object val = onConvertModelValue(model.get(property));
if (updateOriginalValue) {
field.setOriginalValue(val);
}
field.setValue(val);
}
/**
* Updates the model's value with the field value.
*/
public void updateModel() {
Object val = onConvertFieldValue(field.getValue());
if (store != null) {
Record r = store.getRecord(model);
if (r != null) {
r.setValid(property, field.isValid());
r.set(property, val);
}
} else {
model.set(property, val);
}
}
protected Object onConvertFieldValue(Object value) {
if (converter != null) {
return converter.convertFieldValue(value);
}
return value;
}
protected Object onConvertModelValue(Object value) {
if (converter != null) {
return converter.convertModelValue(value);
}
return value;
}
protected void onFieldChange(FieldEvent e) {
updateModel();
}
protected void onModelChange(PropertyChangeEvent event) {
if (event.getName().equals(property)) {
updateField();
}
}
}