blob: 8bf5e01a4d77ecf4157ca3172604fd806efa0d46 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2020 Dirk Fauth and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Dirk Fauth <dirk.fauth@googlemail.com> - initial API and implementation
* Ryan McHale <rpmc22@gmail.com> - Bug 484716
*******************************************************************************/
package org.eclipse.nebula.widgets.nattable.filterrow.combobox;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.nebula.widgets.nattable.data.convert.ConversionFailedException;
import org.eclipse.nebula.widgets.nattable.edit.EditConstants;
import org.eclipse.nebula.widgets.nattable.edit.editor.ComboBoxCellEditor;
import org.eclipse.nebula.widgets.nattable.edit.editor.IComboBoxDataProvider;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum;
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.graphics.Cursor;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
/**
* Specialisation of ComboBoxCellEditor that can only be created using an
* IComboBoxDataProvider. Will show a multiselect combobox with checkboxes and
* uses the FilterNatCombo as underlying control.
*
* @see FilterRowComboBoxDataProvider
*/
public class FilterRowComboBoxCellEditor extends ComboBoxCellEditor {
private static final Log log = LogFactory.getLog(FilterRowComboBoxCellEditor.class);
/**
* This object remembers the current value in the editor. This is necessary
* to avoid double commits on closing the editor again.
* <p>
* Per default editors commit their values prior to closing them. The commit
* call is performed by various actions that get triggered when the editor
* losses focus. As this editor is configured to commit the value on each
* click of a checkbox, we avoid committing the value again on closing.
*/
private Object currentCanonicalValue = null;
/**
* Create a new {@link FilterRowComboBoxCellEditor} 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.
*/
public FilterRowComboBoxCellEditor(IComboBoxDataProvider dataProvider) {
this(dataProvider, NatCombo.DEFAULT_NUM_OF_VISIBLE_ITEMS);
}
/**
* Create a new {@link FilterRowComboBoxCellEditor} based on the given
* {@link IComboBoxDataProvider}.
*
* @param dataProvider
* The {@link IComboBoxDataProvider} that is responsible for
* populating the items to the dropdown box.
* @param maxVisibleItems
* The maximum number of items the drop down will show before
* introducing a scroll bar.
*/
public FilterRowComboBoxCellEditor(IComboBoxDataProvider dataProvider, int maxVisibleItems) {
super(dataProvider, maxVisibleItems);
this.multiselect = true;
this.useCheckbox = true;
}
@Override
public NatCombo createEditorControl(Composite parent) {
int style = SWT.READ_ONLY | SWT.MULTI | SWT.CHECK;
final FilterNatCombo combo = this.iconImage == null
? new FilterNatCombo(parent, this.cellStyle, this.maxVisibleItems, style, this.showDropdownFilter)
: new FilterNatCombo(parent, this.cellStyle, this.maxVisibleItems, style, this.iconImage, this.showDropdownFilter);
combo.setCursor(new Cursor(Display.getDefault(), SWT.CURSOR_IBEAM));
combo.setMultiselectValueSeparator(this.multiselectValueSeparator);
combo.setMultiselectTextBracket(this.multiselectTextPrefix, this.multiselectTextSuffix);
addNatComboListener(combo);
// additionally add the ICheckStateListener so on changing the value of
// the select all item the change is also committed
combo.addCheckStateListener(event -> {
if (event.getChecked()) {
setCanonicalValue(EditConstants.SELECT_ALL_ITEMS_VALUE);
}
commit(MoveDirectionEnum.NONE,
(!FilterRowComboBoxCellEditor.this.multiselect
&& FilterRowComboBoxCellEditor.this.editMode == EditModeEnum.INLINE));
});
return combo;
}
@Override
public void setCanonicalValue(Object canonicalValue) {
this.currentCanonicalValue = canonicalValue;
super.setCanonicalValue(canonicalValue);
}
@Override
public boolean commit(MoveDirectionEnum direction, boolean closeAfterCommit) {
// If the editor should be closed after commit, we first need to ensure
// if the value has changed since the last commit.
// This needs to be done because in this filter combo box, every
// selection immediately causes a commit, which results in applying a
// filter. If the combo box is now closed because of losing the focus,
// the value gets committed again, which again results in filtering,
// which will lead to exceptions because the states are not synchronous
// anymore.
if (!isClosed()) {
try {
// always do the conversion
Object canonicalValue = getCanonicalValue();
if ((canonicalValue != null && this.currentCanonicalValue == null)
|| (canonicalValue == null && this.currentCanonicalValue != null)
|| (canonicalValue != null
&& this.currentCanonicalValue != null
&& !canonicalValue.equals(this.currentCanonicalValue))) {
if (super.commit(direction, closeAfterCommit)) {
this.currentCanonicalValue = canonicalValue;
return true;
}
} else {
// the values are the same so it is not necessary to commit
// again
if (closeAfterCommit) {
close();
}
return true;
}
} catch (ConversionFailedException e) {
// do nothing as exceptions caused by conversion are handled
// already. we just need this catch block for stopping the
// process if conversion failed with an exception
} catch (Exception e) {
// if another exception occured that wasn't thrown by us, it
// should at least be logged without killing the whole
// application
log.error("Error on updating cell value: " + e.getLocalizedMessage(), e); //$NON-NLS-1$
}
}
return false;
}
}