package au.com.vaadinutils.crud;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.metamodel.ListAttribute;
import javax.persistence.metamodel.SetAttribute;
import javax.persistence.metamodel.SingularAttribute;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.vaadin.addons.lazyquerycontainer.EntityContainer;
import org.vaadin.ui.LegacyComboBox;
import com.google.common.base.Preconditions;
import com.vaadin.addon.jpacontainer.JPAContainer;
import com.vaadin.addon.jpacontainer.fieldfactory.SingleSelectConverter;
import com.vaadin.data.Container;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.fieldgroup.FieldGroup;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.shared.ui.datefield.Resolution;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.AbstractLayout;
import com.vaadin.ui.AbstractSelect.ItemCaptionMode;
import com.vaadin.ui.Button;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.CustomField;
import com.vaadin.ui.DateField;
import com.vaadin.ui.Field;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Notification.Type;
import com.vaadin.ui.PasswordField;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
import au.com.vaadinutils.converter.ContainerAdaptor;
import au.com.vaadinutils.converter.ContainerAdaptorFactory;
import au.com.vaadinutils.converter.MultiSelectConverter;
import au.com.vaadinutils.crud.splitFields.SplitCheckBox;
import au.com.vaadinutils.crud.splitFields.SplitColorPicker;
import au.com.vaadinutils.crud.splitFields.SplitComboBox;
import au.com.vaadinutils.crud.splitFields.SplitDateField;
import au.com.vaadinutils.crud.splitFields.SplitEditorField;
import au.com.vaadinutils.crud.splitFields.SplitLabel;
import au.com.vaadinutils.crud.splitFields.SplitListSelect;
import au.com.vaadinutils.crud.splitFields.SplitPasswordField;
import au.com.vaadinutils.crud.splitFields.SplitTextArea;
import au.com.vaadinutils.crud.splitFields.SplitTextField;
import au.com.vaadinutils.crud.splitFields.SplitTwinColSelect;
import au.com.vaadinutils.crud.splitFields.legacy.LegacySplitComboBox;
import au.com.vaadinutils.dao.JpaBaseDao;
import au.com.vaadinutils.domain.iColor;
import au.com.vaadinutils.domain.iColorFactory;
import au.com.vaadinutils.fields.CKEditorEmailField;
import au.com.vaadinutils.fields.CKEditorEmailField.ConfigModifier;
import au.com.vaadinutils.fields.ColorPickerField;
import au.com.vaadinutils.fields.DataBoundButton;
public class FormHelper<E> implements Serializable
{
private static final long serialVersionUID = 1L;
public static final String STANDARD_COMBO_WIDTH = "220";
ArrayList<AbstractComponent> fieldList = new ArrayList<>();
private AbstractLayout form;
private ValidatingFieldGroup<E> group;
private Set<ValueChangeListener> valueChangeListeners = new LinkedHashSet<>();
static transient Logger logger = LogManager.getLogger(FormHelper.class);
public FormHelper(AbstractLayout form, ValidatingFieldGroup<E> group)
{
// I'm actually using this without a field group.
// need to makes some modifications so that we formally support
// non-group usage.
// Preconditions.checkNotNull(group,
// "ValidatingFieldGroup can not be null");
this.form = form;
this.group = group;
}
/**
* The added value change listener will get added to every component that's
* created with the FormHelper
*
* @param listener
* the value change listener
*/
public void addValueChangeListener(ValueChangeListener listener)
{
valueChangeListeners.add(listener);
}
@SuppressWarnings("rawtypes")
private void addValueChangeListeners(AbstractField c)
{
for (ValueChangeListener listener : valueChangeListeners)
{
c.addValueChangeListener(listener);
}
}
public <M> TextField bindTextField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel,
SingularAttribute<E, M> member)
{
TextField field = bindTextField(form, group, fieldLabel, member.getName());
this.fieldList.add(field);
return field;
}
public <M> TextField bindTextField(String fieldLabel, SingularAttribute<E, M> member)
{
TextField field = bindTextField(form, group, fieldLabel, member.getName());
this.fieldList.add(field);
return field;
}
public <M> TextField bindTextFieldWithButton(String fieldLabel, SingularAttribute<E, M> member, Button button)
{
TextField field = bindTextFieldWithButton(form, group, fieldLabel, member.getName(), button);
this.fieldList.add(field);
return field;
}
public TextField bindTextField(String fieldLabel, String fieldName)
{
TextField field = bindTextField(form, group, fieldLabel, fieldName);
this.fieldList.add(field);
return field;
}
public <T extends CustomField<?>> T doBinding(String fieldLabel, SingularAttribute<?, ?> field, T customField)
{
doBinding(group, field.getName(), customField);
this.fieldList.add(customField);
form.addComponent(customField);
return customField;
}
public <T extends CustomField<?>> T doBinding(String fieldLabel, SetAttribute<?, ?> field, T customField)
{
doBinding(group, field.getName(), customField);
this.fieldList.add(customField);
form.addComponent(customField);
return customField;
}
public <T extends CustomField<?>> T doBinding(String fieldLabel, ListAttribute<?, ?> field, T customField)
{
doBinding(group, field.getName(), customField);
this.fieldList.add(customField);
form.addComponent(customField);
return customField;
}
public TextField bindTextField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel,
String fieldName)
{
TextField field = new SplitTextField(fieldLabel);
field.setWidth("100%");
field.setImmediate(true);
field.setNullRepresentation("");
field.setNullSettingAllowed(false);
field.setId(fieldLabel.replace(" ", ""));
addValueChangeListeners(field);
doBinding(group, fieldName, field);
form.addComponent(field);
return field;
}
public TextField bindTextFieldWithButton(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel,
String fieldName, Button button)
{
HorizontalLayout layout = new HorizontalLayout();
layout.setSizeFull();
TextField field = new SplitTextField(fieldLabel);
field.setWidth("100%");
field.setImmediate(true);
field.setNullRepresentation("");
field.setNullSettingAllowed(false);
field.setId(fieldLabel.replace(" ", ""));
addValueChangeListeners(field);
doBinding(group, fieldName, field);
layout.addComponent(field);
layout.addComponent(button);
layout.setExpandRatio(field, 2);
form.addComponent(layout);
return field;
}
public void doBinding(FieldGroup group, String fieldName, @SuppressWarnings("rawtypes") Field field)
{
if (group != null)
group.bind(field, fieldName);
else
{
logger.warn("field {} was not bound", fieldName);
}
}
public <M> PasswordField bindPasswordField(AbstractLayout form, FieldGroup group, String fieldLabel,
SingularAttribute<E, M> member)
{
PasswordField field = bindPasswordField(form, group, fieldLabel, (member != null ? member.getName() : null));
this.fieldList.add(field);
return field;
}
public <M> PasswordField bindPasswordField(String fieldLabel, SingularAttribute<E, M> member)
{
PasswordField field = bindPasswordField(form, group, fieldLabel, (member != null ? member.getName() : null));
this.fieldList.add(field);
return field;
}
public PasswordField bindPasswordField(AbstractLayout form, FieldGroup group, String fieldLabel, String fieldName)
{
PasswordField field = new SplitPasswordField(fieldLabel);
field.setWidth("100%");
field.setImmediate(true);
field.setNullRepresentation("");
field.setNullSettingAllowed(false);
field.setId(fieldLabel.replace(" ", ""));
addValueChangeListeners(field);
doBinding(group, fieldName, field);
form.addComponent(field);
return field;
}
public <M> TextArea bindTextAreaField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel,
SingularAttribute<E, M> member, int rows)
{
TextArea field = bindTextAreaField(form, group, fieldLabel, member.getName(), rows);
this.fieldList.add(field);
return field;
}
public TextArea bindTextAreaField(String fieldLabel, SingularAttribute<E, String> attribute, int rows)
{
TextArea field = bindTextAreaField(form, group, fieldLabel, attribute.getName(), rows);
this.fieldList.add(field);
return field;
}
public TextArea bindTextAreaField(String fieldLabel, String fieldName, int rows)
{
TextArea field = bindTextAreaField(form, group, fieldLabel, fieldName, rows);
this.fieldList.add(field);
return field;
}
public TextArea bindTextAreaField(String fieldLabel, String fieldName, int rows, int maxlength)
{
TextArea field = bindTextAreaField(form, group, fieldLabel, fieldName, rows);
field.setMaxLength(maxlength);
this.fieldList.add(field);
return field;
}
public TextArea bindTextAreaField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel,
String fieldName, int rows)
{
TextArea field = new SplitTextArea(fieldLabel);
field.setRows(rows);
field.setWidth("100%");
field.setImmediate(true);
field.setNullRepresentation("");
addValueChangeListeners(field);
doBinding(group, fieldName, field);
form.addComponent(field);
return field;
}
public DateField bindDateField(String fieldLabel, String fieldName)
{
DateField field = bindDateField(form, group, fieldLabel, fieldName);
this.fieldList.add(field);
return field;
}
public DateField bindDateField(String label, String member, String dateFormat, Resolution resolution)
{
DateField field = bindDateField(form, group, label, member, dateFormat, resolution);
field.setWidth(STANDARD_COMBO_WIDTH);
this.fieldList.add(field);
return field;
}
public DateField bindDateField(String label, SingularAttribute<E, Date> member, String dateFormat,
Resolution resolution)
{
DateField field = bindDateField(form, group, label, member.getName(), dateFormat, resolution);
field.setWidth(STANDARD_COMBO_WIDTH);
this.fieldList.add(field);
return field;
}
public <M> DateField bindDateField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel,
SingularAttribute<E, M> member, String dateFormat, Resolution resolution)
{
DateField field = bindDateField(form, group, fieldLabel, member.getName(), dateFormat, resolution);
this.fieldList.add(field);
return field;
}
public DateField bindDateField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel,
String fieldName, String dateFormat, Resolution resolution)
{
DateField field = new SplitDateField(fieldLabel);
field.setDateFormat(dateFormat);
field.setResolution(resolution);
field.setImmediate(true);
field.setWidth("100%");
addValueChangeListeners(field);
doBinding(group, fieldName, field);
form.addComponent(field);
return field;
}
public DateField bindDateField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel,
String fieldName)
{
return bindDateField(form, group, fieldLabel, fieldName, "yyyy-MM-dd", Resolution.DAY);
}
public Label bindLabel(String fieldLabel)
{
Label field = bindLabel(form, group, fieldLabel);
this.fieldList.add(field);
return field;
}
public Label bindLabel(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel)
{
Label field = new SplitLabel(fieldLabel);
field.setWidth("100%");
form.addComponent(field);
return field;
}
public Label bindLabel(AbstractLayout form, ValidatingFieldGroup<E> group, Label field)
{
field.setWidth("100%");
form.addComponent(field);
return field;
}
public <M> ComboBox bindEnumField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel,
SingularAttribute<E, M> member, Class<?> clazz)
{
ComboBox field = bindEnumField(form, group, fieldLabel, member.getName(), clazz);
this.fieldList.add(field);
return field;
}
public ComboBox bindEnumField(String fieldLabel, String fieldName, Class<?> clazz)
{
ComboBox field = bindEnumField(form, group, fieldLabel, fieldName, clazz);
this.fieldList.add(field);
return field;
}
public ComboBox bindEnumField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel,
String fieldName, Class<?> clazz)
{
return bindEnumField(new SplitComboBox(fieldLabel), form, group, fieldLabel, fieldName, clazz);
}
public ComboBox bindEnumField(ComboBox comboBox, AbstractLayout form, ValidatingFieldGroup<E> group,
String fieldLabel, String fieldName, Class<?> clazz)
{
ComboBox field = comboBox;
field.setCaption(fieldLabel);
field.setContainerDataSource(createContainerFromEnumClass(fieldName, clazz));
field.setItemCaptionPropertyId(fieldName);
// field.setCaption(fieldLabel);
field.setNewItemsAllowed(false);
field.setNullSelectionAllowed(false);
field.setTextInputAllowed(true);
field.setWidth(STANDARD_COMBO_WIDTH);
field.setImmediate(true);
field.setId(fieldLabel.replace(" ", ""));
addValueChangeListeners(field);
doBinding(group, fieldName, field);
form.addComponent(field);
return field;
}
public <M> CheckBox bindBooleanField(String fieldLabel, SingularAttribute<E, M> member)
{
CheckBox field = bindBooleanField(form, group, fieldLabel, member.getName());
this.fieldList.add(field);
return field;
}
public CheckBox bindBooleanField(String fieldLabel, String fieldName)
{
CheckBox field = bindBooleanField(form, group, fieldLabel, fieldName);
this.fieldList.add(field);
return field;
}
public CheckBox bindBooleanField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel,
SingularAttribute<E, Boolean> member)
{
CheckBox field = bindBooleanField(form, group, fieldLabel, member.getName());
this.fieldList.add(field);
return field;
}
public CheckBox bindBooleanField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel,
String fieldName)
{
CheckBox field = new SplitCheckBox(fieldLabel);
field.setWidth("100%");
field.setImmediate(true);
addValueChangeListeners(field);
doBinding(group, fieldName, field);
form.addComponent(field);
return field;
}
public ColorPickerField bindColorPickerField(AbstractLayout form, ValidatingFieldGroup<E> group,
iColorFactory factory, String fieldLabel, SingularAttribute<E, iColor> member)
{
ColorPickerField field = bindColorPickerField(form, group, factory, fieldLabel, member.getName());
this.fieldList.add(field);
return field;
}
public ColorPickerField bindColorPickerField(AbstractLayout form, ValidatingFieldGroup<E> group,
iColorFactory factory, String fieldLabel, String fieldName)
{
ColorPickerField field = new SplitColorPicker(factory, fieldLabel);
field.setWidth("100%");
field.setImmediate(true);
doBinding(group, fieldName, field);
form.addComponent(field);
return field;
}
public <L> ComboBox bindComboBox(AbstractLayout form, ValidatingFieldGroup<E> fieldGroup, String fieldName,
String fieldLabel, Collection<?> options)
{
ComboBox field = new SplitComboBox(fieldLabel, options);
field.setNewItemsAllowed(false);
field.setNullSelectionAllowed(false);
field.setTextInputAllowed(true);
field.setWidth(STANDARD_COMBO_WIDTH);
field.setImmediate(true);
form.addComponent(field);
addValueChangeListeners(field);
doBinding(group, fieldName, field);
return field;
}
public <L> LegacyComboBox bindLegacyComboBox(AbstractLayout form, ValidatingFieldGroup<E> fieldGroup,
String fieldName, String fieldLabel, Collection<?> options)
{
LegacyComboBox field = new LegacySplitComboBox(fieldLabel, options);
field.setNewItemsAllowed(false);
field.setNullSelectionAllowed(false);
field.setTextInputAllowed(true);
field.setWidth(STANDARD_COMBO_WIDTH);
field.setImmediate(true);
form.addComponent(field);
addValueChangeListeners(field);
doBinding(group, fieldName, field);
return field;
}
public <L extends CrudEntity, K> ComboBox bindEntityField(String fieldLabel, SingularAttribute<E, L> fieldName,
SingularAttribute<L, K> listFieldName)
{
return new EntityFieldBuilder<L>().setLabel(fieldLabel).setField(fieldName).setListFieldName(listFieldName)
.build();
}
public <L extends CrudEntity, K> ComboBox bindEntityField(String fieldLabel, SingularAttribute<E, L> fieldName,
SingularAttribute<L, K> listFieldName, boolean useLazyContainer)
{
EntityContainer<L> container = JpaBaseDao.getGenericDao(fieldName.getJavaType()).createLazyQueryContainer();
return new EntityFieldBuilder<L>().setLabel(fieldLabel).setField(fieldName).setListFieldName(listFieldName)
.setContainer(container).build();
}
/**
* Deprecated - use EntityFieldBuilder instead
*/
@Deprecated
public <L extends CrudEntity> ComboBox bindEntityField(String fieldLabel, SingularAttribute<E, L> fieldName,
Class<L> listClazz, SingularAttribute<L, ?> listFieldName)
{
return new EntityFieldBuilder<L>().setLabel(fieldLabel).setField(fieldName).setListFieldName(listFieldName)
.build();
}
@Deprecated
public <L extends CrudEntity> ComboBox bindEntityField(String fieldLabel, String fieldName, Class<L> listClazz,
String listFieldName)
{
return new EntityFieldBuilder<L>().setLabel(fieldLabel).setField(fieldName).setListClass(listClazz)
.setListFieldName(listFieldName).build();
}
/**
* Deprecated - use EntityFieldBuilder instead
*
* this method is for displaying a combobox which displayes all the values
* for a many to one relationship and allows the user to select only one.
*
* @param form
* @param fieldGroup
* @param fieldLabel
* @param field
* @param listClazz
* @param listFieldName
*
* E is the entity F is the set from the entity that contains the
* foriegn entities L is the foriegn entity M is the field to
* display from the foriegn entity
*
* @return
*/
/**
* Deprecated - use EntityFieldBuilder instead
*
* @param form
* @param fieldGroup
* @param fieldLabel
* @param field
* @param listClazz
* @param listFieldName
* @return
*/
@Deprecated
public <L extends CrudEntity> ComboBox bindEntityField(AbstractLayout form, ValidatingFieldGroup<E> fieldGroup,
String fieldLabel, SingularAttribute<E, L> field, Class<L> listClazz, SingularAttribute<L, ?> listFieldName)
{
return new EntityFieldBuilder<L>().setForm(form).setLabel(fieldLabel).setField(field)
.setListFieldName(listFieldName).build();
}
/**
* Deprecated - use EntityFieldBuilder instead
*
* @param form
* @param fieldGroup
* @param fieldLabel
* @param fieldName
* @param listClazz
* @param listFieldName
* @return
*/
@Deprecated
public <L extends CrudEntity> ComboBox bindEntityField(AbstractLayout form, ValidatingFieldGroup<E> fieldGroup,
String fieldLabel, String fieldName, Class<L> listClazz, String listFieldName)
{
return new EntityFieldBuilder<L>().setForm(form).setLabel(fieldLabel).setField(fieldName)
.setListClass(listClazz).setListFieldName(listFieldName).build();
}
/**
* Deprecated - use EntityFieldBuilder instead
*
* @param field
* @param form
* @param fieldGroup
* @param fieldLabel
* @param fieldName
* @param listClazz
* @param listFieldName
* @return
*/
@Deprecated
public <L extends CrudEntity> ComboBox bindEntityField(ComboBox field, AbstractLayout form,
ValidatingFieldGroup<E> fieldGroup, String fieldLabel, String fieldName, Class<L> listClazz,
String listFieldName)
{
return new EntityFieldBuilder<L>().setComponent(field).setForm(form).setLabel(fieldLabel).setField(fieldName)
.setListClass(listClazz).setListFieldName(listFieldName).build();
}
/**
* use this syntax to instance the builder:<br>
* formHelper.new EntityFieldBuilder<{name of list class}>(); <br>
* <br>
* for example<br>
* <br>
*
* FormHelper<RaffleBook> helper = new
* FormHelper<RaffleBook>(...);<br>
* <br>
* ComboBox field = helper.new
* EntityFieldBuilder<RaffleAllocation>()<br>
* .setLabel("Action")<br>
* .setField(RaffleBook.allocation)<br>
* .setListFieldName(RaffleAllocation_.name)<br>
* .build();<br>
*
* @author rsutton
*
* @param <L>
* the type of the list class
*/
public class EntityFieldBuilder<L extends CrudEntity>
{
private ComboBox component = null;
private String label = null;
private Container container = null;
private Class<L> listClazz;
private String listField;
// private ValidatingFieldGroup<E> fieldGroup;
private String field;
private AbstractLayout builderForm;
public ComboBox build()
{
Preconditions.checkNotNull(label, "Label may not be null");
Preconditions.checkNotNull(listField, "ListField may not be null");
Preconditions.checkArgument(group == null || field != null, "Field may not be null");
if (builderForm == null)
{
builderForm = form;
}
Preconditions.checkNotNull(builderForm, "Form may not be null");
if (component == null)
{
component = new SplitComboBox(label);
}
component.setCaption(label);
component.setItemCaptionMode(ItemCaptionMode.PROPERTY);
component.setId(label.replace(" ", ""));
if (container == null)
{
Preconditions.checkNotNull(listClazz, "listClazz may not be null");
container = JpaBaseDao.getGenericDao(listClazz).createVaadinContainer();
}
// Preconditions.checkState(container.getContainerPropertyIds().contains(listField),
// listField
// + " is not valid, valid listFieldNames are " +
// container.getContainerPropertyIds().toString());
ContainerAdaptor<L> adaptor = ContainerAdaptorFactory.getAdaptor(container);
if (adaptor.getSortableContainerPropertyIds().contains(listField))
adaptor.sort(new String[] { listField }, new boolean[] { true });
component.setItemCaptionPropertyId(listField);
component.setContainerDataSource(container);
SingleSelectConverter<L> converter = new SingleSelectConverter<>(component);
component.setConverter(converter);
component.setNewItemsAllowed(false);
component.setNullSelectionAllowed(false);
component.setTextInputAllowed(true);
component.setWidth(STANDARD_COMBO_WIDTH);
component.setImmediate(true);
addValueChangeListeners(component);
if (group != null)
{
Collection<? extends Object> ids = null;
if (group.getContainer() != null)
ids = group.getContainer().getContainerPropertyIds();
else if (group.getItemDataSource() != null)
ids = group.getItemDataSource().getItemPropertyIds();
Preconditions.checkNotNull(ids,
"The group must have either a Container or an ItemDataSource attached.");
Preconditions.checkState(ids.contains(field),
field + " is not valid, valid listFieldNames are " + ids.toString());
doBinding(group, field, component);
}
builderForm.addComponent(component);
return component;
}
public EntityFieldBuilder<L> useLazyContainer()
{
container = new JpaBaseDao<L, Long>(listClazz).createLazyQueryContainer();
return this;
}
public EntityFieldBuilder<L> setContainer(JPAContainer<L> container)
{
this.container = container;
return this;
}
public EntityFieldBuilder<L> setContainer(EntityContainer<L> container)
{
this.container = container;
return this;
}
public EntityFieldBuilder<L> setForm(AbstractLayout form)
{
this.builderForm = form;
return this;
}
public EntityFieldBuilder<L> setLabel(String label)
{
this.label = label;
return this;
}
public EntityFieldBuilder<L> setComponent(ComboBox component)
{
this.component = component;
return this;
}
public EntityFieldBuilder<L> setField(SingularAttribute<E, L> field)
{
this.field = field.getName();
listClazz = field.getJavaType();
return this;
}
public EntityFieldBuilder<L> setField(String field, Class<L> listClazz)
{
this.field = field;
this.listClazz = listClazz;
return this;
}
public EntityFieldBuilder<L> setListFieldName(SingularAttribute<L, ?> listField)
{
this.listField = listField.getName();
return this;
}
public EntityFieldBuilder<L> setField(String field)
{
this.field = field;
return this;
}
public EntityFieldBuilder<L> setListFieldName(String listField)
{
this.listField = listField;
return this;
}
public EntityFieldBuilder<L> setListClass(Class<L> listClazz)
{
Preconditions.checkState(this.listClazz == null,
"As you have set the field as a singularAttribute, the listClass is set automatically so there is no need to call setListClass.");
this.listClazz = listClazz;
return this;
}
@SuppressWarnings("unchecked")
public JPAContainer<L> getContainer()
{
return (JPAContainer<L>) container;
}
}
/**
* use this syntax to instance the builder:<br>
* formHelper.new EntityFieldBuilder<{name of list class}>(); <br>
* <br>
* for example<br>
* <br>
*
* FormHelper<TblAdvertisementSize> helper = new
* FormHelper<TblAdvertisementSize>(...);<br>
* <br>
* ListSelect sections = helper.new ListSelectBuilder<TblSection>()<br>
* .setLabel("Sections")<br>
* .setField(TblAdvertisementSize_.tblSections)<br>
* .setListFieldName("name")<br>
* .setMultiSelect(true)<br>
* .build(); <br>
*
* @author bhorvath
*
* @param <L>
* the type of the list class
*/
public class ListSelectBuilder<L>
{
private SplitListSelect component = null;
private String label = null;
private JPAContainer<L> container = null;
private Class<L> listClazz;
private String listField;
private String field;
private AbstractLayout builderForm;
private boolean multiSelect = false;
@SuppressWarnings({ "unchecked", "rawtypes" })
public SplitListSelect build()
{
Preconditions.checkNotNull(label, "label may not be null");
Preconditions.checkNotNull(listField, "colField Property may not be null");
if (builderForm == null)
{
builderForm = form;
}
Preconditions.checkNotNull(builderForm, "Form may not be null");
if (component == null)
{
component = new SplitListSelect(label);
}
component.setCaption(label);
component.setItemCaptionMode(ItemCaptionMode.PROPERTY);
component.setItemCaptionPropertyId(listField);
if (container == null)
{
Preconditions.checkNotNull(listClazz, "listClazz may not be null");
container = JpaBaseDao.getGenericDao(listClazz).createVaadinContainer();
}
Preconditions.checkState(container.getContainerPropertyIds().contains(listField), listField
+ " is not valid, valid listFields are " + container.getContainerPropertyIds().toString());
if (container.getSortableContainerPropertyIds().contains(listField))
container.sort(new String[] { listField }, new boolean[] { true });
component.setContainerDataSource(container);
if (this.multiSelect == true)
{
component.setConverter(new MultiSelectConverter(component, Set.class));
component.setMultiSelect(true);
}
else
{
SingleSelectConverter<L> converter = new SingleSelectConverter<>(component);
component.setConverter(converter);
}
component.setWidth("100%");
component.setImmediate(true);
component.setNullSelectionAllowed(false);
component.setId(label.replace(" ", ""));
if (group != null && field != null)
{
Preconditions.checkState(group.getContainer().getContainerPropertyIds().contains(field),
field + " is not valid, valid listFieldNames are "
+ group.getContainer().getContainerPropertyIds().toString());
doBinding(group, field, component);
}
builderForm.addComponent(component);
return component;
}
public ListSelectBuilder<L> setMultiSelect(boolean multiSelect)
{
this.multiSelect = multiSelect;
return this;
}
public ListSelectBuilder<L> setLabel(String label)
{
this.label = label;
return this;
}
public ListSelectBuilder<L> setField(SingularAttribute<E, L> field)
{
this.field = field.getName();
listClazz = field.getBindableJavaType();
return this;
}
public ListSelectBuilder<L> setField(SetAttribute<E, L> field)
{
this.field = field.getName();
listClazz = field.getBindableJavaType();
return this;
}
/**
* Sets the field to display from the List entity.
*
* @param colField
* @return
*/
public ListSelectBuilder<L> setListFieldName(SingularAttribute<L, ?> colField)
{
this.listField = colField.getName();
return this;
}
public ListSelectBuilder<L> setListFieldName(String colField)
{
this.listField = colField;
return this;
}
public ListSelectBuilder<L> setContainer(JPAContainer<L> container)
{
this.container = container;
return this;
}
public ListSelectBuilder<L> setForm(AbstractLayout form)
{
this.builderForm = form;
return this;
}
public ListSelectBuilder<L> setComponent(SplitListSelect component)
{
this.component = component;
return this;
}
public ListSelectBuilder<L> setListClass(Class<L> listClazz)
{
Preconditions.checkState(this.listClazz == null,
"If you set the field as a singularAttribute, the listClass is set automatically.");
this.listClazz = listClazz;
return this;
}
}
/**
* use this syntax to instance the builder:<br>
* The formhelper must be an Entity with an attribute containing a Set of
* items that will be selected.
*
* formHelper.new EntityFieldBuilder<{class name of the items in the
* list}>(); <br>
* <br>
* If you need to filter the set of available items then you must explicity
* set the list container and filter it.
*
* for example<br>
* <br>
*
* FormHelper<TblAdvertisementSize> helper = new
* FormHelper<TblAdvertisementSize>(...);<br>
* <br>
* TwinColSelect sections = helper.new
* TwinColSelectBuilder<TblSection>()<br>
* .setLabel("Sections")<br>
* .setField(TblAdvertisementSize_.tblSections)<br>
* .setListFieldName("name")<br>
* .setLeftColumnCaption("Available") .setRightColumnCaption("Selected")
* .build(); <br>
*
* @author bhorvath
*
* @param <L>
* the type of the list class
*/
public class TwinColSelectBuilder<L extends CrudEntity>
{
private SplitTwinColSelect component = null;
private String label = null;
private Container container = null;
private Class<L> listClazz;
private String listField;
private String field;
private AbstractLayout builderForm;
private String leftColumnCaption = "Available";
private String rightColumnCaption = "Selected";
@SuppressWarnings({ "unchecked", "rawtypes" })
public SplitTwinColSelect build()
{
Preconditions.checkNotNull(label, "label may not be null");
Preconditions.checkNotNull(listField, "colField Property may not be null");
Preconditions.checkArgument(group == null || field != null, "Field may not be null");
if (builderForm == null)
{
builderForm = form;
}
Preconditions.checkNotNull(builderForm, "Form may not be null");
if (component == null)
{
component = new SplitTwinColSelect(label);
}
component.setCaption(label);
component.setItemCaptionMode(ItemCaptionMode.PROPERTY);
component.setItemCaptionPropertyId(listField);
component.setLeftColumnCaption(leftColumnCaption);
component.setRightColumnCaption(rightColumnCaption);
if (container == null)
{
Preconditions.checkNotNull(listClazz, "listClazz may not be null");
container = JpaBaseDao.getGenericDao(listClazz).createVaadinContainer();
}
Preconditions.checkState(container.getContainerPropertyIds().contains(listField), listField
+ " is not valid, valid listFields are " + container.getContainerPropertyIds().toString());
ContainerAdaptor<L> adaptor = ContainerAdaptorFactory.getAdaptor(container);
if (adaptor.getSortableContainerPropertyIds().contains(listField))
adaptor.sort(new String[] { listField }, new boolean[] { true });
component.setContainerDataSource(container);
component.setConverter(new MultiSelectConverter(component, Set.class));
component.setWidth("100%");
component.setId(label.replace(" ", ""));
component.setImmediate(true);
component.setNullSelectionAllowed(true);
component.setBuffered(true);
addValueChangeListeners(component);
if (group != null)
{
Preconditions.checkState(group.getContainer().getContainerPropertyIds().contains(field),
field + " is not valid, valid listFieldNames are "
+ group.getContainer().getContainerPropertyIds().toString());
doBinding(group, field, component);
}
builderForm.addComponent(component);
return component;
}
/**
* label that will appear next to the component on the screen
*
* @param label
* @return
*/
public TwinColSelectBuilder<L> setLabel(String label)
{
this.label = label;
return this;
}
public TwinColSelectBuilder<L> setLeftColumnCaption(String leftColumnCaption)
{
this.leftColumnCaption = leftColumnCaption;
return this;
}
public TwinColSelectBuilder<L> setRightColumnCaption(String rightColumnCaption)
{
this.rightColumnCaption = rightColumnCaption;
return this;
}
/**
* the set in the parent table that holds the set of children
*
* @param field
* @return
*/
public TwinColSelectBuilder<L> setField(SetAttribute<E, L> field)
{
this.field = field.getName();
listClazz = field.getBindableJavaType();
return this;
}
public TwinColSelectBuilder<L> setListFieldName(SingularAttribute<L, ?> colField)
{
this.listField = colField.getName();
return this;
}
public TwinColSelectBuilder<L> setListFieldName(String colField)
{
this.listField = colField;
return this;
}
/**
* Set the list container of available items. A container will normally
* be generated automatically based on the List class <L>. However if
* you need to filter the list of available items you will need to
* provide your own container which is filtered.
*
* @param container
* @return
*/
public TwinColSelectBuilder<L> setContainer(JPAContainer<L> container)
{
this.container = container;
return this;
}
public TwinColSelectBuilder<L> setContainer(EntityContainer<L> container)
{
this.container = container;
return this;
}
public TwinColSelectBuilder<L> setForm(AbstractLayout form)
{
this.builderForm = form;
return this;
}
public TwinColSelectBuilder<L> setComponent(SplitTwinColSelect component)
{
this.component = component;
return this;
}
public TwinColSelectBuilder<L> setListClass(Class<L> listClazz)
{
Preconditions.checkState(this.listClazz == null,
"If you set the field as a singularAttribute, the listClass is set automatically.");
this.listClazz = listClazz;
return this;
}
public TwinColSelectBuilder<L> useLazyContainer()
{
container = new JpaBaseDao<L, Long>(listClazz).createLazyQueryContainer();
return this;
}
}
public <M> CKEditorEmailField bindEditorField(AbstractLayout form, ValidatingFieldGroup<E> group,
SingularAttribute<E, M> member, boolean readonly)
{
CKEditorEmailField field = bindEditorField(form, group, member.getName(), readonly);
this.fieldList.add(field);
return field;
}
public <M> CKEditorEmailField bindEditorField(String fieldLabel, SingularAttribute<E, M> member, boolean readonly)
{
CKEditorEmailField field = bindEditorField(form, group, member.getName(), readonly);
this.fieldList.add(field);
return field;
}
public CKEditorEmailField bindEditorField(String fieldName, boolean readonly)
{
CKEditorEmailField field = bindEditorField(form, group, fieldName, readonly);
this.fieldList.add(field);
return field;
}
public CKEditorEmailField bindEditorField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldName,
boolean readonly)
{
SplitEditorField field = new SplitEditorField(readonly);
field.setWidth("100%");
field.setImmediate(true);
addValueChangeListeners(field);
doBinding(group, fieldName, field);
form.addComponent(field);
return field;
}
// public <L> EntityAutoCompleteField
// bindAutoCompleteField(AutoCompleteParent<E> parent,
// String fieldLabel, ListAttribute<E, L> entityField, Class<L> listClazz)
// {
// // hack
// ContactDao dao = new DaoFactory().getContactDao();
// container = dao.createVaadinContainer();
//
// //EntityAutoCompleteField<CrudEntity, JpaBaseDao<E,Long>> field = new
// EntityAutoCompleteField<CrudEntity, JpaBaseDao<E,Long>>(container, dao,
// fieldLabel, parent);
// EntityAutoCompleteField field = new EntityAutoCompleteField<CrudEntity,
// JpaBaseDao(container, dao, fieldLabel, parent);
// return field;
//
// }
// public <L> EntityAutoCompleteField
// bindAutoCompleteField(AutoCompleteParent<E> parent,
// String fieldLabel, ListAttribute<E, L> entityField, Class<L> listClazz)
// {
// // hack
// ContactDao dao = new DaoFactory().getContactDao();
// container = dao.createVaadinContainer();
//
// //EntityAutoCompleteField<CrudEntity, JpaBaseDao<E,Long>> field = new
// EntityAutoCompleteField<CrudEntity, JpaBaseDao<E,Long>>(container, dao,
// fieldLabel, parent);
// EntityAutoCompleteField field = new EntityAutoCompleteField<CrudEntity,
// JpaBaseDao(container, dao, fieldLabel, parent);
// return field;
//
// }
public static Container createContainerFromEnumClass(String fieldName, Class<?> clazz)
{
LinkedHashMap<Enum<?>, String> enumMap = new LinkedHashMap<>();
for (Object enumConstant : clazz.getEnumConstants())
{
enumMap.put((Enum<?>) enumConstant, enumConstant.toString());
}
return createContainerFromMap(fieldName, enumMap);
}
@SuppressWarnings("unchecked")
static public IndexedContainer createContainerFromMap(String fieldName, Map<?, String> hashMap)
{
IndexedContainer container = new IndexedContainer();
container.addContainerProperty(fieldName, String.class, "");
Iterator<?> iter = hashMap.keySet().iterator();
while (iter.hasNext())
{
Object itemId = iter.next();
container.addItem(itemId);
container.getItem(itemId).getItemProperty(fieldName).setValue(hashMap.get(itemId));
}
return container;
}
static public <Q extends CrudEntity> Container createContainerFromEntities(String fieldName, Collection<Q> list)
{
LinkedHashMap<Q, String> enumMap = new LinkedHashMap<>();
List<Q> sortedList = new LinkedList<>();
sortedList.addAll(list);
Collections.sort(sortedList, new Comparator<Q>()
{
@Override
public int compare(Q arg0, Q arg1)
{
return arg0.getName().compareToIgnoreCase(arg1.getName());
}
});
for (Q value : sortedList)
{
enumMap.put(value, value.getName());
}
return createContainerFromMap(fieldName, enumMap);
}
public ArrayList<AbstractComponent> getFieldList()
{
return this.fieldList;
}
public static void showConstraintViolation(ConstraintViolationException e)
{
// build constraint error
StringBuilder sb = new StringBuilder();
for (ConstraintViolation<?> violation : e.getConstraintViolations())
{
sb.append("Error: " + violation.getPropertyPath() + " : " + violation.getMessage() + "\n");
}
logger.error(sb.toString());
Notification.show(sb.toString(), Type.ERROR_MESSAGE);
}
protected AbstractLayout getForm()
{
return form;
}
protected ValidatingFieldGroup<E> getFieldGroup()
{
return this.group;
}
public <M> DataBoundButton<M> bindButtonField(String fieldLabel, SingularAttribute<E, M> enterScript, Class<M> type)
{
return bindButtonField(fieldLabel, enterScript.getName(), type);
}
public <M> DataBoundButton<M> bindButtonField(String fieldLabel, String fieldName, Class<M> type)
{
DataBoundButton<M> field = bindButtonField(form, group, fieldLabel, fieldName, type);
this.fieldList.add(field);
return field;
}
public <M> DataBoundButton<M> bindButtonField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldLabel,
String fieldName, Class<M> type)
{
DataBoundButton<M> field = new DataBoundButton<>(fieldLabel, type);
field.setImmediate(true);
doBinding(group, fieldName, field);
form.addComponent(field);
return field;
}
public CKEditorEmailField bindEditorField(AbstractLayout form, ValidatingFieldGroup<E> group, String fieldName,
boolean readonly, ConfigModifier configModifier)
{
SplitEditorField field = new SplitEditorField(readonly, configModifier);
field.setWidth("100%");
field.setImmediate(true);
addValueChangeListeners(field);
doBinding(group, fieldName, field);
form.addComponent(field);
return field;
}
public <EN> ComboBox bindEnumField(String fieldLabel, SingularAttribute<E, EN> fieldName)
{
return bindEnumField(fieldLabel, fieldName.getName(), fieldName.getBindableJavaType());
}
public <J extends CrudEntity> FormHelper<E>.EntityFieldBuilder<J> getEntityFieldBuilder(Class<J> j)
{
return new EntityFieldBuilder<>();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
static public <J extends CrudEntity> FormHelper<?>.ListSelectBuilder<J> getListSelectBuilder(AbstractLayout form,
Class<J> j)
{
FormHelper<?> helper = new FormHelper(form, null);
return helper.new ListSelectBuilder<J>().setListClass(j);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
static public <J extends CrudEntity> FormHelper<?>.EntityFieldBuilder<J> getEntityFieldBuilder(AbstractLayout form,
Class<J> j)
{
FormHelper<?> helper = new FormHelper(form, null);
return helper.new EntityFieldBuilder<J>().setListClass(j);
}
public <J extends CrudEntity> FormHelper<E>.TwinColSelectBuilder<J> getTwinColSelectBuilder(Class<J> j)
{
return new TwinColSelectBuilder<>();
}
public void addComponent(Component component)
{
form.addComponent(component);
}
}