Package org.eclipse.nebula.widgets.nattable.edit.editor

Source Code of org.eclipse.nebula.widgets.nattable.edit.editor.ComboBoxCellEditor

/*******************************************************************************
* Copyright (c) 2012, 2013 Original authors and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Original authors and others - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.edit.editor;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.nebula.widgets.nattable.data.convert.IDisplayConverter;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum;
import org.eclipse.nebula.widgets.nattable.util.ArrayUtil;
import org.eclipse.nebula.widgets.nattable.widget.EditModeEnum;
import org.eclipse.nebula.widgets.nattable.widget.NatCombo;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Text;

/**
* {@link ICellEditor} implementation to provide combo box editing behaviour.
* Uses the {@link NatCombo} as editor control which provides free editing in
* the text control part and multi selection in the dropdown part if configured.
* <p>
* You can create a ComboBoxCellEditor either by setting the items to show
* statically by constructor, or by using an {@link IComboBoxDataProvider}. Last
* one is a way to dynamically populate the items showed in a combobox in
* NatTable. It is not possible to mix these two approaches!
*
*/
public class ComboBoxCellEditor extends AbstractCellEditor {

    /**
     * The wrapped editor control.
     */
    private NatCombo combo;

    /**
     * The maximum number of items the drop down will show before introducing a
     * scroll bar.
     */
    protected int maxVisibleItems;

    /**
     * The list of canonical values that will be set as selectable items to the
     * combo. If this {@link ComboBoxCellEditor} is created for using such a
     * list, the selectable values will be static.
     * <p>
     * The values will be converted to the corresponding display values prior
     * filling the combo.
     * <p>
     * If this {@link ComboBoxCellEditor} is created for using a
     * {@link IComboBoxDataProvider} this list will be ignored.
     */
    private List<?> canonicalValues;

    /**
     * The {@link IComboBoxDataProvider} that is used to set the selectable
     * items to the combo. If this {@link ComboBoxCellEditor} is created using
     * such a data provider, the selectable value will be dynamic.
     * <p>
     * The values will be converted to the corresponding display values prior
     * filling the combo.
     * <p>
     * If a {@link IComboBoxDataProvider} is set, a possible set static list of
     * canonical values will be ignored.
     */
    private IComboBoxDataProvider dataProvider;

    /**
     * Flag that indicates whether this ComboBoxCellEditor supports free editing
     * in the text control of the NatCombo or not. By default free editing is
     * disabled.
     */
    protected boolean freeEdit = false;

    /**
     * Flag that indicates whether this ComboBoxCellEditor supports multiple
     * selection or not. By default multiple selection is disabled.
     */
    protected boolean multiselect = false;

    /**
     * Flag that indicates whether this ComboBoxCellEditor shows checkboxes for
     * items in the dropdown or not.
     */
    protected boolean useCheckbox = false;

    /**
     * String that is used to separate values in the String representation
     * showed in the text control if multiselect is supported. <code>null</code>
     * to use the default String ", ".
     */
    protected String multiselectValueSeparator = null;

    /**
     * String that is used to prefix the generated String representation showed
     * in the text control if multiselect is supported. Needed to visualize the
     * multiselection to the user. If this value is <code>null</code> the
     * default String "[" is used.
     */
    protected String multiselectTextPrefix = null;

    /**
     * String that is used to suffix the generated String representation showed
     * in the text control if multiselect is supported. Needed to visualize the
     * multiselection to the user. If this value is <code>null</code> the
     * default String "]" is used.
     */
    protected String multiselectTextSuffix = null;

    /**
     * The image to use as overlay to the {@link Text} Control if the dropdown
     * is visible. It will indicate that the control is an open combo to the
     * user. If this value is <code>null</code> the default image specified in
     * NatCombo will be used.
     */
    protected Image iconImage;

    /**
     * Create a new single selection {@link ComboBoxCellEditor} based on the
     * given list of items, showing the default number of items in the dropdown
     * of the combo.
     *
     * @param canonicalValues
     *            Array of items to be shown in the drop down box. These will be
     *            converted using the {@link IDisplayConverter} for display
     *            purposes
     */
    public ComboBoxCellEditor(List<?> canonicalValues) {
        this(canonicalValues, NatCombo.DEFAULT_NUM_OF_VISIBLE_ITEMS);
    }

