
org.vaadin.viritin.fields.CheckBoxGroup Maven / Gradle / Ivy
package org.vaadin.viritin.fields;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.vaadin.viritin.ListContainer;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.ui.Component;
import com.vaadin.ui.CustomField;
import com.vaadin.ui.OptionGroup;
/**
* An OptionGroup that can be used as a field to modify
* List>YourDomainObject< or Set>YourDomainObject< typed fields in
* your domain model.
*
* The field supports only non buffered mode. Also, the field tries to keep the
* original collection and just modify its content. This helps e.g. some ORM
* libraries to create more efficient updates to the database.
*
* If the field value is null (and users selects rows) the field tries to add a
* value with no-arg constructor or with ArrayList/HashMap if interface is used.
*
* @author Matti Tahvonen
* @param The type in the entity collection
*/
public class CheckBoxGroup extends CustomField {
private CaptionGenerator captionGenerator;
OptionGroup optionGroup = new OptionGroup() {
{
setMultiSelect(true);
setSizeFull();
setImmediate(true);
}
private boolean clientSideChange;
@Override
public void changeVariables(Object source,
Map variables) {
clientSideChange = true;
super.changeVariables(source, variables);
clientSideChange = false;
}
@Override
protected void setValue(Object newValue, boolean repaintIsNotNeeded) throws ReadOnlyException {
Set oldvalue = (Set) getValue();
super.setValue(newValue, repaintIsNotNeeded);
if (clientSideChange) {
// TODO add strategies for maintaining the order in case of List
// e.g. same as listing, selection order ...
Collection collection = getEditedCollection();
Set newvalue = (Set) getValue();
Set orphaned = new HashSet(oldvalue);
orphaned.removeAll(newvalue);
collection.removeAll(orphaned);
Set newValues = new LinkedHashSet(newvalue);
newValues.removeAll(oldvalue);
collection.addAll(newValues);
CheckBoxGroup.this.fireValueChange(true);
}
}
@Override
public String getItemCaption(Object itemId) {
if(captionGenerator != null) {
return captionGenerator.getCaption((ET) itemId);
}
return super.getCaption();
}
};
public CheckBoxGroup(String caption) {
this();
setCaption(caption);
}
public CheckBoxGroup setCaptionGenerator(CaptionGenerator captionGenerator) {
this.captionGenerator = captionGenerator;
return this;
}
private Collection getEditedCollection() {
Collection c = getValue();
if (c == null) {
if (getPropertyDataSource() == null) {
// this should never happen :-)
return new HashSet();
}
Class fieldType = getPropertyDataSource().getType();
if (fieldType.isInterface()) {
if (fieldType == List.class) {
c = new ArrayList();
} else { // Set
c = new HashSet();
}
} else {
try {
c = (Collection) fieldType.newInstance();
} catch (IllegalAccessException | InstantiationException ex) {
throw new RuntimeException(
"Could not instantiate the used colleciton type", ex);
}
}
}
return c;
}
@Override
protected Component initContent() {
return optionGroup;
}
@Override
public Class extends Collection> getType() {
return Collection.class;
}
@Override
protected void setInternalValue(Collection newValue) {
super.setInternalValue(newValue);
optionGroup.setValue(newValue);
}
/**
* Sets the list of options available.
*
* @param list the list of available options
* @return this for fluent configuration
*/
public CheckBoxGroup setOptions(List list) {
optionGroup.setContainerDataSource(new ListContainer(list));
return this;
}
/**
* Sets the list of options available.
*
* @param list the list of available options
* @return this for fluent configuration
*/
public CheckBoxGroup setOptions(ET... list) {
return setOptions(Arrays.asList(list));
}
public CheckBoxGroup() {
setHeight("230px");
// TODO verify if this is needed in real usage, but at least to pass the test
setConverter(new Converter() {
@Override
public Collection convertToModel(Collection value,
Class extends Collection> targetType, Locale locale) throws Converter.ConversionException {
return value;
}
@Override
public Collection convertToPresentation(Collection value,
Class extends Collection> targetType, Locale locale) throws Converter.ConversionException {
return value;
}
@Override
public Class getModelType() {
return (Class) getEditedCollection().getClass();
}
@Override
public Class getPresentationType() {
return Collection.class;
}
});
}
public void select(ET objectToSelect) {
if (!optionGroup.isSelected(objectToSelect)) {
optionGroup.select(objectToSelect);
getEditedCollection().add(objectToSelect);
}
}
public void unSelect(ET objectToDeselect) {
if (optionGroup.isSelected(objectToDeselect)) {
optionGroup.unselect(objectToDeselect);
getEditedCollection().remove(objectToDeselect);
}
}
/**
* @return the underlaying table implementation. Protected as one should
* expect odd behavior if it configured in unsupported manner.
*/
protected OptionGroup getUndelayingTable() {
return optionGroup;
}
public CheckBoxGroup withFullWidth() {
setWidth(100, Unit.PERCENTAGE);
return this;
}
public CheckBoxGroup withHeight(String height) {
setHeight(height);
return this;
}
public CheckBoxGroup withFullHeight() {
return withHeight("100%");
}
public CheckBoxGroup withWidth(String width) {
setWidth(width);
return this;
}
public CheckBoxGroup withCaption(String caption) {
setCaption(caption);
return this;
}
public CheckBoxGroup withId(String id) {
setId(id);
return this;
}
}