package org.robobinding.viewattribute.property;
import org.robobinding.BindingContext;
import org.robobinding.attribute.ValueModelAttribute;
import org.robobinding.property.PropertyChangeListener;
import org.robobinding.property.ValueModel;
import org.robobinding.widgetaddon.ViewAddOn;
/**
*
* @since 1.0
* @version $Revision: 1.0 $
* @author Cheng Wei
*/
public class TwoWayBindingProperty extends AbstractBindingProperty {
private final ViewAddOn viewAddOn;
private final TwoWayPropertyViewAttribute<Object, ViewAddOn, Object> viewAttribute;
private final UpdatePropagationLatch viewUpdatePropagationLatch;
private final UpdatePropagationLatch modelUpdatePropagationLatch;
@SuppressWarnings("unchecked")
public TwoWayBindingProperty(Object view, ViewAddOn viewAddOn,
TwoWayPropertyViewAttribute<?, ?, ?> viewAttribute,
ValueModelAttribute attribute) {
super(view, attribute, isAlwaysPreInitializingView(viewAttribute));
this.viewAddOn = viewAddOn;
this.viewAttribute = (TwoWayPropertyViewAttribute<Object, ViewAddOn, Object>)viewAttribute;
this.viewUpdatePropagationLatch = new UpdatePropagationLatch();
this.modelUpdatePropagationLatch = new UpdatePropagationLatch();
}
@Override
public void performBind(BindingContext context) {
ValueModel<Object> valueModel = getPropertyValueModel(context);
valueModel = new PropertyValueModelWrapper(valueModel);
observeChangesOnTheValueModel(valueModel);
viewAttribute.observeChangesOnTheView(viewAddOn, valueModel, view);
}
private void observeChangesOnTheValueModel(final ValueModel<Object> valueModel) {
PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
@Override
public void propertyChanged() {
modelUpdatePropagationLatch.turnOn();
try {
if (viewUpdatePropagationLatch.tryToPass())
updateView(valueModel);
} finally {
modelUpdatePropagationLatch.turnOff();
}
}
};
PropertyChangeListenerInUiThread inUiThread = new PropertyChangeListenerInUiThread(propertyChangeListener);
valueModel.addPropertyChangeListener(inUiThread);
}
@Override
protected void updateView(ValueModel<Object> valueModel) {
viewAttribute.updateView(view, valueModel.getValue(), viewAddOn);
}
@Override
public ValueModel<Object> getPropertyValueModel(BindingContext context) {
return context.getPropertyValueModel(attribute.getPropertyName());
}
private class PropertyValueModelWrapper implements ValueModel<Object> {
private ValueModel<Object> propertyValueModel;
public PropertyValueModelWrapper(ValueModel<Object> propertyValueModel) {
this.propertyValueModel = propertyValueModel;
}
@Override
public Object getValue() {
return propertyValueModel.getValue();
}
@Override
public void setValue(Object newValue) {
viewUpdatePropagationLatch.turnOn();
try {
if (modelUpdatePropagationLatch.tryToPass())
propertyValueModel.setValue(newValue);
} finally {
viewUpdatePropagationLatch.turnOff();
}
}
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertyValueModel.addPropertyChangeListener(listener);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
propertyValueModel.removePropertyChangeListener(listener);
}
}
}