    /**
     * Create a new single selection {@link ComboBoxCellEditor} based on the
     * given list of items.
     *
     * @param canonicalValues
     *            Array of items to be shown in the drop down box. These will be
     *            converted using the {@link IDisplayConverter} for display
     *            purposes
     * @param maxVisibleItems
     *            The maximum number of items the drop down will show before
     *            introducing a scroll bar.
     */
    public ComboBoxCellEditor(List<?> canonicalValues, int maxVisibleItems) {
        this.canonicalValues = canonicalValues;
        this.maxVisibleItems = maxVisibleItems;
    }

    /**
     * Create a new single selection {@link ComboBoxCellEditor} based on the
     * given {@link IComboBoxDataProvider}, showing the default number of items
     * in the dropdown of the combo.
     *
     * @param dataProvider
     *            The {@link IComboBoxDataProvider} that is responsible for
     *            populating the items to the dropdown box. This is the way to
     *            use a ComboBoxCellEditor with dynamic content.
     */
    public ComboBoxCellEditor(IComboBoxDataProvider dataProvider) {
        this(dataProvider, NatCombo.DEFAULT_NUM_OF_VISIBLE_ITEMS);
    }

    /**
     * Create a new single selection {@link ComboBoxCellEditor} based on the
     * given {@link IComboBoxDataProvider}.
     *
     * @param dataProvider
     *            The {@link IComboBoxDataProvider} that is responsible for
     *            populating the items to the dropdown box. This is the way to
     *            use a ComboBoxCellEditor with dynamic content.
     * @param maxVisibleItems
     *            The maximum number of items the drop down will show before
     *            introducing a scroll bar.
     */
    public ComboBoxCellEditor(IComboBoxDataProvider dataProvider,
            int maxVisibleItems) {
        this.dataProvider = dataProvider;
        this.maxVisibleItems = maxVisibleItems;
    }

    @Override
    protected Control activateCell(Composite parent,
            final Object originalCanonicalValue) {
        this.combo = createEditorControl(parent);

        fillCombo();

        setCanonicalValue(originalCanonicalValue);

        // open the dropdown immediately after the Text control of the NatCombo
        // is positioned
        if (this.editMode == EditModeEnum.INLINE) {
            this.combo.addTextControlListener(new ControlAdapter() {
                @Override
                public void controlResized(ControlEvent e) {
                    combo.showDropdownControl(originalCanonicalValue instanceof Character);
                    combo.removeTextControlListener(this);
                }

                @Override
                public void controlMoved(ControlEvent e) {
                    combo.showDropdownControl(originalCanonicalValue instanceof Character);
                    combo.removeTextControlListener(this);
                }
            });
        }

        return this.combo;
    }

    /**
     * This implementation overrides the default implementation because we can
     * work on the list of canonical items in the combo directly. Only for
     * multiselect in combination with free editing, we need to convert here
     * ourself.
     */
    @Override
    public Object getCanonicalValue() {
        if (!this.multiselect) {
            // single selection handling
            int selectionIndex = this.combo.getSelectionIndex();

            // Item selected from list
            if (selectionIndex >= 0) {
                if (this.dataProvider != null) {
                    return this.dataProvider.getValues(getColumnIndex(),
                            getRowIndex()).get(selectionIndex);
                } else {
                    return this.canonicalValues.get(selectionIndex);
                }
            } else {
                // if there is no selection in the dropdown, we need to check if
                // there is a free edit
                // in the NatCombo control
                if (this.combo.getSelection().length > 0) {
                    return super.getCanonicalValue();
                }
            }
        } else {
            // multi selection handling
            int[] selectionIndices = this.combo.getSelectionIndices();

            // as we are in multiselection mode, we always return a Collection
            // and never null
            List<Object> result = new ArrayList<Object>();

            // Item selected from list
            if (selectionIndices.length > 0) {
                List<?> values = null;
                if (this.dataProvider != null) {
                    values = this.dataProvider.getValues(getColumnIndex(),
                            getRowIndex());
                } else {
                    values = this.canonicalValues;
                }
                for (int i : selectionIndices) {
                    result.add(values.get(i));
                }
            } else {
                // if there is no selection in the dropdown, we need to check if
                // there is a free edit
                // in the NatCombo control
                String[] comboSelection = this.combo.getSelection();
                if (comboSelection.length > 0) {
                    for (String selection : comboSelection) {
                        result.add(handleConversion(selection,
                                this.conversionEditErrorHandler));
                    }
                }
            }

            // if nothing is selected and there is no free edit, we return an
            // empty Collection
            return result;
        }

        return null;
    }

