com.arcbees.chosen.client.gwt.MultipleChosenValueListBox.java Source code

Java tutorial

Introduction

Here is the source code for com.arcbees.chosen.client.gwt.MultipleChosenValueListBox.java

Source

/**
 * Copyright 2015 ArcBees Inc.
 *
 * 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.arcbees.chosen.client.gwt;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import com.arcbees.chosen.client.ChosenOptions;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.gwt.editor.client.IsEditor;
import com.google.gwt.editor.client.adapters.TakesValueEditor;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.text.shared.Renderer;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.SimpleKeyProvider;

public class MultipleChosenValueListBox<T> extends BaseChosenValueListBox<T>
        implements HasValue<List<T>>, IsEditor<TakesValueEditor<List<T>>> {
    private final Renderer<T> renderer;

    private final Set<T> selectedValues;
    private TakesValueEditor<List<T>> editor;

    /**
     * @throws java.lang.NullPointerException if {@code renderer} is null
     */
    public MultipleChosenValueListBox(Renderer<T> renderer) {
        this(renderer, new ChosenOptions());
    }

    /**
     * @throws java.lang.NullPointerException if {@code renderer} is null
     * @throws java.lang.NullPointerException if {@code options} is null
     */
    public MultipleChosenValueListBox(Renderer<T> renderer, ChosenOptions options) {
        this(renderer, new SimpleKeyProvider<T>(), options);
    }

    /**
     * @throws java.lang.NullPointerException if {@code renderer} is null
     * @throws java.lang.NullPointerException if {@code keyProvider} is null
     */
    public MultipleChosenValueListBox(Renderer<T> renderer, ProvidesKey<T> keyProvider) {
        this(renderer, keyProvider, new ChosenOptions());
    }

    /**
     * @throws java.lang.NullPointerException if {@code renderer} is null
     * @throws java.lang.NullPointerException if {@code keyProvider} is null
     * @throws java.lang.NullPointerException if {@code options} is null
     */
    public MultipleChosenValueListBox(Renderer<T> renderer, ProvidesKey<T> keyProvider, ChosenOptions options) {
        super(keyProvider, options);

        Preconditions.checkNotNull(renderer);

        this.renderer = renderer;
        selectedValues = new LinkedHashSet<T>();
    }

    @Override
    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<List<T>> handler) {
        return addHandler(handler, ValueChangeEvent.getType());
    }

    @Override
    public TakesValueEditor<List<T>> asEditor() {
        if (editor == null) {
            editor = TakesValueEditor.of(this);
        }
        return editor;
    }

    /**
     * Get the list of selected values of the component.
     */
    @Override
    public List<T> getValue() {
        return Lists.newArrayList(selectedValues);
    }

    /**
     * Set the values of the component. This method throws an IllegalStateException if one of the values isn't part
     * of the accepted values.
     * <p/>
     * See {@link #isAccepted(Object)} in order to test if a value can be accepted by the component.
     */
    @Override
    public void setValue(List<T> values) {
        setValue(values, false);
    }

    /**
     * Set the values of the component. This method throws an IllegalStateException if one of the values isn't part
     * of the accepted values.
     * <p/>
     * See {@link #isAccepted(Object)} in order to test if a value can be accepted by the component.
     * <p/>
     * If the {@code fireEvent} is set to true, a {@link com.google.gwt.event.logical.shared.ValueChangeEvent} will be
     * fired.
     */
    public void setValue(List<T> values, boolean fireEvent) {
        setValue(values, fireEvent, false);
    }

    /**
     * Unselect a specific value. This method does nothing if the <code>value</code> is not selected.
     */
    public void unselect(T value) {
        unselect(value, false);
    }

    /**
     * Unselect a specific value. This method does nothing if the <code>value</code> is not selected.
     * <p>If the {@code fireEvent} is set to true, a {@link com.google.gwt.event.logical.shared.ValueChangeEvent} will
     * be fired.
     */
    public void unselect(T value, boolean fireEvent) {
        boolean removed = selectedValues.remove(value);

        if (removed) {
            updateChosenListBox();

            if (fireEvent) {
                ValueChangeEvent.fire(this, getValue());
            }
        }
    }

    /**
     * Unselect all previously selected values.
     */
    public void unselectAll() {
        setValue(null);
    }

    @Override
    protected void addItemToChosenListBox(T value) {
        int index = valueKeyToIndex.get(keyProvider.getKey(value));

        getChosenListBox().addItem(renderer.render(value), "" + index);
    }

    @Override
    protected ChosenListBox createChosenListBox(ChosenOptions options) {
        return new ChosenListBox(true, options);
    }

    @Override
    protected void deselectValue(T value) {
        boolean removed = selectedValues.remove(value);
        Preconditions.checkState(removed, "Value was not previously selected");

        ValueChangeEvent.fire(this, getValue());
    }

    @Override
    protected void selectValue(T value) {
        setValue(Lists.newArrayList(value), true, true);
    }

    @Override
    protected void updateChosenListBox() {
        List<String> valueIndex = new ArrayList<String>();

        for (Iterator<T> iterator = selectedValues.iterator(); iterator.hasNext();) {
            Object key = keyProvider.getKey(iterator.next());
            Integer index = valueKeyToIndex.get(key);

            if (index == null) {
                iterator.remove();
            } else {
                valueIndex.add("" + index);
            }
        }

        getChosenListBox().unselectAll();
        getChosenListBox().setSelectedValue(valueIndex.toArray(new String[valueIndex.size()]));
    }

    private void checkValuesAcceptability(List<T> values) {
        List<T> unacceptableValues = new ArrayList<T>();

        for (T value : values) {
            if (!isAccepted(value)) {
                unacceptableValues.add(value);
            }
        }

        if (!unacceptableValues.isEmpty()) {
            throw new IllegalStateException(
                    "These following values are not accepted by the component: " + unacceptableValues);
        }
    }

    private void setValue(List<T> values, boolean fireEvent, boolean fromComponent) {
        if (!fromComponent) {
            selectedValues.clear();
        }

        if (values != null) {
            checkValuesAcceptability(values);

            selectedValues.addAll(values);
        }

        if (!fromComponent) {
            updateChosenListBox();
        }

        if (fireEvent) {
            ValueChangeEvent.fire(this, getValue());
        }
    }
}