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); } } }