    /**
     * This implementation overrides the default implementation because of the
     * special handling for comboboxes. It can handle multi selection and needs
     * to transfer the converted values into a String array so the values in the
     * combobox can be selected.
     *
     * @param canonicalValue
     *            The canonical value to be set to the wrapped editor control.
     */
    @Override
    public void setCanonicalValue(Object canonicalValue) {
        if (canonicalValue != null) {
            String[] editorValues = null;
            if (canonicalValue instanceof List<?>) {
                List<?> temp = (List<?>) canonicalValue;
                String[] result = new String[temp.size()];
                for (int i = 0; i < temp.size(); i++) {
                    result[i] = (String) this.displayConverter
                            .canonicalToDisplayValue(this.layerCell,
                                    this.configRegistry, temp.get(i));
                }
                editorValues = result;
            } else {
                editorValues = new String[] { (String) this.displayConverter
                        .canonicalToDisplayValue(this.layerCell,
                                this.configRegistry, canonicalValue) };
            }
            setEditorValue(editorValues);
        }
    }

    /**
     * Will set the items selectable in the combo dependent on the configuration
     * of this {@link ComboBoxCellEditor}. As the combo is only able to handle
     * Strings in the combo itself, and this editor works directly on the
     * canonical values, the values are converted in here too.
     */
    private void fillCombo() {
        List<String> displayValues = new ArrayList<String>();

        List<?> values;
        if (this.dataProvider != null) {
            values = this.dataProvider.getValues(getColumnIndex(),
                    getRowIndex());
        } else {
            values = this.canonicalValues;
        }

        for (Object canonicalValue : values) {
            displayValues.add((String) this.displayConverter
                    .canonicalToDisplayValue(this.layerCell,
                            this.configRegistry, canonicalValue));
        }

        this.combo.setItems(displayValues.toArray(ArrayUtil.STRING_TYPE_ARRAY));
    }

    @Override
    public Object getEditorValue() {
        if (!this.multiselect) {
            return this.combo.getSelection()[0];
        }
        return this.combo.getSelection();
    }

    @Override
    public void setEditorValue(Object value) {
        this.combo.setSelection((String[]) value);
    }

    @Override
    public NatCombo getEditorControl() {
        return this.combo;
    }

    @Override
    public NatCombo createEditorControl(Composite parent) {
        int style = SWT.NONE;
        if (!this.freeEdit) {
            style |= SWT.READ_ONLY;
        }
        if (this.multiselect) {
            style |= SWT.MULTI;
        }
        if (this.useCheckbox) {
            style |= SWT.CHECK;
        }
        final NatCombo combo = this.iconImage == null ? new NatCombo(parent,
                this.cellStyle, this.maxVisibleItems, style) : new NatCombo(
                parent, this.cellStyle, this.maxVisibleItems, style,
                this.iconImage);

        combo.setCursor(new Cursor(Display.getDefault(), SWT.CURSOR_IBEAM));

        if (multiselect) {
            combo.setMultiselectValueSeparator(this.multiselectValueSeparator);
            combo.setMultiselectTextBracket(this.multiselectTextPrefix,
                    this.multiselectTextSuffix);
        }

        addNatComboListener(combo);
        return combo;
    }

