package org.aperteworkflow.view.impl.history;
import com.vaadin.data.Container;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.Validator.InvalidValueException;
import com.vaadin.event.LayoutEvents.LayoutClickEvent;
import com.vaadin.event.LayoutEvents.LayoutClickListener;
import com.vaadin.ui.*;
import org.aperteworkflow.util.vaadin.ui.AligningHorizontalLayout;
import org.aperteworkflow.util.vaadin.ui.OrderedLayoutFactory;
import org.vaadin.addon.customfield.CustomField;
import org.vaadin.hene.flexibleoptiongroup.FlexibleOptionGroup;
import org.vaadin.hene.flexibleoptiongroup.FlexibleOptionGroupItemComponent;
import pl.net.bluesoft.util.lang.Transformer;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* @author: amichalak@bluesoft.net.pl
*/
public class ConfigurableOptionGroupField<T> extends CustomField implements Container {
private FlexibleOptionGroup optionGroup;
private Transformer<T, String> itemCaptionResolver;
private OrderedLayoutFactory layoutFactory;
private ItemComponentGenerator<T> componentGenerator;
private Map<T, Component> generatedComponentsMap;
private boolean disableOthersOnChange = true;
public ConfigurableOptionGroupField(Collection<T> collection, Transformer<T, String> itemCaptionResolver, ItemComponentGenerator<T> componentGenerator,
Boolean multiSelect) {
this.itemCaptionResolver = itemCaptionResolver;
this.optionGroup = new FlexibleOptionGroup(collection);
this.componentGenerator = componentGenerator != null ? componentGenerator : new DefaultItemComponentGenerator<T>();
if (multiSelect != null) {
setMultiSelect(multiSelect);
}
this.optionGroup.setImmediate(true);
this.optionGroup.addListener(new ValueChangeListener() {
@Override
public void valueChange(Property.ValueChangeEvent event) {
disableOthersOnChange(event.getProperty().getValue());
}
});
}
private void disableOthersOnChange(Object value) {
if (!(value instanceof Collection) && value != null) {
if (disableOthersOnChange) {
for (T itemId : generatedComponentsMap.keySet()) {
generatedComponentsMap.get(itemId).setEnabled(itemId.equals(value));
}
}
}
}
public ConfigurableOptionGroupField(Collection<T> collection, Transformer<T, String> itemCaptionResolver, ItemComponentGenerator<T> componentGenerator) {
this(collection, itemCaptionResolver, componentGenerator, null);
}
public ConfigurableOptionGroupField(Collection<T> collection) {
this(collection, null, null);
}
protected AbstractOrderedLayout createLayout() {
return layoutFactory != null ? layoutFactory.create() : new AligningHorizontalLayout(Alignment.MIDDLE_LEFT);
}
public ConfigurableOptionGroupField<T> setMultiSelect(boolean multiSelect) {
this.optionGroup.setMultiSelect(multiSelect);
this.disableOthersOnChange = !multiSelect;
return this;
}
public ConfigurableOptionGroupField<T> setItemCaptionResolver(Transformer<T, String> itemCaptionResolver) {
this.itemCaptionResolver = itemCaptionResolver;
return this;
}
public ConfigurableOptionGroupField<T> setItemComponentGenerator(ItemComponentGenerator<T> componentGenerator) {
this.componentGenerator = componentGenerator != null ? componentGenerator : new DefaultItemComponentGenerator<T>();
return this;
}
public ConfigurableOptionGroupField<T> setLayoutFactory(OrderedLayoutFactory layoutFactory) {
this.layoutFactory = layoutFactory;
return this;
}
public ConfigurableOptionGroupField setDisableOthersOnChange(boolean disable) {
this.disableOthersOnChange = disable;
return this;
}
@Override
public void setReadOnly(boolean readOnly) {
super.setReadOnly(readOnly);
optionGroup.setReadOnly(readOnly);
}
public void addOptionChangedListener(ValueChangeListener listener) {
optionGroup.addListener(listener);
}
public ConfigurableOptionGroupField<T> init() {
AbstractOrderedLayout layout = createLayout();
generatedComponentsMap = new HashMap<T, Component>();
for (Iterator<FlexibleOptionGroupItemComponent> it = optionGroup.getItemComponentIterator(); it.hasNext(); ) {
FlexibleOptionGroupItemComponent comp = it.next();
T itemId = (T) comp.getItemId();
Component generatedComponent = componentGenerator.generate(optionGroup, itemId, comp, itemCaptionResolver);
layout.addComponent(generatedComponent);
generatedComponentsMap.put(itemId, generatedComponent);
}
Object value = optionGroup.getValue();
if (!optionGroup.isMultiSelect()) {
Collection<?> itemIds = optionGroup.getContainerDataSource().getItemIds();
if (value != null && itemIds.contains(value)) {
optionGroup.setValue(value);
}
else if (!itemIds.isEmpty()) {
optionGroup.setValue(value = itemIds.iterator().next());
}
}
disableOthersOnChange(value);
layout.addListener(createLayoutClickListener());
setCompositionRoot(layout);
return this;
}
protected LayoutClickListener createLayoutClickListener() {
return new LayoutClickListener() {
public void layoutClick(LayoutClickEvent event) {
FlexibleOptionGroupItemComponent c = null;
boolean allowUnselection = optionGroup.isMultiSelect();
if (event.getChildComponent() instanceof FlexibleOptionGroupItemComponent) {
c = (FlexibleOptionGroupItemComponent) event.getChildComponent();
}
else if (event.getChildComponent() instanceof AbstractComponent) {
Object data = ((AbstractComponent) event.getChildComponent()).getData();
if (data instanceof FlexibleOptionGroupItemComponent) {
c = (FlexibleOptionGroupItemComponent) data;
}
if (event.getChildComponent() instanceof HorizontalLayout) {
allowUnselection = false;
}
}
if (c != null) {
Object itemId = c.getItemId();
if (optionGroup.isSelected(itemId) && allowUnselection) {
optionGroup.unselect(itemId);
}
else {
optionGroup.select(itemId);
}
}
}
};
}
public static class DefaultItemComponentGenerator<T> implements ItemComponentGenerator<T> {
@Override
public Component generate(final FlexibleOptionGroup optionGroup, final T itemId,
final FlexibleOptionGroupItemComponent itemComponent,
final Transformer<T, String> itemCaptionResolver) {
final Label title = new Label(itemCaptionResolver != null ? itemCaptionResolver.transform(itemId)
: itemComponent.getCaption(), Label.CONTENT_XHTML) {{
setWidth("100%");
addStyleName("pointer");
setData(itemComponent);
}};
HorizontalLayout hl = new HorizontalLayout();
hl.addComponent(itemComponent);
hl.addComponent(title);
hl.setData(itemComponent);
return hl;
}
}
public static interface ItemComponentGenerator<T> {
Component generate(FlexibleOptionGroup optionGroup, T itemId, FlexibleOptionGroupItemComponent itemComponent,
Transformer<T, String> itemCaptionResolver);
}
@Override
public Class<?> getType() {
return Collection.class;
}
@Override
public void setTabIndex(int tabIndex) {
super.setTabIndex(tabIndex);
optionGroup.setTabIndex(tabIndex);
}
@Override
public void setPropertyDataSource(Property newDataSource) {
optionGroup.setPropertyDataSource(newDataSource);
init();
}
@Override
public Object getValue() {
return optionGroup.getValue();
}
@Override
public void setValue(Object newValue) throws ReadOnlyException, ConversionException {
optionGroup.setValue(newValue);
}
@Override
public void commit() throws SourceException, InvalidValueException {
optionGroup.commit();
}
@Override
public void discard() throws SourceException {
optionGroup.discard();
}
@Override
public Item getItem(Object itemId) {
return optionGroup.getItem(itemId);
}
@Override
public Collection<?> getContainerPropertyIds() {
return optionGroup.getContainerPropertyIds();
}
@Override
public Collection<?> getItemIds() {
return optionGroup.getItemIds();
}
@Override
public Property getContainerProperty(Object itemId, Object propertyId) {
return optionGroup.getContainerProperty(itemId, propertyId);
}
@Override
public Class<?> getType(Object propertyId) {
return optionGroup.getType(propertyId);
}
@Override
public int size() {
return optionGroup.size();
}
@Override
public boolean containsId(Object itemId) {
return optionGroup.containsId(itemId);
}
@Override
public Item addItem(Object itemId) throws UnsupportedOperationException {
return optionGroup.addItem(itemId);
}
@Override
public Object addItem() throws UnsupportedOperationException {
return optionGroup.addItem();
}
@Override
public boolean removeItem(Object itemId) throws UnsupportedOperationException {
return optionGroup.removeItem(itemId);
}
@Override
public boolean addContainerProperty(Object propertyId, Class<?> type, Object defaultValue) throws UnsupportedOperationException {
return optionGroup.addContainerProperty(propertyId, type, defaultValue);
}
@Override
public boolean removeContainerProperty(Object propertyId) throws UnsupportedOperationException {
return optionGroup.removeContainerProperty(propertyId);
}
@Override
public boolean removeAllItems() throws UnsupportedOperationException {
return optionGroup.removeAllItems();
}
}