/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG 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:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.ui.ridgets.swt;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.BindingException;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateListStrategy;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.beans.BeansObservables;
import org.eclipse.core.databinding.beans.PojoObservables;
import org.eclipse.core.databinding.conversion.Converter;
import org.eclipse.core.databinding.conversion.IConverter;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.IValueChangeListener;
import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.riena.core.util.ListenerList;
import org.eclipse.riena.core.util.ReflectionUtils;
import org.eclipse.riena.core.util.StringUtils;
import org.eclipse.riena.ui.core.marker.ErrorMarker;
import org.eclipse.riena.ui.core.marker.ErrorMessageMarker;
import org.eclipse.riena.ui.ridgets.IColumnFormatter;
import org.eclipse.riena.ui.ridgets.IComboRidget;
import org.eclipse.riena.ui.ridgets.IMarkableRidget;
import org.eclipse.riena.ui.ridgets.IRidget;
import org.eclipse.riena.ui.ridgets.databinding.ConverterFactory;
import org.eclipse.riena.ui.ridgets.holder.SelectableListHolder;
import org.eclipse.riena.ui.ridgets.listener.ISelectionListener;
import org.eclipse.riena.ui.ridgets.listener.SelectionEvent;
import org.eclipse.riena.ui.ridgets.swt.nls.Messages;
import org.eclipse.riena.ui.swt.CompletionCombo;
import org.eclipse.riena.ui.swt.utils.SwtUtilities;
/**
* Superclass of ComboRidget that does not depend on the Combo SWT control. May be reused for custom Combo controls.
*/
public abstract class AbstractComboRidget extends AbstractSWTRidget implements IComboRidget {
/**
* List of available options (ridget).
*
* @since 3.0
*/
protected final IObservableList rowObservables;
/**
* The selected option (ridget).
*
* @since 3.0
*/
protected final IObservableValue selectionObservable;
/** Selection validator that allows or cancels a selection request. */
private final SelectionBindingValidator selectionValidator;
/**
* Listener that can undo a user's selection if the ridget is in 'readOnly' mode.
*/
private final SelectionEnforcer selectionEnforcer;
/** IValueChangeListener that fires a selection event on change. */
private final IValueChangeListener valueChangeNotifier;
/** A list of selection listeners. */
private ListenerList<ISelectionListener> selectionListeners;
/** If this item is selected, treat it as if nothing is selected */
private Object emptySelection;
/** The value which will be set if the model value is null. */
private Object defaultSelection;
/** List of available options (model). */
private IObservableList optionValues;
/** Class of the optional values. */
private Class<? extends Object> rowClass;
/** The selected option (model). */
private IObservableValue selectionValue;
/**
* Optional IColumnFormatter providing an Image or Text for each model entry.
*/
private IColumnFormatter formatter;
/** A string used for converting from Object to String */
private String renderingMethod;
/**
* Converts from objects (rowObsservables) to strings (Combo) using the renderingMethod.
*/
private IConverter objToStrConverter;
/**
* Converts from strings (Combo) to objects (rowObservables).
*/
private IConverter strToObjConverter;
/**
* Binding between the rowObservables and the list of choices from the model. May be null, when there is no model.
*/
private Binding listBindingExternal;
/**
* Binding between the selection in the combo and the selectionObservable. May be null, when there is no control or model.
*/
private Binding selectionBindingInternal;
/**
* Binding between the selectionObservable and the selection in the model. May be null, when there is no model.
*/
private Binding selectionBindingExternal;
/**
* If true, it will cause an error marker to be shown, once the selected value in the combo is no longer available in the list of selectable values. This
* can occur if the selection was removed from the bound model and {@link #updateFromModel()} is called.
* <p>
* The default setting is false.
*
* @see Bug 304733
*/
private boolean markSelectionMismatch;
/**
* The {@link ErrorMarker} used when a 'selection mismatch' occurs
*/
private ErrorMarker selectionMismatchMarker;
/**
* The text value shown in the combo. Note: this is not necessarily a valid selection. Use {@link #getSelection()} to get the current selection.
*/
private String text;
public AbstractComboRidget() {
rowClass = null;
rowObservables = new WritableList();
selectionObservable = new WritableValue();
objToStrConverter = new ObjectToStringConverter();
strToObjConverter = new StringToObjectConverter();
selectionValidator = new SelectionBindingValidator();
selectionEnforcer = new SelectionEnforcer();
valueChangeNotifier = new ValueChangeNotifier();
text = ""; //$NON-NLS-1$
addPropertyChangeListener(IRidget.PROPERTY_ENABLED, new PropertyChangeListener() {
public void propertyChange(final PropertyChangeEvent evt) {
applyEnabled();
}
});
addPropertyChangeListener(IMarkableRidget.PROPERTY_OUTPUT_ONLY, new PropertyChangeListener() {
public void propertyChange(final PropertyChangeEvent evt) {
if (getUIControl() != null) {
updateEditable();
}
}
});
}
@Override
protected void bindUIControl() {
if (!SwtUtilities.isDisposed(getUIControl())) {
applyText();
addTextModifyListener();
addSelectionListener(selectionEnforcer);
updateEditable();
}
if (optionValues != null) {
// These bindings are only necessary when we have a model
final DataBindingContext dbc = new DataBindingContext();
if (!SwtUtilities.isDisposed(getUIControl())) {
applyEnabled();
}
listBindingExternal = dbc.bindList(rowObservables, optionValues, new UpdateListStrategy(UpdateListStrategy.POLICY_ON_REQUEST),
new UpdateListStrategy(UpdateListStrategy.POLICY_ON_REQUEST));
final UpdateValueStrategy targetToModel = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE).setAfterGetValidator(selectionValidator);
addConverter(targetToModel, selectionValue);
final UpdateValueStrategy modelToTarget = new UpdateValueStrategy(UpdateValueStrategy.POLICY_ON_REQUEST);
selectionBindingExternal = dbc.bindValue(selectionObservable, selectionValue, targetToModel, modelToTarget);
// Ensure valueChangeNotifier is not added more that once.
selectionObservable.removeValueChangeListener(valueChangeNotifier);
// We have to add the notifier after installing selectionBindingExternal,
// to guarantee that the binding updates the selection value before
// the valueChangeNotifier sends the selection changed event (bug 287740)
selectionObservable.addValueChangeListener(valueChangeNotifier);
}
selectionEnforcer.saveSelection();
}
/**
* @since 5.0
*/
protected void addConverter(final UpdateValueStrategy targetToModelStrategy, final IObservableValue selectionValue) {
// default: do nothing
}
@Override
protected void unbindUIControl() {
super.unbindUIControl();
if (getUIControl() != null) {
removeTextModifyListener();
removeSelectionListener(selectionEnforcer);
}
disposeBinding(listBindingExternal);
listBindingExternal = null;
disposeBinding(selectionBindingInternal);
selectionBindingInternal = null;
disposeBinding(selectionBindingExternal);
selectionBindingExternal = null;
}
/**
* Provides access to an optional {@link IColumnFormatter} that provides an Image or Text for each model entry of the Combo.
*
* @return an {@link IColumnFormatter} or null (if not set)
*
* @since 3.0
*/
protected final IColumnFormatter getColumnFormatter() {
return formatter;
}
/**
* {@inheritDoc}
* <p>
* Implementation note: the {@link ISelectionListener} will receive a list with the selected values. Since the combo only supports a single selection, the
* value will be the one element in the list. If there is no selection or the 'empty' selection entry is selected, the list will be empty.
*/
public void addSelectionListener(final ISelectionListener selectionListener) {
Assert.isNotNull(selectionListener, "selectionListener is null"); //$NON-NLS-1$
if (selectionListeners == null) {
selectionListeners = new ListenerList<ISelectionListener>(ISelectionListener.class);
addPropertyChangeListener(IComboRidget.PROPERTY_SELECTION, new PropertyChangeListener() {
public void propertyChange(final PropertyChangeEvent evt) {
notifySelectionListeners(evt.getOldValue(), evt.getNewValue());
}
});
}
selectionListeners.add(selectionListener);
}
public void removeSelectionListener(final ISelectionListener selectionListener) {
if (selectionListeners != null) {
selectionListeners.remove(selectionListener);
}
}
public void bindToModel(final IObservableList optionValues, final Class<? extends Object> rowClass, final String renderingMethod,
final IObservableValue selectionValue) {
unbindUIControl();
this.optionValues = optionValues;
this.rowClass = rowClass;
this.renderingMethod = renderingMethod;
this.selectionValue = selectionValue;
bindUIControl();
if (defaultSelection != null) {
setDefaultSelection(defaultSelection);
}
}
/**
* @since 4.0
*/
public void bindToModel(final SelectableListHolder<?> listHolder, final String renderMethodName) {
if (renderMethodName != null) {
final ConverterFactory<?, String> converterFactory = listHolder.getConverterFactory(renderMethodName);
setUIControlToModelConverter(converterFactory.createToFromConverter());
setModelToUIControlConverter(converterFactory.createFromToConverter());
}
bindToModel(listHolder, SelectableListHolder.PROP_LIST, listHolder.getGuessedType(), null, listHolder, SelectableListHolder.SELECTION_PROPERTY);
}
public void bindToModel(final Object listHolder, final String listPropertyName, final Class<? extends Object> rowClass, final String renderingMethod,
final Object selectionHolder, final String selectionPropertyName) {
IObservableList listObservableValue;
if (AbstractSWTWidgetRidget.isBean(rowClass)) {
listObservableValue = BeansObservables.observeList(listHolder, listPropertyName);
} else {
listObservableValue = PojoObservables.observeList(listHolder, listPropertyName);
}
IObservableValue selectionObservableValue;
if (AbstractSWTWidgetRidget.isBean(selectionHolder.getClass())) {
selectionObservableValue = BeansObservables.observeValue(selectionHolder, selectionPropertyName);
} else {
selectionObservableValue = PojoObservables.observeValue(selectionHolder, selectionPropertyName);
}
bindToModel(listObservableValue, rowClass, renderingMethod, selectionObservableValue);
}
/**
* @since 6.1
*/
public Object getDefaultSelection() {
return defaultSelection;
}
public Object getEmptySelectionItem() {
return emptySelection;
}
// TODO [ev] should method return null when not bound? See ListRidget#getObservableList()
public IObservableList getObservableList() {
return rowObservables;
}
public String getText() {
return text;
}
public Object getSelection() {
final Object selection = selectionObservable.getValue();
return selection == emptySelection ? null : selection;
}
public int getSelectionIndex() {
int result = -1;
final Object selection = selectionObservable.getValue();
if (emptySelection != selection) {
result = rowObservables.indexOf(selection);
}
return result;
}
@Override
public boolean isDisableMandatoryMarker() {
return hasInput();
}
public boolean isMarkSelectionMismatch() {
return markSelectionMismatch;
}
/**
* @since 3.0
*/
public void setColumnFormatter(final IColumnFormatter formatter) {
this.formatter = formatter;
}
/**
* @since 6.1
*/
public void setDefaultSelection(final Object defaultSelection) {
this.defaultSelection = defaultSelection;
if (optionValues != null && selectionValue != null && selectionValue.getValue() == null) {
if (SwtUtilities.isDisposed(getUIControl())) {
selectionValue.setValue(defaultSelection);
} else {
setSelection(defaultSelection);
}
}
}
public void setEmptySelectionItem(final Object emptySelection) {
this.emptySelection = emptySelection;
}
public void setMarkSelectionMismatch(final boolean mark) {
if (mark != markSelectionMismatch) {
if (mark && selectionMismatchMarker == null) {
selectionMismatchMarker = new ErrorMessageMarker(Messages.AbstractComboRidget_markerMessage_selectionMismatch);
}
markSelectionMismatch = mark;
applyMarkSelectionMismatch();
}
}
public void setSelection(final Object newSelection) {
assertIsBoundToModel();
final Object oldSelection = selectionObservable.getValue();
if (oldSelection != newSelection) {
if (newSelection == null || !rowObservables.contains(newSelection)) {
if (!SwtUtilities.isDisposed(getUIControl())) {
clearUIControlListSelection();
}
}
selectionObservable.setValue(newSelection);
selectionEnforcer.saveSelection();
}
}
public void setSelection(final int index) {
if (index == -1) {
setSelection(null);
} else {
final Object newSelection = rowObservables.get(index);
setSelection(newSelection);
}
}
public void setText(final String text) {
Assert.isNotNull(text);
if (!StringUtils.equals(text, this.text)) {
final String oldText = this.text;
this.text = text;
firePropertyChange(PROPERTY_TEXT, oldText, this.text);
applyText();
}
}
public void setModelToUIControlConverter(final IConverter converter) {
objToStrConverter = (converter != null) ? converter : new ObjectToStringConverter();
}
public void setUIControlToModelConverter(final IConverter converter) {
strToObjConverter = (converter != null) ? converter : new StringToObjectConverter();
}
@Override
public void updateFromModel() {
// dont do anything if no model is bound
if (optionValues == null) {
return;
}
assertIsBoundToModel();
super.updateFromModel();
// disable the selection binding, because updating the combo items
// causes the selection to change temporarily
selectionValidator.enableBinding(false);
try {
listBindingExternal.updateModelToTarget();
updateValueToItem();
} finally {
selectionValidator.enableBinding(true);
}
selectionBindingExternal.updateModelToTarget();
if (selectionBindingInternal != null) {
selectionBindingInternal.updateModelToTarget();
}
// Bug 304733: clear selection if not in rowObservables
applyMarkSelectionMismatch();
selectionEnforcer.saveSelection();
}
/**
* @since 3.0
*/
protected void assertIsBoundToModel() {
if (optionValues == null) {
final String msg = String.format("ridget with ID '%s' is not bound to a model", getID()); //$NON-NLS-1$
throw new BindingException(msg);
}
}
// abstract methods
///////////////////
/**
* Attach a given {@link SelectionListener} to the combo.
*
* @param listener
* {@link SelectionListener}; never null.
* @since 3.0
*/
protected abstract void addSelectionListener(SelectionListener listener);
/**
* Attach a text modify listener to the combo. The listener must invoke {@code ridget.setText(...)} if the control's text is modified.
*/
protected abstract void addTextModifyListener();
/**
* Deselects all selected items in the controls list.
*/
protected abstract void clearUIControlListSelection();
/**
* @return The items of the controls list. May be an empty array.
*/
protected abstract String[] getUIControlItems();
/**
* @return an observable observing the items attribute of the control.
*/
protected abstract IObservableList getUIControlItemsObservable();
/**
* @return an observable observing the selection attribute of the control.
*/
protected abstract ISWTObservableValue getUIControlSelectionObservable();
/**
* Return the current text in the combo.
*
* @return a String; never null; may be empty
* @since 2.0
*/
protected abstract String getUIControlText();
/**
* Selects the item in the controls list.
*/
protected abstract void selectInUIControl(int index);
/**
* @return The index of the item in the controls list or -1 if no such item is found.
*/
protected abstract int indexOfInUIControl(String item);
/**
* Removes all of the items from the controls list and clears the controls text field.
*/
protected abstract void removeAllFromUIControl();
/**
* Remove a given {@link SelectionListener} from the combo.
*
* @param listener
* the {@link SelectionListener}; never null.
* @since 3.0
*/
protected abstract void removeSelectionListener(SelectionListener listener);
/**
* Remove the text modify listener from the combo.
*
* @see #addTextModifyListener()
* @since 2.0
*/
protected abstract void removeTextModifyListener();
/**
* Make the given array the list of selectable items in the combo.
*
* @param arrItems
* an array; never null.
* @since 1.2
*/
protected abstract void setItemsToControl(String[] arrItems);
/**
* @since 6.0
*/
protected abstract void setItemsToControl(Object[] arrItems);
/**
* Set the given {@code text} to the combo.
*
* @param text
* a String; never null; may be empty
* @since 2.0
*/
protected abstract void setTextToControl(String text);
/**
* Updates the editable state of the ridget's control.
* <p>
* <b>Implementation note</b>: This method is invoked when
* <ul>
* <li>a control is bound to the ridget</li>
* <li>the 'output only' or 'enabled' markers change state. For some combo widgets, not editable implies disabled so the two states overlap.</li>
* </ul>
*
* @since 3.0
*/
protected abstract void updateEditable();
// helping methods
//////////////////
private void applyEnabled() {
if (super.isEnabled()) {
bindControlToSelectionAndUpdate();
} else {
unbindControlFromSelectionAndClear();
}
}
private void applyText() {
if (!SwtUtilities.isDisposed(getUIControl())) {
if (!StringUtils.equals(text, getUIControlText())) {
setTextToControl(text);
}
}
}
private void applyMarkSelectionMismatch() {
final Object selection = selectionObservable.getValue();
if (markSelectionMismatch && selection != null && !rowObservables.contains(selection)) {
Assert.isNotNull(markSelectionMismatch);
addMarker(selectionMismatchMarker);
} else {
if (selectionMismatchMarker != null) {
removeMarker(selectionMismatchMarker);
}
}
}
/**
* Restores the list of items / selection in the combo, when the ridget is enabled.
*/
private void bindControlToSelectionAndUpdate() {
if (getUIControl() != null) {
/* update list of items in combo */
updateValueToItem();
/* re-create selectionBinding */
final ISWTObservableValue controlSelection = getUIControlSelectionObservable();
final UpdateValueStrategy controlSelectionBindingStrategy = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE);
controlSelectionBindingStrategy.setConverter(strToObjConverter).setAfterGetValidator(selectionValidator);
controlSelectionBindingStrategy.setBeforeSetValidator(new IValidator() {
public IStatus validate(final Object value) {
if (isOutputOnly()) {
return Status.CANCEL_STATUS;
}
return Status.OK_STATUS;
}
});
final DataBindingContext dbc = new DataBindingContext();
selectionBindingInternal = dbc.bindValue(controlSelection, selectionObservable, controlSelectionBindingStrategy, new UpdateValueStrategy(
UpdateValueStrategy.POLICY_UPDATE).setConverter(objToStrConverter));
/* update selection in combo */
selectionBindingInternal.updateModelToTarget();
}
}
private void disposeBinding(final Binding binding) {
if (binding != null && !binding.isDisposed()) {
binding.dispose();
}
}
private String getItemFromValue(final Object value) {
Object valueObject = value;
if (valueObject != null && formatter != null) {
valueObject = formatter.getText(value);
}
if (valueObject != null && renderingMethod != null) {
valueObject = ReflectionUtils.invoke(value, renderingMethod, (Object[]) null);
}
String result;
if (valueObject == null || valueObject.toString() == null) {
result = ""; //$NON-NLS-1$
} else {
result = valueObject.toString();
}
return result;
}
/**
* Returns the value of the given item.
*
* @param item
* item of combo box
* @return value relevant object; {@code null} or empty string if no relevant object exists
*/
private Object getValueFromItem(final String item) {
final String[] uiItems = getUIControlItems();
for (int i = 0; i < uiItems.length; i++) {
if (uiItems[i].equals(item)) {
return rowObservables.get(i);
}
}
if (rowClass == String.class) {
return ""; //$NON-NLS-1$
} else {
return null;
}
}
private boolean hasInput() {
final Object selection = selectionObservable.getValue();
return selection != null && selection != emptySelection;
}
private void notifySelectionListeners(final Object oldValue, final Object newValue) {
if (selectionListeners != null) {
final List<Object> oldSelectionList = new ArrayList<Object>();
if (oldValue != null) {
oldSelectionList.add(oldValue);
}
final List<Object> newSelectionList = new ArrayList<Object>();
if (newValue != null) {
newSelectionList.add(newValue);
}
final SelectionEvent event = new SelectionEvent(this, oldSelectionList, newSelectionList);
for (final ISelectionListener listener : selectionListeners.getListeners()) {
listener.ridgetSelected(event);
}
}
}
/**
* Clears the list of items in the combo, when the ridget is disabled.
*/
private void unbindControlFromSelectionAndClear() {
if (getUIControl() != null && !super.isEnabled()) {
/* dispose selectionBinding to avoid sync */
disposeBinding(selectionBindingInternal);
selectionBindingInternal = null;
/* clear combo */
if (MarkerSupport.isHideDisabledRidgetContent()) {
removeAllFromUIControl();
}
}
}
private void updateValueToItem() {
final List<Object> items = new ArrayList<Object>();
try {
items.addAll(getItemsFromModel());
} finally {
if (getUIControl() != null) {
final Object[] arrItems = items.toArray(new Object[items.size()]);
setItemsToControl(arrItems);
}
}
}
/**
* @since 6.0
*/
protected List<Object> getItemsFromModel() {
final List<Object> items = new ArrayList<Object>();
for (final Object value : rowObservables) {
if (value == null || value.toString() == null) {
throw new NullPointerException("The item value for a model element is null"); //$NON-NLS-1$
}
final String item = (String) objToStrConverter.convert(value);
items.add(item);
}
return items;
}
/**
* @since 6.0
*/
protected String[] getStringArray(final Object[] array) {
return Arrays.copyOf(array, array.length, String[].class);
}
// helping classes
//////////////////
/**
* Convert from model object to combo box items (strings).
*/
private final class ObjectToStringConverter extends Converter {
public ObjectToStringConverter() {
super(Object.class, String.class);
}
public Object convert(final Object fromObject) {
return getItemFromValue(fromObject);
}
}
/**
* Convert from combo box items (strings) to model objects.
*/
private final class StringToObjectConverter extends Converter {
public StringToObjectConverter() {
super(String.class, Object.class);
}
public Object convert(final Object fromObject) {
return getValueFromItem((String) fromObject);
}
}
/**
* This validator can be used to interrupt an update request
*/
private final class SelectionBindingValidator implements IValidator {
private boolean isEnabled = true;
public IStatus validate(final Object value) {
IStatus result = Status.OK_STATUS;
// disallow control to ridget update, isEnabled == false || output
if (!isEnabled) {
result = Status.CANCEL_STATUS;
}
return result;
}
void enableBinding(final boolean isEnabled) {
this.isEnabled = isEnabled;
}
}
/**
* Upon a selection change:
* <ul>
* <li>fire a PROPERTY_SELECTION event and</li>
* <li>update the mandatory marker state</li>
* </ul>
*/
private final class ValueChangeNotifier implements IValueChangeListener {
public void handleValueChange(final ValueChangeEvent event) {
final Object oldValue = event.diff.getOldValue();
final Object newValue = event.diff.getNewValue();
try {
firePropertyChange(IComboRidget.PROPERTY_SELECTION, oldValue, newValue);
} finally {
disableMandatoryMarkers(hasInput());
applyMarkSelectionMismatch();
}
}
}
/**
* TwoWayAdapter that saves the current selection, when outputOnly changes and applies it again after the user tries to select an entry in the combo.
*
* @since 3.0
*/
private final class SelectionEnforcer extends SelectionAdapter {
private int selectionIndex;
@Override
public void widgetSelected(final org.eclipse.swt.events.SelectionEvent e) {
if (getUIControl() != null && isOutputOnly()) {
final Widget uiControl = e.widget;
resetSelection(uiControl);
}
}
/**
* Save the currently selected value of the Combo.
*/
public void saveSelection() {
if (isBound()) {
selectionIndex = getSelectionIndex();
// System.out.println("## saveSelection; selectionIndex: " + selectionIndex);
}
}
private boolean isBound() {
return listBindingExternal != null && selectionBindingExternal != null;
}
private void resetSelection(final Widget uiControl) {
// System.out.println("## propertyChange; resetSel: " + selectionIndex);
if (uiControl instanceof CCombo) {
if (selectionIndex == -1) {
((CCombo) uiControl).deselectAll();
} else {
((CCombo) uiControl).select(selectionIndex);
}
} else if (uiControl instanceof Combo) {
if (selectionIndex == -1) {
((Combo) uiControl).deselectAll();
} else {
((Combo) uiControl).select(selectionIndex);
}
} else if (uiControl instanceof CompletionCombo) {
if (selectionIndex == -1) {
((CompletionCombo) uiControl).deselectAll();
} else {
((CompletionCombo) uiControl).select(selectionIndex);
}
}
}
}
}