    /**
     * Registers special listeners to the {@link NatCombo} regarding the
     * {@link EditModeEnum}, that are needed to commit/close or change the
     * visibility state of the {@link NatCombo} dependent on UI interactions.
     *
     * @param combo
     *            The {@link NatCombo} to add the listeners to.
     */
    protected void addNatComboListener(final NatCombo combo) {
        combo.addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent event) {
                if ((event.keyCode == SWT.CR)
                        || (event.keyCode == SWT.KEYPAD_CR)) {
                    commit(MoveDirectionEnum.NONE,
                            editMode == EditModeEnum.INLINE);
                } else if (event.keyCode == SWT.ESC) {
                    close();
                }
            }

        });

        combo.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseUp(MouseEvent e) {
                commit(MoveDirectionEnum.NONE,
                        (!multiselect && editMode == EditModeEnum.INLINE));
                if (!multiselect && editMode == EditModeEnum.DIALOG) {
                    // hide the dropdown after a value was selected in the combo
                    // in a dialog
                    combo.hideDropdownControl();
                }
            }
        });

        if (editMode == EditModeEnum.INLINE) {
            combo.addShellListener(new ShellAdapter() {
                @Override
                public void shellClosed(ShellEvent e) {
                    close();
                }
            });
        }

        if (editMode == EditModeEnum.DIALOG) {
            combo.addFocusListener(new FocusAdapter() {
                @Override
                public void focusLost(FocusEvent e) {
                    combo.hideDropdownControl();
                }
            });
        }
    }

    /**
     * Selects the item at the given zero-relative index in the receiver's list.
     * If the item at the index was already selected, it remains selected.
     * Indices that are out of range are ignored.
     *
     * @param index
     *            the index of the item to select
     *
     * @see org.eclipse.swt.widgets.List#select(int)
     */
    public void select(int index) {
        this.combo.select(index);
    }

    /**
     * Selects the items at the given zero-relative indices in the receiver. The
     * current selection is not cleared before the new items are selected.
     * <p>
     * If the item at a given index is not selected, it is selected. If the item
     * at a given index was already selected, it remains selected. Indices that
     * are out of range and duplicate indices are ignored. If the receiver is
     * single-select and multiple indices are specified, then all indices are
     * ignored.
     *
     * @param indices
     *            the array of indices for the items to select
     *
     * @see org.eclipse.swt.widgets.List#select(int[])
     */
    public void select(int[] indices) {
        this.combo.select(indices);
    }

    /**
     * @param multiselectValueSeparator
     *            String that should be used to separate values in the String
     *            representation showed in the text control if multiselect is
     *            supported. <code>null</code> to use the default value
     *            separator.
     * @see NatCombo#DEFAULT_MULTI_SELECT_VALUE_SEPARATOR
     */
    public void setMultiselectValueSeparator(String multiselectValueSeparator) {
        this.multiselectValueSeparator = multiselectValueSeparator;
    }

    /**
     * Set the prefix and suffix that will parenthesize the text that is created
     * out of the selected values if this NatCombo supports multiselection.
     *
     * @param multiselectTextPrefix
     *            String that should be used to prefix the generated String
     *            representation showed in the text control if multiselect is
     *            supported. <code>null</code> to use the default prefix.
     * @param multiselectTextSuffix
     *            String that should be used to suffix the generated String
     *            representation showed in the text control if multiselect is
     *            supported. <code>null</code> to use the default suffix.
     * @see NatCombo#DEFAULT_MULTI_SELECT_PREFIX
     * @see NatCombo#DEFAULT_MULTI_SELECT_SUFFIX
     */
    public void setMultiselectTextBracket(String multiselectTextPrefix,
            String multiselectTextSuffix) {
        this.multiselectTextPrefix = multiselectTextPrefix;
        this.multiselectTextSuffix = multiselectTextSuffix;
    }

    /**
     * @return The image that is used as overlay to the {@link Text} Control if
     *         the dropdown is visible. It will indicate that the control is an
     *         open combo to the user. If this value is <code>null</code> the
     *         default image specified in NatCombo will be used.
     */
    public Image getIconImage() {
        return this.iconImage;
    }

    /**
     * @param iconImage
     *            The image to use as overlay to the {@link Text} Control if the
     *            dropdown is visible. It will indicate that the control is an
     *            open combo to the user. If this value is <code>null</code> the
     *            default image specified in NatCombo will be used.
     */
    public void setIconImage(Image iconImage) {
        this.iconImage = iconImage;
    }

    /**
     * @return <code>true</code> if this ComboBoxCellEditor supports free
     *         editing in the text control of the NatCombo or not. By default
     *         free editing is disabled.
     */
    public boolean isFreeEdit() {
        return freeEdit;
    }

    /**
     * @param freeEdit
     *            <code>true</code> to indicate that this ComboBoxCellEditor
     *            supports free editing in the text control of the NatCombo,
     *            <code>false</code> if not.
     */
    public void setFreeEdit(boolean freeEdit) {
        this.freeEdit = freeEdit;
    }

    /**
     * @return <code>true</code> if this ComboBoxCellEditor supports multiple
     *         selection or not. By default multiple selection is disabled.
     */
    public boolean isMultiselect() {
        return multiselect;
    }

    /**
     * @param multiselect
     *            <code>true</code> to indicate that this ComboBoxCellEditor
     *            supports multiple selection, <code>false</code> if not.
     */
    public void setMultiselect(boolean multiselect) {
        this.multiselect = multiselect;
    }

    /**
     * @return <code>true</code> if this ComboBoxCellEditor shows checkboxes for
     *         items in the dropdown. By default there are not checkboxes shown.
     */
    public boolean isUseCheckbox() {
        return useCheckbox;
    }

    /**
     * @param useCheckbox
     *            <code>true</code> if this ComboBoxCellEditor should show
     *            checkboxes for items in the dropdown, <code>false</code> if
     *            not.
     */
    public void setUseCheckbox(boolean useCheckbox) {
        this.useCheckbox = useCheckbox;
    }
}
TOP

Related Classes of org.eclipse.nebula.widgets.nattable.edit.editor.ComboBoxCellEditor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.