package edu.ualberta.med.biobank.widgets;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
public class SmartCombo extends Composite {
List<SelectionListener> listeners;
private String[] items;
private Combo combo;
boolean ignore;
boolean traversed;
char keyPress;
public SmartCombo(Composite parent, int style) {
super(parent, style);
listeners = new ArrayList<SelectionListener>();
GridLayout gl = new GridLayout();
gl.marginWidth = 0;
this.setLayout(gl);
combo = new Combo(this, SWT.DROP_DOWN);
items = new String[0];
ignore = false;
traversed = false;
combo.addKeyListener(new KeyListener() {
@Override
public void keyPressed(KeyEvent e) {
if (Character.isLetter(e.character) || e.keyCode == SWT.DEL
|| e.keyCode == SWT.BS || e.keyCode == SWT.Selection) {
ignore = false;
traversed = false;
} else {
ignore = true;
traversed = true;
}
// in case the user hits multiple keys, only consider the last
// pressed
keyPress = e.character;
}
@Override
public void keyReleased(KeyEvent e) {
if (!ignore && keyPress == e.character) {
refineList(combo.getText());
String newText = closestMatch();
int caretPosition = combo.getSelection().x;
// combo might need to be expanded
combo.setVisibleItemCount(combo.getItemCount());
combo.setListVisible(true);
if (newText.length() > 0) {
if (e.keyCode == SWT.DEL || e.keyCode == SWT.BS) {
combo.setText(newText.substring(0, caretPosition));
combo.setSelection(new Point(caretPosition,
caretPosition));
} else {
combo.setText(newText);
combo.setSelection(new Point(caretPosition, newText
.length()));
}
}
}
if (e.keyCode == SWT.Selection && !valid()) {
reset();
} else if (e.keyCode == SWT.Selection) {
combo.setListVisible(false);
Event event = new Event();
event.widget = SmartCombo.this;
notifyListeners(new SelectionEvent(event));
}
// ignore = false;
// traversed = false;
}
});
combo.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
}
@Override
public void focusLost(FocusEvent e) {
if (!valid()) {
reset();
}
}
});
combo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
@Override
public void widgetSelected(SelectionEvent e) {
// ignore traversal
if (!traversed) {
// System.out.println("Selected");
ignore = true;
if (combo.getSelectionIndex() == -1)
combo.select(0);
ignore = false;
Event event = new Event();
event.widget = SmartCombo.this;
notifyListeners(new SelectionEvent(event));
} else {
Event event = new Event();
event.widget = SmartCombo.this;
notifyListeners(new SelectionEvent(event));
}
}
});
}
protected void reset() {
refineList(""); //$NON-NLS-1$
combo.setVisibleItemCount(combo.getItemCount());
combo.select(0);
Event event = new Event();
event.widget = SmartCombo.this;
notifyListeners(new SelectionEvent(event));
}
protected boolean valid() {
String text = combo.getText();
for (int i = 0; i < items.length; i++) {
if (items[i].compareTo(text) == 0)
return true;
}
return false;
}
protected void refineList(String text) {
combo.remove(0, combo.getItemCount() - 1);
for (int i = 0; i < items.length; i++) {
String item = items[i];
if (item.startsWith(text))
combo.add(item);
}
}
protected String closestMatch() {
if (combo.getItemCount() > 0)
return combo.getItem(0);
return ""; //$NON-NLS-1$
}
public void setInput(String[] items) {
this.items = items;
reset();
}
public void setLayoutData(GridData combodata) {
combo.setLayoutData(combodata);
}
public String getSelection() {
return combo.getText();
}
public void addSelectionListener(SelectionListener listener) {
listeners.add(listener);
}
public void notifyListeners(SelectionEvent event) {
for (SelectionListener listener : listeners) {
listener.widgetSelected(event);
}
}
}