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

com.vaadin.ui.ComboBox Maven / Gradle / Ivy

There is a newer version: 8.27.3
Show newest version
/*
 * Copyright (C) 2000-2024 Vaadin Ltd
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See  for the full
 * license.
 */

package com.vaadin.ui;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;

import com.vaadin.data.provider.CallbackDataProvider;
import com.vaadin.data.provider.DataChangeEvent;
import com.vaadin.data.provider.DataCommunicator;
import com.vaadin.data.provider.DataGenerator;
import com.vaadin.data.provider.DataKeyMapper;
import com.vaadin.data.provider.DataProvider;
import com.vaadin.data.provider.InMemoryDataProvider;
import com.vaadin.data.provider.ListDataProvider;
import org.jsoup.nodes.Element;

import com.vaadin.data.HasFilterableDataProvider;
import com.vaadin.data.HasValue;
import com.vaadin.data.ValueProvider;
import com.vaadin.event.FieldEvents;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcDecorator;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.server.ConnectorResource;
import com.vaadin.server.KeyMapper;
import com.vaadin.server.Resource;
import com.vaadin.server.ResourceReference;
import com.vaadin.server.SerializableBiPredicate;
import com.vaadin.server.SerializableConsumer;
import com.vaadin.server.SerializableFunction;
import com.vaadin.server.SerializableToIntFunction;
import com.vaadin.shared.Registration;
import com.vaadin.shared.data.DataCommunicatorConstants;
import com.vaadin.shared.ui.combobox.ComboBoxClientRpc;
import com.vaadin.shared.ui.combobox.ComboBoxConstants;
import com.vaadin.shared.ui.combobox.ComboBoxServerRpc;
import com.vaadin.shared.ui.combobox.ComboBoxState;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
import com.vaadin.ui.declarative.DesignFormatter;

import elemental.json.JsonObject;

/**
 * A filtering dropdown single-select. Items are filtered based on user input.
 * Supports the creation of new items when a handler is set by the user.
 *
 * @param 
 *            item (bean) type in ComboBox
 * @author Vaadin Ltd
 */
@SuppressWarnings("serial")
public class ComboBox extends AbstractSingleSelect
        implements FieldEvents.BlurNotifier, FieldEvents.FocusNotifier,
        HasFilterableDataProvider {

    /**
     * A callback method for fetching items. The callback is provided with a
     * non-null string filter, offset index and limit.
     *
     * @param 
     *            item (bean) type in ComboBox
     * @since 8.0
     */
    @FunctionalInterface
    public interface FetchItemsCallback extends Serializable {

        /**
         * Returns a stream of items that match the given filter, limiting the
         * results with given offset and limit.
         * 

* This method is called after the size of the data set is asked from a * related size callback. The offset and limit are promised to be within * the size of the data set. * * @param filter * a non-null filter string * @param offset * the first index to fetch * @param limit * the fetched item count * @return stream of items */ public Stream fetchItems(String filter, int offset, int limit); } /** * Handler that adds a new item based on user input when the new items * allowed mode is active. *

* NOTE 1: If the new item is rejected the client must be notified of the * fact via ComboBoxClientRpc or selection handling won't complete. *

*

* NOTE 2: Selection handling must be completed separately if filtering the * data source with the same value won't include the new item in the initial * list of suggestions. Failing to do so will lead to selection handling * never completing and previous selection remaining on the server. *

* * @since 8.0 * @deprecated Since 8.4 replaced by {@link NewItemProvider}. */ @Deprecated @FunctionalInterface public interface NewItemHandler extends SerializableConsumer { } /** * Provider function that adds a new item based on user input when the new * items allowed mode is active. After the new item handling is complete, * this function should return {@code Optional.of(text)} for the completion * of automatic selection handling. If automatic selection is not wished * for, always return {@code Optional.isEmpty()}. * * @since 8.4 */ @FunctionalInterface public interface NewItemProvider extends SerializableFunction> { } /** * Item style generator class for declarative support. *

* Provides a straightforward mapping between an item and its style. * * @param * item type * @since 8.0 */ protected static class DeclarativeStyleGenerator implements StyleGenerator { private StyleGenerator fallback; private Map styles = new HashMap<>(); public DeclarativeStyleGenerator(StyleGenerator fallback) { this.fallback = fallback; } @Override public String apply(T item) { return styles.containsKey(item) ? styles.get(item) : fallback.apply(item); } /** * Sets a {@code style} for the {@code item}. * * @param item * a data item * @param style * a style for the {@code item} */ protected void setStyle(T item, String style) { styles.put(item, style); } } private ComboBoxServerRpc rpc = new ComboBoxServerRpc() { @Override public void createNewItem(String itemValue) { // New option entered boolean added = false; if (itemValue != null && !itemValue.isEmpty()) { if (getNewItemProvider() != null) { Optional item = getNewItemProvider().apply(itemValue); added = item.isPresent(); // Fixes issue // https://github.com/vaadin/framework/issues/11343 // Update the internal selection state immediately to avoid // client side hanging. This is needed for cases that user // interaction fires multi events (like adding and deleting) // on a new item during the same round trip. item.ifPresent(value -> { setSelectedItem(value, true); getDataCommunicator().reset(); }); } else if (getNewItemHandler() != null) { getNewItemHandler().accept(itemValue); // Up to the user to tell if no item was added. added = true; } } if (!added) { // New item was not handled. getRpcProxy(ComboBoxClientRpc.class).newItemNotAdded(itemValue); } } @Override public void setFilter(String filterText) { getState().currentFilterText = filterText; filterSlot.accept(filterText); } @Override public void resetForceDataSourceUpdate() { getState().forceDataSourceUpdate = false; } }; /** * Handler for new items entered by the user. */ @Deprecated private NewItemHandler newItemHandler; /** * Provider function for new items entered by the user. */ private NewItemProvider newItemProvider; private StyleGenerator itemStyleGenerator = item -> null; private SerializableConsumer filterSlot = filter -> { // Just ignore when neither setDataProvider nor setItems has been called }; private Registration dataProviderListener = null; /** * Constructs an empty combo box without a caption. The content of the combo * box can be set with {@link #setDataProvider(DataProvider)} or * {@link #setItems(Collection)} */ public ComboBox() { this(new DataCommunicator() { @Override protected DataKeyMapper createKeyMapper( ValueProvider identifierGetter) { return new KeyMapper(identifierGetter) { @Override public void remove(T removeobj) { // never remove keys from ComboBox to support selection // of items that are not currently visible } }; } }); } /** * Constructs an empty combo box, whose content can be set with * {@link #setDataProvider(DataProvider)} or {@link #setItems(Collection)}. * * @param caption * the caption to show in the containing layout, null for no * caption */ public ComboBox(String caption) { this(); setCaption(caption); } /** * Constructs a combo box with a static in-memory data provider with the * given options. * * @param caption * the caption to show in the containing layout, null for no * caption * @param options * collection of options, not null */ public ComboBox(String caption, Collection options) { this(caption); setItems(options); } /** * Constructs and initializes an empty combo box. * * @param dataCommunicator * the data comnunicator to use with this ComboBox * @since 8.5 */ protected ComboBox(DataCommunicator dataCommunicator) { super(dataCommunicator); init(); } /** * Initialize the ComboBox with default settings and register client to * server RPC implementation. */ private void init() { registerRpc(rpc); registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent)); addDataGenerator(new DataGenerator() { /** * Map for storing names for icons. */ private Map resourceKeyMap = new HashMap<>(); private int counter = 0; @Override public void generateData(T item, JsonObject jsonObject) { String caption = getItemCaptionGenerator().apply(item); if (caption == null) { caption = ""; } jsonObject.put(DataCommunicatorConstants.NAME, caption); String style = itemStyleGenerator.apply(item); if (style != null) { jsonObject.put(ComboBoxConstants.STYLE, style); } Resource icon = getItemIcon(item); if (icon != null) { String iconKey = resourceKeyMap .get(getDataProvider().getId(item)); String iconUrl = ResourceReference .create(icon, ComboBox.this, iconKey).getURL(); jsonObject.put(ComboBoxConstants.ICON, iconUrl); } } @Override public void destroyData(T item) { Object itemId = getDataProvider().getId(item); if (resourceKeyMap.containsKey(itemId)) { setResource(resourceKeyMap.get(itemId), null); resourceKeyMap.remove(itemId); } } private Resource getItemIcon(T item) { Resource icon = getItemIconGenerator().apply(item); if (icon == null || !(icon instanceof ConnectorResource)) { return icon; } Object itemId = getDataProvider().getId(item); if (!resourceKeyMap.containsKey(itemId)) { resourceKeyMap.put(itemId, "icon" + (counter++)); } setResource(resourceKeyMap.get(itemId), icon); return icon; } }); } /** * {@inheritDoc} *

* Filtering will use a case insensitive match to show all items where the * filter text is a substring of the caption displayed for that item. */ @Override public void setItems(Collection items) { ListDataProvider listDataProvider = DataProvider.ofCollection(items); setDataProvider(listDataProvider); } /** * {@inheritDoc} *

* Filtering will use a case insensitive match to show all items where the * filter text is a substring of the caption displayed for that item. */ @Override public void setItems(Stream streamOfItems) { // Overridden only to add clarification to javadocs super.setItems(streamOfItems); } /** * {@inheritDoc} *

* Filtering will use a case insensitive match to show all items where the * filter text is a substring of the caption displayed for that item. */ @Override public void setItems(T... items) { // Overridden only to add clarification to javadocs super.setItems(items); } /** * Sets a list data provider as the data provider of this combo box. * Filtering will use a case insensitive match to show all items where the * filter text is a substring of the caption displayed for that item. *

* Note that this is a shorthand that calls * {@link #setDataProvider(DataProvider)} with a wrapper of the provided * list data provider. This means that {@link #getDataProvider()} will * return the wrapper instead of the original list data provider. * * @param listDataProvider * the list data provider to use, not null * @since 8.0 */ public void setDataProvider(ListDataProvider listDataProvider) { // Cannot use the case insensitive contains shorthand from // ListDataProvider since it wouldn't react to locale changes CaptionFilter defaultCaptionFilter = (itemText, filterText) -> itemText .toLowerCase(getLocale()) .contains(filterText.toLowerCase(getLocale())); setDataProvider(defaultCaptionFilter, listDataProvider); } /** * Sets the data items of this listing and a simple string filter with which * the item string and the text the user has input are compared. *

* Note that unlike {@link #setItems(Collection)}, no automatic case * conversion is performed before the comparison. * * @param captionFilter * filter to check if an item is shown when user typed some text * into the ComboBox * @param items * the data items to display * @since 8.0 */ public void setItems(CaptionFilter captionFilter, Collection items) { ListDataProvider listDataProvider = DataProvider.ofCollection(items); setDataProvider(captionFilter, listDataProvider); } /** * Sets a list data provider with an item caption filter as the data * provider of this combo box. The caption filter is used to compare the * displayed caption of each item to the filter text entered by the user. * * @param captionFilter * filter to check if an item is shown when user typed some text * into the ComboBox * @param listDataProvider * the list data provider to use, not null * @since 8.0 */ public void setDataProvider(CaptionFilter captionFilter, ListDataProvider listDataProvider) { Objects.requireNonNull(listDataProvider, "List data provider cannot be null"); // Must do getItemCaptionGenerator() for each operation since it might // not be the same as when this method was invoked setDataProvider(listDataProvider, filterText -> item -> captionFilter .test(getItemCaptionOfItem(item), filterText)); } // Helper method for the above to make lambda more readable private String getItemCaptionOfItem(T item) { String caption = getItemCaptionGenerator().apply(item); if (caption == null) { caption = ""; } return caption; } /** * Sets the data items of this listing and a simple string filter with which * the item string and the text the user has input are compared. *

* Note that unlike {@link #setItems(Collection)}, no automatic case * conversion is performed before the comparison. * * @param captionFilter * filter to check if an item is shown when user typed some text * into the ComboBox * @param items * the data items to display * @since 8.0 */ public void setItems(CaptionFilter captionFilter, @SuppressWarnings("unchecked") T... items) { setItems(captionFilter, Arrays.asList(items)); } /** * Gets the current placeholder text shown when the combo box would be * empty. * * @see #setPlaceholder(String) * @return the current placeholder string, or null if not enabled * @since 8.0 */ public String getPlaceholder() { return getState(false).placeholder; } /** * Sets the placeholder string - a textual prompt that is displayed when the * select would otherwise be empty, to prompt the user for input. * * @param placeholder * the desired placeholder, or null to disable * @since 8.0 */ public void setPlaceholder(String placeholder) { getState().placeholder = placeholder; } /** * Sets whether it is possible to input text into the field or whether the * field area of the component is just used to show what is selected. By * disabling text input, the comboBox will work in the same way as a * {@link NativeSelect} * * @see #isTextInputAllowed() * * @param textInputAllowed * true to allow entering text, false to just show the current * selection */ public void setTextInputAllowed(boolean textInputAllowed) { getState().textInputAllowed = textInputAllowed; } /** * Returns true if the user can enter text into the field to either filter * the selections or enter a new value if new item provider or handler is * set (see {@link #setNewItemProvider(NewItemProvider)} (recommended) and * {@link #setNewItemHandler(NewItemHandler)} (deprecated)). If text input * is disabled, the comboBox will work in the same way as a * {@link NativeSelect} * * @return true if text input is allowed */ public boolean isTextInputAllowed() { return getState(false).textInputAllowed; } @Override public Registration addBlurListener(BlurListener listener) { return addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, BlurListener.blurMethod); } @Override public Registration addFocusListener(FocusListener listener) { return addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener, FocusListener.focusMethod); } /** * Returns the page length of the suggestion popup. * * @return the pageLength */ public int getPageLength() { return getState(false).pageLength; } /** * Returns the suggestion pop-up's width as a CSS string. By default this * width is set to "100%". * * @see #setPopupWidth * @since 7.7 * @return explicitly set popup width as CSS size string or null if not set */ public String getPopupWidth() { return getState(false).suggestionPopupWidth; } /** * Sets the page length for the suggestion popup. Setting the page length to * 0 will disable suggestion popup paging (all items visible). * * @param pageLength * the pageLength to set */ public void setPageLength(int pageLength) { getState().pageLength = pageLength; } /** * Returns whether the user is allowed to select nothing in the combo box. * * @return true if empty selection is allowed, false otherwise * @since 8.0 */ public boolean isEmptySelectionAllowed() { return getState(false).emptySelectionAllowed; } /** * Sets whether the user is allowed to select nothing in the combo box. When * true, a special empty item is shown to the user. * * @param emptySelectionAllowed * true to allow not selecting anything, false to require * selection * @since 8.0 */ public void setEmptySelectionAllowed(boolean emptySelectionAllowed) { getState().emptySelectionAllowed = emptySelectionAllowed; } /** * Returns the empty selection caption. *

* The empty string {@code ""} is the default empty selection caption. * * @return the empty selection caption, not {@code null} * @see #setEmptySelectionAllowed(boolean) * @see #isEmptySelectionAllowed() * @see #setEmptySelectionCaption(String) * @see #isSelected(Object) * @since 8.0 */ public String getEmptySelectionCaption() { return getState(false).emptySelectionCaption; } /** * Sets the empty selection caption. *

* The empty string {@code ""} is the default empty selection caption. *

* If empty selection is allowed via the * {@link #setEmptySelectionAllowed(boolean)} method (it is by default) then * the empty item will be shown with the given caption. * * @param caption * the caption to set, not {@code null} * @see #isSelected(Object) * @since 8.0 */ public void setEmptySelectionCaption(String caption) { Objects.nonNull(caption); getState().emptySelectionCaption = caption; } /** * Sets the suggestion pop-up's width as a CSS string. By using relative * units (e.g. "50%") it's possible to set the popup's width relative to the * ComboBox itself. *

* By default this width is set to "100%" so that the pop-up's width is * equal to the width of the combobox. By setting width to null the pop-up's * width will automatically expand beyond 100% relative width to fit the * content of all displayed items. * * @see #getPopupWidth() * @since 7.7 * @param width * the width */ public void setPopupWidth(String width) { getState().suggestionPopupWidth = width; } /** * Sets whether to scroll the selected item visible (directly open the page * on which it is) when opening the combo box popup or not. *

* This requires finding the index of the item, which can be expensive in * many large lazy loading containers. * * @param scrollToSelectedItem * true to find the page with the selected item when opening the * selection popup */ public void setScrollToSelectedItem(boolean scrollToSelectedItem) { getState().scrollToSelectedItem = scrollToSelectedItem; } /** * Returns true if the select should find the page with the selected item * when opening the popup. * * @see #setScrollToSelectedItem(boolean) * * @return true if the page with the selected item will be shown when * opening the popup */ public boolean isScrollToSelectedItem() { return getState(false).scrollToSelectedItem; } @Override public ItemCaptionGenerator getItemCaptionGenerator() { return super.getItemCaptionGenerator(); } @Override public void setItemCaptionGenerator( ItemCaptionGenerator itemCaptionGenerator) { super.setItemCaptionGenerator(itemCaptionGenerator); } /** * Sets the style generator that is used to produce custom class names for * items visible in the popup. The CSS class name that will be added to the * item is v-filterselect-item-[style name]. Returning null from * the generator results in no custom style name being set. * * @see StyleGenerator * * @param itemStyleGenerator * the item style generator to set, not null * @throws NullPointerException * if {@code itemStyleGenerator} is {@code null} * @since 8.0 */ public void setStyleGenerator(StyleGenerator itemStyleGenerator) { Objects.requireNonNull(itemStyleGenerator, "Item style generator must not be null"); this.itemStyleGenerator = itemStyleGenerator; getDataCommunicator().reset(); } /** * Gets the currently used style generator that is used to generate CSS * class names for items. The default item style provider returns null for * all items, resulting in no custom item class names being set. * * @see StyleGenerator * @see #setStyleGenerator(StyleGenerator) * * @return the currently used item style generator, not null * @since 8.0 */ public StyleGenerator getStyleGenerator() { return itemStyleGenerator; } @Override public void setItemIconGenerator(IconGenerator itemIconGenerator) { super.setItemIconGenerator(itemIconGenerator); } @Override public IconGenerator getItemIconGenerator() { return super.getItemIconGenerator(); } /** * Sets the handler that is called when user types a new item. The creation * of new items is allowed when a new item handler has been set. If new item * provider is also set, the new item handler is ignored. * * @param newItemHandler * handler called for new items, null to only permit the * selection of existing items, all options ignored if new item * provider is set * @since 8.0 * @deprecated Since 8.4 use {@link #setNewItemProvider(NewItemProvider)} * instead. */ @Deprecated public void setNewItemHandler(NewItemHandler newItemHandler) { getLogger().log(Level.WARNING, "NewItemHandler is deprecated. Please use NewItemProvider instead."); this.newItemHandler = newItemHandler; getState(true).allowNewItems = newItemProvider != null || newItemHandler != null; } /** * Sets the provider function that is called when user types a new item. The * creation of new items is allowed when a new item provider has been set. * If a deprecated new item handler is also set it is ignored in favor of * new item provider. * * @param newItemProvider * provider function that is called for new items, null to only * permit the selection of existing items or to use a deprecated * new item handler if set * @since 8.4 */ public void setNewItemProvider(NewItemProvider newItemProvider) { this.newItemProvider = newItemProvider; getState(true).allowNewItems = newItemProvider != null || newItemHandler != null; } /** * Returns the handler called when the user enters a new item (not present * in the data provider). * * @return new item handler or null if none specified * @deprecated Since 8.4 use {@link #getNewItemProvider()} instead. */ @Deprecated public NewItemHandler getNewItemHandler() { return newItemHandler; } /** * Returns the provider function that is called when the user enters a new * item (not present in the data provider). * * @since 8.4 * @return new item provider or null if none specified */ public NewItemProvider getNewItemProvider() { return newItemProvider; } // HasValue methods delegated to the selection model @Override public Registration addValueChangeListener( HasValue.ValueChangeListener listener) { return addSelectionListener(event -> listener .valueChange(new ValueChangeEvent<>(event.getComponent(), this, event.getOldValue(), event.isUserOriginated()))); } @Override protected ComboBoxState getState() { return (ComboBoxState) super.getState(); } @Override protected ComboBoxState getState(boolean markAsDirty) { return (ComboBoxState) super.getState(markAsDirty); } @Override protected void updateSelectedItemState(T value) { super.updateSelectedItemState(value); updateSelectedItemCaption(value); updateSelectedItemIcon(value); } private void updateSelectedItemCaption(T value) { String selectedCaption = null; if (value != null) { selectedCaption = getItemCaptionGenerator().apply(value); } getState().selectedItemCaption = selectedCaption; } private void updateSelectedItemIcon(T value) { String selectedItemIcon = null; if (value != null) { Resource icon = getItemIconGenerator().apply(value); if (icon != null) { if (icon instanceof ConnectorResource) { if (!isAttached()) { // Deferred resource generation. return; } setResource("selected", icon); } selectedItemIcon = ResourceReference .create(icon, ComboBox.this, "selected").getURL(); } } getState().selectedItemIcon = selectedItemIcon; } @Override public void attach() { super.attach(); // Update icon for ConnectorResource updateSelectedItemIcon(getValue()); DataProvider dataProvider = getDataProvider(); if (dataProvider != null && dataProviderListener == null) { setupDataProviderListener(dataProvider); } } @Override public void detach() { if (dataProviderListener != null) { dataProviderListener.remove(); dataProviderListener = null; } super.detach(); } @Override protected Element writeItem(Element design, T item, DesignContext context) { Element element = design.appendElement("option"); String caption = getItemCaptionGenerator().apply(item); if (caption != null) { element.html(DesignFormatter.encodeForTextNode(caption)); } else { element.html(DesignFormatter.encodeForTextNode(item.toString())); } element.attr("item", item.toString()); Resource icon = getItemIconGenerator().apply(item); if (icon != null) { DesignAttributeHandler.writeAttribute("icon", element.attributes(), icon, null, Resource.class, context); } String style = getStyleGenerator().apply(item); if (style != null) { element.attr("style", style); } if (isSelected(item)) { element.attr("selected", true); } return element; } @Override protected void readItems(Element design, DesignContext context) { setStyleGenerator(new DeclarativeStyleGenerator<>(getStyleGenerator())); super.readItems(design, context); } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override protected T readItem(Element child, Set selected, DesignContext context) { T item = super.readItem(child, selected, context); if (child.hasAttr("style")) { StyleGenerator styleGenerator = getStyleGenerator(); if (styleGenerator instanceof DeclarativeStyleGenerator) { ((DeclarativeStyleGenerator) styleGenerator).setStyle(item, child.attr("style")); } else { throw new IllegalStateException(String.format("Don't know how " + "to set style using current style generator '%s'", styleGenerator.getClass().getName())); } } return item; } @Override public DataProvider getDataProvider() { if (this.getDataCommunicator() != null) { return internalGetDataProvider(); } return null; } @Override public void setDataProvider(DataProvider dataProvider, SerializableFunction filterConverter) { Objects.requireNonNull(dataProvider, "dataProvider cannot be null"); Objects.requireNonNull(filterConverter, "filterConverter cannot be null"); SerializableFunction convertOrNull = filterText -> { if (filterText == null || filterText.isEmpty()) { return null; } return filterConverter.apply(filterText); }; SerializableConsumer providerFilterSlot = internalSetDataProvider( dataProvider, convertOrNull.apply(getState(false).currentFilterText)); filterSlot = filter -> providerFilterSlot .accept(convertOrNull.apply(filter)); setupDataProviderListener(dataProvider); } private void setupDataProviderListener( DataProvider dataProvider) { // This workaround is done to fix issue #11642 for unpaged comboboxes. // Data sources for on the client need to be updated after data provider // refreshAll so that serverside selection works even before the // dropdown // is opened. Only done for in-memory data providers for performance // reasons. if (dataProvider instanceof InMemoryDataProvider) { if (dataProviderListener != null) { dataProviderListener.remove(); } dataProviderListener = dataProvider .addDataProviderListener(event -> { if ((!(event instanceof DataChangeEvent.DataRefreshEvent)) && (getPageLength() == 0)) { getState().forceDataSourceUpdate = true; } }); } } /** * Sets a CallbackDataProvider using the given fetch items callback and a * size callback. *

* This method is a shorthand for making a {@link CallbackDataProvider} that * handles a partial {@link com.vaadin.data.provider.Query Query} object. * * @param fetchItems * a callback for fetching items * @param sizeCallback * a callback for getting the count of items * * @see CallbackDataProvider * @see #setDataProvider(DataProvider) */ public void setDataProvider(FetchItemsCallback fetchItems, SerializableToIntFunction sizeCallback) { setDataProvider(new CallbackDataProvider<>( q -> fetchItems.fetchItems(q.getFilter().orElse(""), q.getOffset(), q.getLimit()), q -> sizeCallback.applyAsInt(q.getFilter().orElse("")))); } /** * Predicate to check {@link ComboBox} item captions against user typed * strings. * * @see ComboBox#setItems(CaptionFilter, Collection) * @see ComboBox#setItems(CaptionFilter, Object[]) * @since 8.0 */ @FunctionalInterface public interface CaptionFilter extends SerializableBiPredicate { /** * Check item caption against entered text. * * @param itemCaption * the caption of the item to filter, not {@code null} * @param filterText * user entered filter, not {@code null} * @return {@code true} if item passes the filter and should be listed, * {@code false} otherwise */ @Override public boolean test(String itemCaption, String filterText); } private static Logger getLogger() { return Logger.getLogger(ComboBox.class.getName()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy