Last active
April 25, 2017 12:23
-
-
Save christoph-frick/947fec59cfd09f7140933b52102cc041 to your computer and use it in GitHub Desktop.
Vaadin CustomField for a Value-type, that wrapps a field for a Presentation-type and uses a Converter to transform between the two
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.ofnir.vaadin.form | |
import com.vaadin.data.BeanValidationBinder | |
import com.vaadin.data.Binder | |
import com.vaadin.data.Converter | |
import com.vaadin.data.HasValue | |
import com.vaadin.shared.Registration | |
import com.vaadin.ui.AbstractField | |
import com.vaadin.ui.Component | |
import com.vaadin.ui.CustomField | |
import groovy.transform.EqualsAndHashCode | |
import groovy.transform.TupleConstructor | |
/** | |
* Adapts a Field to another type via a Converter. | |
* @param < VALUE > Type this field can handle | |
* @param < PRESENTATION > Type of the wrapped field | |
*/ | |
class ConverterField<VALUE, PRESENTATION> extends CustomField<VALUE> { | |
private final AbstractField<PRESENTATION> wrappedField | |
private final Converter<PRESENTATION, VALUE> converter | |
private final Binder<ValueContainer<VALUE>> binder | |
private VALUE oldValue | |
/** | |
* @param wrappedField The field to edit the converted value. | |
* @param converter Converter to transform between the edited type and the type of the wrapped field. | |
* @param nullRepresentation Optional `null` applied before the converter | |
*/ | |
ConverterField(AbstractField<PRESENTATION> wrappedField, Converter<PRESENTATION, VALUE> converter, Optional<PRESENTATION> nullRepresentation = Optional.empty()) { | |
this.wrappedField = wrappedField | |
caption = wrappedField.caption | |
this.converter = converter | |
binder = new BeanValidationBinder<ValueContainer<VALUE>>(ValueContainer) | |
def builder = binder.forField(wrappedField) | |
nullRepresentation.ifPresent{ | |
builder = builder.withNullRepresentation(it) // before converter! | |
} | |
builder.withConverter(converter).bind('value') | |
doSetValue(null) | |
} | |
// @Override | |
protected Component initContent() { | |
return wrappedField | |
} | |
// @Override | |
protected void doSetValue(VALUE value) { | |
oldValue = value | |
binder.bean = new ValueContainer<VALUE>(value) | |
} | |
@Override | |
VALUE getValue() { | |
return binder.bean.value | |
} | |
@Override | |
Registration addValueChangeListener(HasValue.ValueChangeListener<VALUE> listener) { | |
return binder.addValueChangeListener({ HasValue.ValueChangeEvent<PRESENTATION> event -> | |
assert event.source == wrappedField, "A binder will only ever fire change events for the bound fields" | |
listener.valueChange(new HasValue.ValueChangeEvent<VALUE>(this, oldValue, event.userOriginated)) | |
oldValue = getValue() | |
} as HasValue.ValueChangeListener<VALUE>) | |
} | |
@TupleConstructor | |
@EqualsAndHashCode(includes = ['value']) | |
static class ValueContainer<VALUE> { | |
VALUE value | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment