@Override public Binding<BEAN, TARGET> bind(ValueProvider<BEAN, TARGET> getter, Setter<BEAN, TARGET> setter) { checkUnbound(); Objects.requireNonNull(getter, "getter cannot be null"); BindingImpl<BEAN, FIELDVALUE, TARGET> binding = new BindingImpl<>( this, getter, setter); getBinder().bindings.add(binding); if (getBinder().getBean() != null) { binding.initFieldValue(getBinder().getBean()); } if (setter == null) { binding.getField().setReadOnly(true); } getBinder().fireStatusChangeEvent(false); bound = true; getBinder().incompleteBindings.remove(getField()); return binding; }
@Override public BindingValidationStatus<TARGET> validate(boolean fireEvent) { Objects.requireNonNull(binder, "This Binding is no longer attached to a Binder"); BindingValidationStatus<TARGET> status = doValidation(); if (fireEvent) { getBinder().getValidationStatusHandler() .statusChange(new BinderValidationStatus<>(getBinder(), Arrays.asList(status), Collections.emptyList())); getBinder().fireStatusChangeEvent(status.isError()); } return status; }
/** * Sets the read only state to the given value for all current bindings. * <p> * This is just a shorthand for calling {@link Binding#setReadOnly(boolean)} * for all current bindings. It means that bindings added after this method * call won't be set read-only. * * @param readOnly * {@code true} to set the bindings to read-only, {@code false} * to set them to read-write */ public void setReadOnly(boolean readOnly) { getBindings().stream().filter(binding -> binding.getSetter() != null) .forEach(binding -> binding.setReadOnly(readOnly)); }
if (binding.getField() != null) binding.initFieldValue(bean); });
/** * Finds and removes all Bindings for the given field. Note that this method * and other overloads of removeBinding method do not reset component errors * that might have been added to the field and do not remove required * indicator of the field no matter if it was set by Binder or not. To reset * component errors, {@code field.setComponentError(null)} should be called * and to remove required indicator, * {@code field.setRequiredIndicatorVisible(false)} should be called. * * @see com.vaadin.ui.AbstractComponent#setComponentError * @see com.vaadin.ui.AbstractComponent#setRequiredIndicatorVisible * * @param field * the field to remove from bindings * * @since 8.2 */ public void removeBinding(HasValue<?> field) { Objects.requireNonNull(field, "Field can not be null"); Set<BindingImpl<BEAN, ?, ?>> toRemove = getBindings().stream() .filter(binding -> field.equals(binding.getField())) .collect(Collectors.toSet()); toRemove.forEach(Binding::unbind); }
/** * Finds an appropriate locale to be used in conversion and validation. * * @return the found locale, not null */ protected Locale findLocale() { Locale l = null; if (getField() instanceof Component) { l = ((Component) getField()).getLocale(); } if (l == null && UI.getCurrent() != null) { l = UI.getCurrent().getLocale(); } if (l == null) { l = Locale.getDefault(); } return l; }
/** * Sets the field value by invoking the getter function on the given * bean. The default listener attached to the field will be removed for * the duration of this update. * * @param bean * the bean to fetch the property value from */ private void initFieldValue(BEAN bean) { assert bean != null; assert onValueChange != null; valueInit = true; try { getField().setValue(convertDataToFieldType(bean)); } finally { valueInit = false; } }
/** * Write the field value by invoking the setter function on the given * bean, if the value passes all registered validators. * * @param bean * the bean to set the property value to */ private BindingValidationStatus<TARGET> writeFieldValue(BEAN bean) { assert bean != null; Result<TARGET> result = doConversion(); if (!isReadOnly()) { result.ifOk(value -> setter.accept(bean, value)); } return toValidationStatus(result); }
/** * Handles the value change triggered by the bound field. * * @param event */ private void handleFieldValueChange( ValueChangeEvent<FIELDVALUE> event) { // Don't handle change events when setting initial value if (valueInit) { return; } if (binder != null) { // Inform binder of changes; if setBean: writeIfValid getBinder().handleFieldValueChange(this, event); getBinder().fireValueChangeEvent(event); } }
@Override public void read(BEAN bean) { getField().setValue(convertDataToFieldType(bean)); }
public BindingImpl(BindingBuilderImpl<BEAN, FIELDVALUE, TARGET> builder, ValueProvider<BEAN, TARGET> getter, Setter<BEAN, TARGET> setter) { this.binder = builder.getBinder(); this.field = builder.field; this.statusHandler = builder.statusHandler; converterValidatorChain = ((Converter<FIELDVALUE, TARGET>) builder.converterValidatorChain); onValueChange = getField() .addValueChangeListener(this::handleFieldValueChange); this.getter = getter; this.setter = setter; readOnly = setter == null; }
/** * Creates a value context from the current state of the binding and its * field. * * @return the value context */ protected ValueContext createValueContext() { if (field instanceof Component) { return new ValueContext((Component) field, field); } return new ValueContext(null, field, findLocale()); }
/** * Returns the field value run through all converters and validators, * but doesn't pass the {@link BindingValidationStatus} to any status * handler. * * @return the validation status */ private BindingValidationStatus<TARGET> doValidation() { return toValidationStatus(doConversion()); }
private FIELDVALUE convertDataToFieldType(BEAN bean) { TARGET target = getter.apply(bean); ValueContext valueContext = createValueContext(); return converterValidatorChain.convertToPresentation(target, valueContext); }
/** * Returns the field value run through all converters and validators, * but doesn't pass the {@link BindingValidationStatus} to any status * handler. * * @return the result of the conversion */ private Result<TARGET> doConversion() { FIELDVALUE fieldValue = field.getValue(); return converterValidatorChain.convertToModel(fieldValue, createValueContext()); }
@Override public void setReadOnly(boolean readOnly) { if (setter == null && !readOnly) { throw new IllegalStateException( "Binding with a null setter has to be read-only"); } this.readOnly = readOnly; getField().setReadOnly(readOnly); }