All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.vaadin.viritin.fields.SubSetSelector Maven / Gradle / Ivy

package org.vaadin.viritin.fields;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

import org.vaadin.viritin.button.MButton;
import org.vaadin.viritin.form.AbstractForm;
import org.vaadin.viritin.layouts.MHorizontalLayout;
import org.vaadin.viritin.layouts.MVerticalLayout;

import com.vaadin.data.Property;
import com.vaadin.server.FontAwesome;
import com.vaadin.ui.AbstractSelect;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.CustomField;
import com.vaadin.ui.Table;
import com.vaadin.ui.Window;
import com.vaadin.ui.themes.Reindeer;
import com.vaadin.ui.themes.ValoTheme;

/**
 * Selects a set of beans from a larger set of choices. Bit similar UI component
 * as "TwinColSelect", but available options are in a combobox for easy picking,
 * and selected entries are displayed in a Table. Should work with virtually any
 * collection type - not just with sets, but same bean can be only once in the
 * collection. If a null is passed for the field value, it is "converted" into
 * and empty Set or list List.
 * 

* The component can be configured to create new entities as well on demand, * either by hitting enter with ComboBox or with a new entry form, or combined. * * @param the type of items in from which the selection is build */ @SuppressWarnings({"rawtypes", "serial", "unchecked"}) public class SubSetSelector extends CustomField implements AbstractForm.SavedHandler, AbstractForm.ResetHandler { private Class type; private TypedSelect cb; private MTable table; private Collection selected; private Button newInstanceBtn; private final Class elementType; private MHorizontalLayout toprow; private MVerticalLayout verticalLayout; private AbstractForm newInstanceForm; private List availableOptions; private int limit = Integer.MAX_VALUE; public SubSetSelector(Class elementType) { this.elementType = elementType; cb = new TypedSelect<>(elementType).withSelectType(ComboBox.class); table = new MTable<>(elementType).withFullWidth(); setHeight("300px"); toprow = new MHorizontalLayout(cb); verticalLayout = new MVerticalLayout(toprow).expand(table); table.setPageLength(5); table.withGeneratedColumn("Remove", new MTable.SimpleColumnGenerator() { @Override public Object generate(final ET entity) { return getToolColumnContent(entity); } }); table.setColumnHeader("Remove", ""); cb.setInputPrompt("Add to selection..."); cb.addValueChangeListener(new ValueChangeListener() { @Override public void valueChange( com.vaadin.data.Property.ValueChangeEvent event) { if (event.getProperty().getValue() != null) { Object pojo = event.getProperty().getValue(); cb.getBic().removeItem(pojo); cb.setValue(null); table.addItem(pojo); selected.add(pojo); cb.setEnabled(selected.size() < limit); // fire value change fireValueChange(true); } } }); } /** * Generates the tool cell content in the listing of selected items. By * default contains button to remove selection. Overridden implementation * can add other stuff there as well, like edit button. * * @param entity the entity for which the cell content is created * @return the content (String or Component) */ protected Object getToolColumnContent(final ET entity) { Button button = new Button(FontAwesome.MINUS); button.setDescription("Removes the selection from the list"); button.addStyleName(ValoTheme.BUTTON_ICON_ONLY); button.addClickListener(new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { removeSelectedOption(entity); } }); button.setStyleName(Reindeer.BUTTON_SMALL); return button; } /** * @param entity the entity to be removed from the selection */ public void removeSelectedOption(ET entity) { cb.addOption(entity); table.removeItem(entity); selected.remove(entity); cb.setEnabled(selected.size() < limit); // fire value change fireValueChange(true); } public String getAddInputPrompt() { return ((ComboBox) cb.getSelect()).getInputPrompt(); } public void setAddInputPrompt(String inputPrompt) { cb.setInputPrompt(inputPrompt); } /** * Sets a form which can be used to add new items to the selection. A button * to add new instances is displayed if this method is called. * * @param newInstanceForm the form */ public void setNewInstanceForm(AbstractForm newInstanceForm) { this.newInstanceForm = newInstanceForm; if (newInstanceForm != null) { if (newInstanceBtn == null) { newInstanceBtn = new MButton(FontAwesome.PLUS).withStyleName(ValoTheme.BUTTON_ICON_ONLY); newInstanceBtn.addClickListener(new Button.ClickListener() { @Override public void buttonClick(ClickEvent clickEvent) { addEntity(null); } }); toprow.add(newInstanceBtn); } } else if (newInstanceBtn != null) { toprow.removeComponent(newInstanceBtn); newInstanceBtn = null; } } public AbstractForm getNewInstanceForm() { return newInstanceForm; } protected String getDeleteButtonCaption() { return "-"; } /** * @param headers the headers to be used for the table containing the * selected items in the display order of the columns * @see Table#setColumnHeaders(String[]) */ public void setColumnHeaders(String... headers) { table.setColumnHeaders(headers); } /** * @param propertyId the id of the property whose columen header is to be * set * @param header the columen header * @see Table#setColumnHeader(Object, String) */ public void setColumnHeader(Object propertyId, String header) { table.setColumnHeader(propertyId, header); } /** * @return the reference to the Table used by this field internally. * Modifying this object directly might cause odd behavior. */ public MTable getTable() { return table; } protected void addEntity(String stringInput) { final ET newInstance = instantiateOption(stringInput); if (newInstanceForm != null) { String caption = "Add new " + elementType.getSimpleName(); newInstanceForm.setEntity(newInstance); newInstanceForm.setSavedHandler(this); newInstanceForm.setResetHandler(this); Window w = newInstanceForm.openInModalPopup(); w.setWidth("70%"); w.setCaption(caption); } else { onSave(newInstance); } } protected ET instantiateOption(String stringInput) { try { return elementType.getConstructor().newInstance(); } catch (IllegalAccessException | IllegalArgumentException | InstantiationException | NoSuchMethodException | SecurityException | InvocationTargetException e) { throw new RuntimeException(e); } } @Override public Class getType() { return (Class) type; } /** * @param options the list of options from which the sub set is selected * @return this */ public SubSetSelector setOptions(List options) { availableOptions = options; cb.setOptions(new ArrayList<>(options)); return this; } @Override public void setPropertyDataSource(Property newDataSource) { if (newDataSource != null) { type = newDataSource.getType(); } super.setPropertyDataSource(newDataSource); } @Override protected void setInternalValue(Collection newValue) { selected = newValue; if (selected == null) { Class clazz = getType(); if (clazz != null && List.class.isAssignableFrom(clazz)) { selected = new ArrayList(); } else { selected = new HashSet(); } setValue(selected); return; } final ArrayList arrayList = new ArrayList<>(availableOptions); arrayList.removeAll(selected); cb.setOptions(arrayList); cb.getBic().fireItemSetChange(); cb.setEnabled(selected.size() < limit); table.setBeans(new ArrayList(selected)); super.setInternalValue(newValue); } @Override protected void fireValueChange(boolean repaintIsNotNeeded) { super.fireValueChange(repaintIsNotNeeded); } public void setVisibleProperties(String... visible) { List a = new ArrayList(Arrays.asList(visible)); a.add("Remove"); table.withProperties(a); table.setColumnHeader("Remove", ""); } public String getNewEntityCaption() { return newInstanceBtn.getCaption(); } public void setNewEntityCaption(String newEntityCaption) { newInstanceBtn.setCaption(newEntityCaption); } @Override protected Component initContent() { return verticalLayout; } public void setCaptionGenerator(CaptionGenerator cg) { cb.setCaptionGenerator(cg); } @Override public void onSave(ET entity) { // TODO, figure out something here, needs a listener/handler // getProvider().persist(elementType, newInstance); table.addItem(entity); selected.add(entity); /* * Here we check the table for limit because the added entity could be equal to another added previously. * Since the table has a list container and selected has a map, they do not have the same behavior for equality. */ cb.setEnabled(table.size() < limit); if (newInstanceForm != null) { newInstanceForm.closePopup(); } // fire value change fireValueChange(true); } @Override public void onReset(ET entity) { newInstanceForm.closePopup(); } /** * With this method users can be allowed to add new entities directly via * the combobox used to select entities from the existing set. *

* Developer can decide what to do with the input string, by overriding the * instantiateOption method. Also override onSave method if you need to do * something specific with new entities (e.g. save to persistency context * and pass the persisted instance to the default action that adds it to * select and available options). *

* If a newInstanceForm is set, the created the entity is then shown for * further editing in the form. * * @param allowAddingNewItems true if hitting enter without suggestions * should add a new item. */ public void setNewItemsAllowed(boolean allowAddingNewItems) { cb.getSelect().setNewItemsAllowed(allowAddingNewItems); if (allowAddingNewItems) { cb.getSelect().setNewItemHandler(new AbstractSelect.NewItemHandler() { @Override public void addNewItem(String s) { addEntity(s); } }); } else { cb.getSelect().setNewItemHandler(null); } } public int getLimit() { return limit; } /** * Sets the limit of elements added to the SubSetSelector. Setting the limit * or adding elements will trigger the combo box availability. * * @param limit the maximum number of selected elements (collection size) */ public void setLimit(int limit) { if (limit < 0) { this.limit = Integer.MAX_VALUE; } else { this.limit = limit; } cb.setEnabled(selected.size() < limit); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy