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

com.vaadin.ui.components.grid.SingleSelectionModelImpl 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.components.grid;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

import com.vaadin.event.selection.SingleSelectionEvent;
import com.vaadin.event.selection.SingleSelectionListener;
import com.vaadin.shared.Registration;
import com.vaadin.shared.data.selection.SelectionServerRpc;
import com.vaadin.shared.ui.grid.SingleSelectionModelState;
import com.vaadin.ui.SingleSelect;

/**
 * Single selection model for grid.
 *
 * @author Vaadin Ltd.
 * @since 8.0
 *
 * @param 
 *            the type of the selected item in grid.
 */
public class SingleSelectionModelImpl extends AbstractSelectionModel
        implements SingleSelectionModel {

    private T selectedItem = null;

    @Override
    protected void init() {
        registerRpc(new SelectionServerRpc() {

            @Override
            public void select(String key) {
                setSelectedFromClient(key);
            }

            @Override
            public void deselect(String key) {
                if (isKeySelected(key)) {
                    setSelectedFromClient(null);
                }
            }
        });
    }

    @Override
    protected SingleSelectionModelState getState() {
        return (SingleSelectionModelState) super.getState();
    }

    @Override
    protected SingleSelectionModelState getState(boolean markAsDirty) {
        return (SingleSelectionModelState) super.getState(markAsDirty);
    }

    @Override
    public Registration addSingleSelectionListener(
            SingleSelectionListener listener) {
        return addListener(SingleSelectionEvent.class, listener,
                SingleSelectionListener.SELECTION_CHANGE_METHOD);
    }

    @Override
    public Optional getSelectedItem() {
        return Optional.ofNullable(selectedItem);
    }

    @Override
    public void deselect(T item) {
        Objects.requireNonNull(item, "deselected item cannot be null");
        if (isSelected(item)) {
            setSelectedFromServer(null);
        }
    }

    @Override
    public void select(T item) {
        Objects.requireNonNull(item, "selected item cannot be null");
        setSelectedFromServer(item);
    }

    /**
     * Returns whether the given key maps to the currently selected item.
     *
     * @param key
     *            the key to test or {@code null} to test whether nothing is
     *            selected
     * @return {@code true} if the key equals the key of the currently selected
     *         item (or {@code null} if no selection), {@code false} otherwise.
     */
    protected boolean isKeySelected(String key) {
        return isSelected(getData(key));
    }

    /**
     * Sets the selected item. If the item is {@code null}, clears the current
     * selection if any.
     *
     * @param item
     *            the selected item or {@code null} to clear selection
     * @since 8.1
     */
    protected void doSetSelected(T item) {
        if (getParent() == null) {
            throw new IllegalStateException(
                    "Trying to update selection for grid selection model that has been detached from the grid.");
        }

        if (selectedItem != null) {
            getGrid().getDataCommunicator().refresh(selectedItem);
        }
        selectedItem = item;
        if (selectedItem != null) {
            getGrid().getDataCommunicator().refresh(selectedItem);
        }
    }

    /**
     * Sets the selection based on a client request. Does nothing if the select
     * component is {@linkplain SingleSelect#isReadOnly()} or if the selection
     * would not change. Otherwise updates the selection and fires a selection
     * change event with {@code isUserOriginated == true}.
     *
     * @param key
     *            the key of the item to select or {@code null} to clear
     *            selection
     */
    protected void setSelectedFromClient(String key) {
        if (!isUserSelectionAllowed()) {
            throw new IllegalStateException("Client tried to update selection"
                    + " although user selection is disallowed");
        }
        T item = getData(key);
        if (isSelected(item)) {
            return;
        }

        T oldSelection = selectedItem;
        doSetSelected(item);
        fireEvent(new SingleSelectionEvent<>(getGrid(), asSingleSelect(),
                oldSelection, true));
    }

    /**
     * Sets the selection based on server API call. Does nothing if the
     * selection would not change; otherwise updates the selection and fires a
     * selection change event with {@code isUserOriginated == false}.
     *
     * @param item
     *            the item to select or {@code null} to clear selection
     */
    protected void setSelectedFromServer(T item) {
        if (isSelected(item)) {
            // Avoid generating an extra key when item matches a stale one.
            return;
        }

        T oldSelection = this.getSelectedItem()
                .orElse(asSingleSelect().getEmptyValue());
        doSetSelected(item);
        fireEvent(new SingleSelectionEvent<>(getGrid(), asSingleSelect(),
                oldSelection, false));
    }

    @Override
    public Set getSelectedItems() {
        if (selectedItem != null) {
            return new HashSet<>(Arrays.asList(selectedItem));
        } else {
            return Collections.emptySet();
        }
    }

    @Override
    public void setDeselectAllowed(boolean deselectAllowed) {
        getState().deselectAllowed = deselectAllowed;
    }

    @Override
    public boolean isDeselectAllowed() {
        return getState().deselectAllowed;
    }

    /**
     * Gets a wrapper for using this grid as a single select in a binder.
     *
     * @return a single select wrapper for grid
     */
    @Override
    public SingleSelect asSingleSelect() {
        return new SingleSelect() {

            @Override
            public void setValue(T value) {
                SingleSelectionModelImpl.this.setSelectedFromServer(value);
            }

            @Override
            public T getValue() {
                return SingleSelectionModelImpl.this.getSelectedItem()
                        .orElse(null);
            }

            @Override
            public Registration addValueChangeListener(
                    com.vaadin.data.HasValue.ValueChangeListener listener) {
                return SingleSelectionModelImpl.this.addSingleSelectionListener(
                        (SingleSelectionListener) event -> listener
                                .valueChange(event));
            }

            @Override
            public void setRequiredIndicatorVisible(
                    boolean requiredIndicatorVisible) {
                // TODO support required indicator when grid is used in binder ?
                throw new UnsupportedOperationException(
                        "Required indicator is not supported for Grid.");
            }

            @Override
            public boolean isRequiredIndicatorVisible() {
                throw new UnsupportedOperationException(
                        "Required indicator is not supported for Grid.");
            }

            @Override
            public void setReadOnly(boolean readOnly) {
                setUserSelectionAllowed(!readOnly);
            }

            @Override
            public boolean isReadOnly() {
                return !isUserSelectionAllowed();
            }
        };
    }

    @Override
    public void refreshData(T item) {
        if (isSelected(item)) {
            selectedItem = item;
        }
    }

    @Override
    public boolean isSelected(T item) {
        // Quick comparison of objects directly
        if (Objects.equals(item, selectedItem)) {
            return true;
        }

        // Id based check
        return item != null && selectedItem != null
                && getGrid().getDataProvider().getId(selectedItem)
                        .equals(getGrid().getDataProvider().getId(item));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy