package com.gwt.ui.client;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
public class AutoCompleteTextBox extends TextBox {
protected PopupPanel choicesPopup = new PopupPanel(true);
protected ListBox choices = new ListBox();
protected CompletionItems items = new SimpleAutoCompletionItems(new String[] {});
protected boolean popupAdded = false;
protected boolean visible = false;
/**
* Default Constructor
*/
public AutoCompleteTextBox() {
super();
addKeyUpHandler(new KeyUpHandler() {
@Override
public void onKeyUp(KeyUpEvent event) {
if (event.isDownArrow()) {
int selectedIndex = choices.getSelectedIndex();
selectedIndex++;
if (selectedIndex >= choices.getItemCount()) {
selectedIndex = 0;
}
choices.setSelectedIndex(selectedIndex);
return;
}
if (event.isUpArrow()) {
int selectedIndex = choices.getSelectedIndex();
selectedIndex--;
if (selectedIndex < 0) {
selectedIndex = choices.getItemCount()-1;
}
choices.setSelectedIndex(selectedIndex);
return;
}
if (event.getNativeKeyCode() == 13) {
if (visible) {
complete();
}
return;
}
if (event.getNativeKeyCode() == 27) {
choices.clear();
choicesPopup.hide();
visible = false;
return;
}
String text = getText();
String[] matches = new String[] {};
if (text.length() > 0) {
matches = items.getCompletionItems(text);
}
if (matches.length > 0) {
choices.clear();
for (int i = 0; i < matches.length; i++) {
choices.addItem((String)matches[i]);
}
// if there is only one match and it is what is in the
// text field anyways there is no need to show autocompletion
if (matches.length == 1 && matches[0].compareTo(text) == 0) {
choicesPopup.hide();
} else {
choices.setSelectedIndex(0);
choices.setVisibleItemCount(matches.length + 1);
if (!popupAdded) {
RootPanel.get().add(choicesPopup);
popupAdded = true;
}
choicesPopup.show();
visible = true;
choicesPopup.setPopupPosition(getAbsoluteLeft(), getAbsoluteTop() + getOffsetHeight());
// choicesPopup.setWidth(this.getOffsetWidth() + "px");
choices.setWidth(getOffsetWidth() + "px");
}
} else {
visible = false;
choicesPopup.hide();
}
}
});
this.setStyleName("AutoCompleteTextBox");
choicesPopup.add(choices);
choicesPopup.addStyleName("AutoCompleteChoices");
choices.setStyleName("list");
choices.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent arg0) {
complete();
}
});
choices.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent arg0) {
complete();
}
});
}
/**
* Sets an "algorithm" returning completion items You can define your own way how the textbox retrieves autocompletion items by
* implementing the CompletionItems interface and setting the according object
*
* @see SimpleAutoCompletionItem
* @param items CompletionItem implementation
*/
public void setCompletionItems(CompletionItems items) {
this.items = items;
}
/**
* Returns the used CompletionItems object
*
* @return CompletionItems implementation
*/
public CompletionItems getCompletionItems() {
return this.items;
}
// add selected item to textbox
protected void complete() {
if (choices.getItemCount() > 0) {
this.setText(choices.getItemText(choices.getSelectedIndex()));
}
choices.clear();
choicesPopup.hide();
}
}