//Created by plusminus on 13:33:21 - 16.05.2008
package org.androad.ui.common;
import java.util.ArrayList;
import java.util.NoSuchElementException;
import org.androad.util.constants.Constants;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.EditText;
public abstract class InlineAutoCompleterDynamic implements OnKeyListener, TextWatcher, Constants{
// ===========================================================
// Final Fields
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
protected EditText mEditText;
// ===========================================================
// Constructors
// ===========================================================
public InlineAutoCompleterDynamic(final EditText aEditTextToApplyTo){
this.mEditText = aEditTextToApplyTo;
this.mEditText.setOnKeyListener(this);
this.mEditText.addTextChangedListener(this);
}
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods from SuperClass/Interfaces
// ===========================================================
@Override
public boolean onKey(final View arg0, final int arg1, final KeyEvent ke) {
if(ke.getAction() == KeyEvent.ACTION_DOWN){
if(ke.getKeyCode() == KeyEvent.KEYCODE_ENTER || ke.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER){
return InlineAutoCompleterDynamic.this.onEnter();
}else if(ke.getKeyCode() == KeyEvent.KEYCODE_CLEAR || ke.getKeyCode() == KeyEvent.KEYCODE_DEL){
final EditText et = InlineAutoCompleterDynamic.this.mEditText;
final int selStart = et.getSelectionStart();
final int selEnd = et.getSelectionEnd();
if(selStart != selEnd){
et.getText().delete(selStart, selEnd);
return true;
}
}
}
return false;
}
@Override
public void afterTextChanged(final Editable s) { }
@Override
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after){ }
@Override
public void onTextChanged(final CharSequence s, final int start, final int before, final int count){
// Log.d(Constants.DEBUGTAG, "ON: s=" + s + " start=" + start + " before=" + before + " count=" + count);
if((count - before <= 1 // > 1 when this method was invoked by a completion (users type only 1 char each call). <= 0 when overwriting the selection.
&& count != 0 // count == 0, when letters are deleted
&& start != 0 // on the first letter
) || (s.length() == 1 && start == 0 && before == 0 && count == 1)) {
InlineAutoCompleterDynamic.this.performAutoCompletion();
}
}
// ===========================================================
// Methods
// ===========================================================
protected String getCurrent(){
final int selStart = this.mEditText.getSelectionStart();
// Log.d(DEBUGTAG, "SelStart: " + selStart);
if(selStart >= 0) {
return this.mEditText.getText().toString().substring(0, selStart);
} else {
return this.mEditText.getText().toString();
}
}
private void complete(final String aCandidate){
this.mEditText.post(new Runnable(){
@Override
public void run() {
final String strBefore = InlineAutoCompleterDynamic.this.getCurrent();
/* The Content of the EditText may have changed since the candidate was determined. */
if(!aCandidate.toLowerCase().startsWith(strBefore.toLowerCase())) {
return;
}
InlineAutoCompleterDynamic.this.mEditText.setText(aCandidate);
final int lenBefore = strBefore.length();
final int lenNew = aCandidate.length();
if(lenBefore <= lenNew) {
InlineAutoCompleterDynamic.this.mEditText.setSelection(lenBefore, lenNew);
}
}
});
}
public abstract boolean onEnter();
private void performAutoCompletion(){
new Thread(new Runnable(){
@Override
public void run() {
try {
final String strNew = InlineAutoCompleterDynamic.this.onGetAutoCompletionStrings().get(0);
InlineAutoCompleterDynamic.this.complete(strNew);
} catch (final NoSuchElementException e) {
return;
}
}
}, "AutoCompletion-Thread").start();
}
public abstract ArrayList<String> onGetAutoCompletionStrings() throws NoSuchElementException;
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}