package org.vaadin.viritin;
import org.vaadin.viritin.v7.ListContainer;
import com.vaadin.v7.data.util.converter.Converter;
import com.vaadin.ui.Component;
import com.vaadin.v7.ui.Table;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import junit.framework.Assert;
import org.junit.Test;
import org.vaadin.viritin.v7.fields.MultiSelectTable;
import org.vaadin.viritin.v7.form.AbstractForm;
import org.vaadin.viritin.layouts.MVerticalLayout;
import org.vaadin.viritin.testdomain.Group;
import org.vaadin.viritin.testdomain.Person;
import org.vaadin.viritin.testdomain.Service;
/**
* A test and use case for MultiSelectTable
*
* @author Matti Tahvonen
*
*/
public class MultiSelectMadnesInCore {
public static class PersonFormWithCoreTable extends AbstractForm {
private static final long serialVersionUID = -4766609148902175465L;
private Table groups = new Table();
public PersonFormWithCoreTable() {
setEagerValidation(true);
groups.setMultiSelect(true);
groups.setContainerDataSource(new ListContainer<>(Service.
getAvailableGroups()));
Class c = groups.getType();
// The presentation type of multiselect table is Set, but you
// cannot give such converter for it :-(
// And, Vaadin is doing weirdish doublecounversion when pushing data
// to data sources, so it is probably not possible to implement a
// "modifying collection container". So this is not, and not even
// used in the example....
Converter<Object, Collection> modifyingCollectionConverter = new Converter() {
@Override
public Object convertToModel(Object value, Class targetType,
Locale locale) throws Converter.ConversionException {
Collection originalCollection;
if (groups.getPropertyDataSource().getValue() != null) {
originalCollection = (Collection) groups.
getPropertyDataSource().getValue();
} else {
// create collection with correct type supports List/Set
Class c = groups.getPropertyDataSource().getType();
if (c.isInterface()) {
if (c == List.class) {
originalCollection = new ArrayList();
} else {
// assume set, try to use HashSet
originalCollection = new HashSet();
}
} else {
try {
originalCollection = (Collection) c.
newInstance();
} catch (IllegalAccessException | InstantiationException ex) {
throw new RuntimeException(
"Unsupported collection type", ex);
}
}
groups.getPropertyDataSource().setValue(
originalCollection);
}
Collection c = (Collection) groups.getValue();
Set orphaned = new HashSet(c);
for (Object o : c) {
orphaned.remove(o);
if (!originalCollection.contains(o)) {
originalCollection.add(o);
}
}
originalCollection.removeAll(orphaned);
return originalCollection;
}
@Override
public Object convertToPresentation(Object value,
Class targetType, Locale locale) throws Converter.ConversionException {
// Vaadin does some really hackish double conversions when
// pushing back the data to entity :-( this will never work
// properly...
Set s = new HashSet();
if (value != null) {
s.addAll((Collection) value);
}
return s;
}
@Override
public Class getModelType() {
return Collection.class;
}
@Override
public Class getPresentationType() {
return Set.class;
}
};
// groups.setConverter(modifyingCollectionConverter);
Converter<Object, Collection> nonModifyingCollectionConverter = new Converter() {
@Override
public Object convertToModel(Object value, Class targetType,
Locale locale) throws Converter.ConversionException {
Set set = (Set) value;
// create collection with correct type supports List/Set
Class c = groups.getPropertyDataSource().getType();
if (c.isInterface()) {
if (c == List.class) {
return new ArrayList(set);
} else {
// assume set, try to use HashSet
return new HashSet(set);
}
} else {
try {
Collection col = (Collection) c.
newInstance();
col.addAll(set);
return col;
} catch (IllegalAccessException | InstantiationException ex) {
throw new RuntimeException(
"Unsupported collection type",
ex);
}
}
}
@Override
public Object convertToPresentation(Object value,
Class targetType, Locale locale) throws Converter.ConversionException {
// Vaadin does some really hackish double conversions when
// pushing back the data to entity :-( this will never work
// properly...
Set s = new HashSet();
if (value != null) {
s.addAll((Collection) value);
}
return s;
}
@Override
public Class
getModelType() {
return Collection.class;
}
@Override
public Class
getPresentationType() {
return Set.class;
}
};
groups.setConverter(nonModifyingCollectionConverter);
}
@Override
protected Component createContent() {
return new MVerticalLayout(groups);
}
}
public static class PersonForm extends AbstractForm<Person> {
private static final long serialVersionUID = 6410815033625409608L;
MultiSelectTable<Group> groups = new MultiSelectTable()
.setOptions(Service.getAvailableGroups());
{
setEagerValidation(true);
}
@Override
protected Component createContent() {
return new MVerticalLayout(groups);
}
}
@Test
public void bindMultiSelectFormWithCoreComponent() {
PersonFormWithCoreTable f = new PersonFormWithCoreTable();
final Person person = Service.getPerson();
List<Group> originalList = person.getGroups();
f.setEntity(person);
// FIXME avoid odd cast
Object o = f.groups.getValue();
Set value = (Set) o;
Assert.assertEquals(1, value.size());
Assert.assertEquals(person.getGroups().get(0), value.iterator().next());
f.groups.select(Service.getAvailableGroups().get(2));
f.groups.select(Service.getAvailableGroups().get(3));
Assert.assertEquals(3, person.getGroups().size());
o = f.groups.getValue();
value = (Set) o;
Assert.assertEquals(3, value.size());
// FIXME typing
for (Object v : value) {
Assert.assertTrue(person.getGroups().contains(v));
}
// TODO it should be possible to keep the list same/write final for the
// groups collection in Personā«
//Assert.assertSame(originalList, person.getGroups());
}
@Test
public void bindMultiSelectForm() {
PersonForm f = new PersonForm();
final Person person = Service.getPerson();
List<Group> originalList = person.getGroups();
f.setEntity(person);
// No odd casts, the table value is always Collection of your referenced types
Collection<Group> value = f.groups.getValue();
Assert.assertEquals(1, value.size());
Assert.assertEquals(person.getGroups().get(0), value.iterator().next());
f.groups.select(Service.getAvailableGroups().get(2));
f.groups.select(Service.getAvailableGroups().get(3));
Assert.assertEquals(3, person.getGroups().size());
value = f.groups.getValue();
Assert.assertEquals(3, value.size());
for (Group v : value) {
Assert.assertTrue(person.getGroups().contains(v));
}
// The backed list is kept the same
Assert.assertSame(originalList, person.getGroups());
}
}