
no.tornado.databinding.Binding Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of databinding Show documentation
Show all versions of databinding Show documentation
Swing Data Binding is a powerful, fast, light and simple data binding framework for Java.
The newest version!
package no.tornado.databinding;
import no.tornado.databinding.converter.ConversionException;
import no.tornado.databinding.converter.Converter;
import no.tornado.databinding.converter.ConverterRegistry;
import no.tornado.databinding.status.StatusMonitor;
import no.tornado.databinding.uibridge.UIBridge;
import no.tornado.databinding.uibridge.UIBridgeRegistry;
import no.tornado.databinding.validator.RequiredValidator;
import no.tornado.databinding.validator.ValidationResult;
import no.tornado.databinding.validator.ValidationStrategy;
import no.tornado.databinding.validator.Validator;
import org.apache.commons.beanutils.BeanUtilsBean2;
import org.apache.commons.beanutils.PropertyUtilsBean;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class Binding {
public static final PropertyUtilsBean propertyUtils = BeanUtilsBean2.getInstance().getPropertyUtils();
private String propertyExpression;
private UI_TYPE ui;
private Object model;
private UIBridge bridge;
private StatusMonitor statusMonitor;
private boolean valid = true;
private BindingStrategy bindingStrategy = BindingStrategy.ONFLUSH;
private ValidationStrategy validationStrategy = ValidationStrategy.ONCHANGE;
private List validators = new ArrayList();
private Converter converter;
private Class extends UI_VALUE_TYPE> uiValueType;
private Class extends MODEL_VALUE_TYPE> modelValueType;
private BindingGroup bindingGroup;
private List focusListeners = new ArrayList();
private List changeListeners = new ArrayList();
private boolean bound = false;
private boolean usePropertyChangeSupport = false;
private PropertyChangeListener modelPropertyChangeListener;
public Binding(UI_TYPE ui, Object model, String propertyExpression) {
this.ui = ui;
this.model = model;
this.propertyExpression = propertyExpression;
}
@SuppressWarnings({"unchecked"})
public static Binding create(JComponent ui, Object model, String propertyExpression) {
return new Binding(ui, model, propertyExpression);
}
public static Binding create(JComponent ui, String propertyExpression) {
return new Binding(ui, null, propertyExpression);
}
public void flushModelToUI() {
try {
bridge.setUIValue(ui, convertForward(getModelValue()));
// Load "full" object from ui listmodel into model
if (ui.getClass().equals(JComboBox.class)) {
JComboBox c = (JComboBox) ui;
int idx = c.getSelectedIndex();
if (idx > -1) {
Object o = c.getModel().getElementAt(idx);
propertyUtils.setNestedProperty(model, propertyExpression, o);
}
}
} catch (Exception ignored) {
}
}
public void flushUIToModel() {
try {
doValidate();
setModelValue(convertReverse(bridge.getUIValue(ui)));
handleConversionSuccess();
} catch (ConversionException ex) {
handleConversionFailed(ex);
}
}
private void setValid(boolean valid) {
this.valid = valid;
if (valid)
bindingGroup.bindingValid(this);
else
bindingGroup.bindingInvalid(this);
}
private void setModelValue(MODEL_VALUE_TYPE value) throws ConversionException {
try {
propertyUtils.setNestedProperty(model, propertyExpression, value);
} catch (Exception e) {
throw new ConversionException("Failed to retrieve property from object", e);
}
}
@SuppressWarnings({"unchecked"})
private MODEL_VALUE_TYPE getModelValue() throws ConversionException {
try {
return (MODEL_VALUE_TYPE) propertyUtils.getNestedProperty(model, propertyExpression);
} catch (Exception e) {
throw new ConversionException("Failed to retrieve property from object", e);
}
}
public Binding bind() {
if (bound)
return this;
bound = true;
if (model == null)
throw new RuntimeException("Missing model!");
if (propertyExpression == null)
throw new RuntimeException("No propertyexpression set on binding");
if (ui == null)
throw new RuntimeException("No ui component set when when connecting " + propertyExpression);
bridge = UIBridgeRegistry.getBridge(ui.getClass());
if (bridge == null)
throw new RuntimeException("No UIBridge found for " + ui.getClass() + " when connecting " + propertyExpression);
try {
this.modelValueType = propertyUtils.getPropertyType(model, propertyExpression);
} catch (Exception e) {
throw new RuntimeException("Cannot get model type");
}
this.uiValueType = bridge.getUIValueType();
flushModelToUI();
configureBindingStrategy();
configureValidationStrategy();
configurePropertyChangeSupport();
return this;
}
private void configurePropertyChangeSupport() {
if (isUsePropertyChangeSupport() && model != null) {
try {
modelPropertyChangeListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(propertyExpression))
flushModelToUI();
}
};
Method addListenerMethod = model.getClass().getMethod("addPropertyChangeListener", PropertyChangeListener.class);
addListenerMethod.invoke(model, modelPropertyChangeListener);
} catch (Exception ignored) {
}
}
}
private void configureValidationStrategy() {
// Skip validation if conversion happens onchange or onblur, because validation happens in the conversion step as well
if (bindingStrategy.equals(BindingStrategy.ONFLUSH)) {
switch (validationStrategy) {
case ONCHANGE:
ChangeListener ch = new ChangeListener() {
public void stateChanged(ChangeEvent e) {
validate();
}
};
changeListeners.add(bridge.addValueChangeListener(ui, ch));
break;
case ONBLUR:
FocusAdapter focus = new FocusAdapter() {
public void focusLost(FocusEvent e) {
validate();
}
};
focusListeners.add(focus);
ui.addFocusListener(focus);
break;
}
}
}
public void validate() {
try {
doValidate();
} catch (ConversionException ex) {
handleConversionFailed(ex);
}
}
private void handleConversionSuccess() {
setValid(true);
if (statusMonitor != null)
statusMonitor.setStatus(null);
}
private void handleConversionFailed(ConversionException ex) {
setValid(false);
if (statusMonitor != null)
statusMonitor.setStatus(ex.getMessage());
}
/**
* Validate UI content, but don't flush the data to the model object.
* Trigger conversion to trap any exceptions there as well
*
* @throws ConversionException If the conversion fails
*/
private void doValidate() throws ConversionException {
if (validators.isEmpty()) {
convertReverse(bridge.getUIValue(ui));
} else {
MODEL_VALUE_TYPE convertedValue = convertReverse(bridge.getUIValue(ui));
for (Validator validator : validators) {
ValidationResult result = validator.validate(convertedValue);
if (!result.isOk())
throw new ConversionException(result);
}
}
handleConversionSuccess();
}
private UI_VALUE_TYPE convertForward(MODEL_VALUE_TYPE modelValue) throws ConversionException {
if (modelValue == null) return null;
if (converter != null) return converter.convertForward(modelValue);
return ConverterRegistry.convert(modelValue, uiValueType);
}
private MODEL_VALUE_TYPE convertReverse(UI_VALUE_TYPE uiValue) throws ConversionException {
if (uiValue == null) return null;
if (converter != null) return converter.convertReverse(uiValue);
return ConverterRegistry.convert(uiValue, modelValueType);
}
public Binding required() {
validators.add(RequiredValidator.INSTANCE);
return this;
}
private void configureBindingStrategy() {
switch (bindingStrategy) {
case ONCHANGE:
ChangeListener ch = new ChangeListener() {
public void stateChanged(ChangeEvent e) {
flushUIToModel();
}
};
changeListeners.add(bridge.addValueChangeListener(ui, ch));
break;
case ONBLUR:
FocusAdapter focus = new FocusAdapter() {
public void focusLost(FocusEvent e) {
flushUIToModel();
}
};
focusListeners.add(focus);
ui.addFocusListener(focus);
break;
}
}
public Binding unbind() {
if (!bound)
return this;
for (UI_LISTENER_TYPE listener : changeListeners)
bridge.removeValueChangelistener(ui, listener);
for (FocusListener focus : focusListeners)
ui.removeFocusListener(focus);
focusListeners.clear();
changeListeners.clear();
removePropertyChangeSupport();
bound = false;
return this;
}
private void removePropertyChangeSupport() {
if (modelPropertyChangeListener != null) {
try {
Method removeListenerMethod = model.getClass().getMethod("removePropertyChangeListener", PropertyChangeListener.class);
removeListenerMethod.invoke(model, modelPropertyChangeListener);
modelPropertyChangeListener = null;
} catch (Exception ignored) {
}
}
}
public Binding validator(Validator validator) {
validators.add(validator);
return this;
}
public Binding bindingStrategy(BindingStrategy bindingStrategy) {
this.bindingStrategy = bindingStrategy;
return this;
}
public Binding validationStrategy(ValidationStrategy validationStrategy) {
this.validationStrategy = validationStrategy;
return this;
}
public String getPropertyExpression() {
return propertyExpression;
}
public void setPropertyExpression(String propertyExpression) {
this.propertyExpression = propertyExpression;
}
public UI_TYPE getUi() {
return ui;
}
public void setUi(UI_TYPE ui) {
this.ui = ui;
}
public Object getModel() {
return model;
}
public void setModel(Object model) {
this.model = model;
}
public BindingStrategy getBindingStrategy() {
return bindingStrategy;
}
public void setBindingStrategy(BindingStrategy bindingStrategy) {
this.bindingStrategy = bindingStrategy;
}
public ValidationStrategy getValidationStrategy() {
return validationStrategy;
}
public void setValidationStrategy(ValidationStrategy validationStrategy) {
this.validationStrategy = validationStrategy;
}
public List getValidators() {
return validators;
}
public void setValidators(List validators) {
this.validators = validators;
}
public Converter getConverter() {
return converter;
}
public void setConverter(Converter converter) {
this.converter = converter;
}
public StatusMonitor getStatusMonitor() {
return statusMonitor;
}
public void setStatusMonitor(StatusMonitor statusMonitor) {
this.statusMonitor = statusMonitor;
}
public Binding statusMonitor(StatusMonitor statusMonitor) {
this.statusMonitor = statusMonitor;
return this;
}
public boolean isValid() {
return valid;
}
public BindingGroup getBindingGroup() {
return bindingGroup;
}
public void setBindingGroup(BindingGroup bindingGroup) {
this.bindingGroup = bindingGroup;
}
public boolean isUsePropertyChangeSupport() {
return usePropertyChangeSupport;
}
public void setUsePropertyChangeSupport(boolean usePropertyChangeSupport) {
this.usePropertyChangeSupport = usePropertyChangeSupport;
}
public Binding usePropertyChangeSupport(boolean usePropertyChangeSupport) {
setUsePropertyChangeSupport(usePropertyChangeSupport);
return this;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy