package edu.ualberta.med.biobank.mvp.view.item; import java.util.ArrayList; import java.util.List; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ComboViewer; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import edu.ualberta.med.biobank.mvp.user.ui.SelectedValueField; import edu.ualberta.med.biobank.mvp.util.Converter; public class ComboBox<T> extends AbstractValueField<T> implements SelectedValueField<T> { private static final Listener KILL_MOUSE_WHEEL_LISTENER = new Listener() { @Override public void handleEvent(Event event) { event.doit = false; } }; private final ISelectionChangedListener selectionListener = new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { setValueInternal(getSelectedValue()); } }; private ComboViewer comboViewer; private List<T> options = new ArrayList<T>(); private Converter<T, String> optionLabeler; public synchronized void setComboViewer(ComboViewer comboViewer) { unbindOldComboViewer(); this.comboViewer = comboViewer; comboViewer.setContentProvider(new ArrayContentProvider()); comboViewer.setLabelProvider(new CustomLabelProvider()); setOptions(options); updateGui(); comboViewer.addSelectionChangedListener(selectionListener); disableMouseWheel(); } @Override protected void updateGui() { if (comboViewer != null) { Display display = comboViewer.getCombo().getDisplay(); display.asyncExec(new Update()); } } @Override public void setOptions(List<T> options) { this.options = new ArrayList<T>(options); if (comboViewer != null) { Display display = comboViewer.getCombo().getDisplay(); display.asyncExec(new UpdateOptions(options)); } } @Override public void setOptionLabeller(Converter<T, String> labeler) { this.optionLabeler = labeler; } private void unbindOldComboViewer() { if (comboViewer != null) { comboViewer .removeSelectionChangedListener(selectionListener); } } private void disableMouseWheel() { Control combo = comboViewer.getControl(); combo.addListener(SWT.MouseWheel, KILL_MOUSE_WHEEL_LISTENER); } private class CustomLabelProvider extends LabelProvider { @SuppressWarnings("unchecked") @Override public String getText(Object element) { return optionLabeler.convert((T) element); } } private IStructuredSelection getStructuredSelection() { if (getValue() != null) { return new StructuredSelection(getValue()); } return new StructuredSelection(); } private T getSelectedValue() { T value = null; IStructuredSelection selection = (IStructuredSelection) comboViewer .getSelection(); if (selection != null && !selection.isEmpty()) { @SuppressWarnings("unchecked") T tmp = (T) selection.getFirstElement(); value = tmp; } return value; } private boolean hasIllegalValue() { return getValue() != null && !options.contains(getValue()); } private class UpdateOptions implements Runnable { private final List<T> options; public UpdateOptions(List<T> options) { this.options = options; } @Override public void run() { if (comboViewer != null && !comboViewer.getCombo().isDisposed()) { comboViewer.setInput(options); comboViewer.refresh(); if (hasIllegalValue()) { setValue(null, true); } } } } private class Update implements Runnable { @Override public void run() { if (hasIllegalValue()) { setValue(null, false); } else if (comboViewer != null && !comboViewer.getCombo().isDisposed()) { comboViewer.removeSelectionChangedListener(selectionListener); comboViewer.setSelection(getStructuredSelection(), true); comboViewer.addSelectionChangedListener(selectionListener); } } } }