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

com.vaadin.client.ui.VListSelect Maven / Gradle / Ivy

There is a newer version: 8.26.0
Show newest version
/*
 * Copyright 2000-2018 Vaadin Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.vaadin.client.ui;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiConsumer;

import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HasEnabled;
import com.google.gwt.user.client.ui.ListBox;
import com.vaadin.client.FastStringSet;
import com.vaadin.client.Focusable;
import com.vaadin.client.connectors.AbstractMultiSelectConnector.MultiSelectWidget;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.listselect.ListSelectState;

import elemental.json.JsonObject;

/**
 * A simple list select for selecting multiple items.
 *
 * @author Vaadin Ltd
 */
public class VListSelect extends Composite
        implements Field, Focusable, HasEnabled, MultiSelectWidget {

    private List, Set>> selectionChangeListeners = new ArrayList<>();

    /** Container for select. Kept for DOM backwards compatibility. */
    protected final FlowPanel container;
    /** The select component. */
    protected final ListBox select;

    private boolean enabled;
    private boolean readOnly;
    private FastStringSet selectedItemKeys = FastStringSet.create();

    /**
     * Constructs a simple ListSelect widget in multiselect mode.
     */
    public VListSelect() {
        container = new FlowPanel();

        initWidget(container);

        select = new ListBox();
        select.setMultipleSelect(true);

        // Add event handlers
        select.addClickHandler(
                clickEvent -> selectionEvent(clickEvent.getSource()));
        select.addChangeHandler(
                changeEvent -> selectionEvent(changeEvent.getSource()));

        container.add(select);

        updateEnabledState();
        setStylePrimaryName(ListSelectState.PRIMARY_STYLENAME);
    }

    @Override
    public void setStylePrimaryName(String style) {
        super.setStylePrimaryName(style);
        select.setStyleName(style + "-select");
    }

    /**
     * Sets the number of visible items for the list select.
     *
     * @param rows
     *            the number of items to show
     * @see ListBox#setVisibleItemCount(int)
     */
    public void setRows(int rows) {
        if (select.getVisibleItemCount() != rows) {
            select.setVisibleItemCount(rows);
        }
    }

    /**
     * Returns the number of visible items for the list select.
     *
     * @return the number of items to show
     * @see ListBox#setVisibleItemCount(int)
     */
    public int getRows() {
        return select.getVisibleItemCount();
    }

    @Override
    public Registration addSelectionChangeListener(
            BiConsumer, Set> listener) {
        Objects.nonNull(listener);
        selectionChangeListeners.add(listener);
        return (Registration) () -> selectionChangeListeners.remove(listener);
    }

    @Override
    public void setItems(List items) {
        selectedItemKeys = FastStringSet.create();
        for (int i = 0; i < items.size(); i++) {
            final JsonObject item = items.get(i);
            // reuse existing option if possible
            final String key = MultiSelectWidget.getKey(item);
            if (i < select.getItemCount()) {
                select.setItemText(i, MultiSelectWidget.getCaption(item));
                select.setValue(i, key);
            } else {
                select.addItem(MultiSelectWidget.getCaption(item), key);
            }
            final boolean selected = MultiSelectWidget.isSelected(item);
            select.setItemSelected(i, selected);
            if (selected) {
                selectedItemKeys.add(key);
            }
        }

        // remove extra
        for (int i = select.getItemCount() - 1; i >= items.size(); i--) {
            select.removeItem(i);
        }
    }

    /**
     * Gets the currently selected item values.
     *
     * @return the currently selected item keys
     */
    protected FastStringSet getSelectedItems() {
        final FastStringSet selectedItemKeys = FastStringSet.create();
        for (int i = 0; i < select.getItemCount(); i++) {
            if (select.isItemSelected(i)) {
                selectedItemKeys.add(select.getValue(i));
            }
        }
        return selectedItemKeys;
    }

    private void selectionEvent(Object source) {
        if (source == select) {
            // selection can change by adding and at the same time removing
            // previous keys, or by just adding (e.g. when modifier keys are
            // pressed)
            final Set newSelectedItemKeys = new HashSet<>();
            final Set removedItemKeys = new HashSet<>();
            for (int i = 0; i < select.getItemCount(); i++) {
                String key = select.getValue(i);
                boolean selected = select.isItemSelected(i);
                boolean wasSelected = selectedItemKeys.contains(key);
                if (selected && !wasSelected) {
                    newSelectedItemKeys.add(key);
                    selectedItemKeys.add(key);
                } else if (!selected && wasSelected) {
                    removedItemKeys.add(key);
                    selectedItemKeys.remove(key);
                }
            }
            selectionChangeListeners.forEach(
                    l -> l.accept(newSelectedItemKeys, removedItemKeys));
        }
    }

    @Override
    public void setHeight(String height) {
        select.setHeight(height);
        super.setHeight(height);
    }

    @Override
    public void setWidth(String width) {
        select.setWidth(width);
        super.setWidth(width);
    }

    /**
     * Sets the tab index.
     *
     * @param tabIndex
     *            the tab index to set
     */
    public void setTabIndex(int tabIndex) {
        select.setTabIndex(tabIndex);
    }

    /**
     * Gets the tab index.
     *
     * @return the tab index
     */
    public int getTabIndex() {
        return select.getTabIndex();
    }

    /**
     * Sets this select as read only, meaning selection cannot be changed.
     *
     * @param readOnly
     *            {@code true} for read only, {@code false} for not read only
     */
    public void setReadOnly(boolean readOnly) {
        if (this.readOnly != readOnly) {
            this.readOnly = readOnly;
            updateEnabledState();
        }
    }

    /**
     * Returns {@code true} if this select is in read only mode, {@code false}
     * if not.
     *
     * @return {@code true} for read only, {@code false} for not read only
     */
    public boolean isReadOnly() {
        return readOnly;
    }

    @Override
    public void setEnabled(boolean enabled) {
        if (this.enabled != enabled) {
            this.enabled = enabled;
            updateEnabledState();
        }
    }

    @Override
    public boolean isEnabled() {
        return enabled;
    }

    private void updateEnabledState() {
        select.setEnabled(isEnabled() && !isReadOnly());
    }

    @Override
    public void focus() {
        select.setFocus(true);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy