package org.minimalj.frontend.swing.toolkit;

import java.awt.Component;
import java.util.List;

import javax.swing.JComboBox;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.JTextComponent;

import org.minimalj.frontend.toolkit.ClientToolkit.Input;
import org.minimalj.frontend.toolkit.ClientToolkit.InputComponentListener;

public class SwingTextFieldAutocomplete extends JComboBox<String> implements Input<String> {
	private static final long serialVersionUID = -1;

	public SwingTextFieldAutocomplete(InputComponentListener changeListener, List<String> suggestions) {
		super(suggestions.toArray(new String[suggestions.size()]));
		setEditable(true);
		Component c = getEditor().getEditorComponent();
		if (c instanceof JTextComponent) {
			JTextComponent tc = (JTextComponent) c;
			tc.getDocument().addDocumentListener(new DocumentListener() {

				@Override
				public void changedUpdate(DocumentEvent arg0) {
					changeListener.changed(SwingTextFieldAutocomplete.this);
					hideIfNoMatchingItem();
				}

				@Override
				public void insertUpdate(DocumentEvent arg0) {
					changeListener.changed(SwingTextFieldAutocomplete.this);
					hideIfNoMatchingItem();
				}

				@Override
				public void removeUpdate(DocumentEvent arg0) {
					changeListener.changed(SwingTextFieldAutocomplete.this);
					hideIfNoMatchingItem();
				}
			});
		} else {
			throw new IllegalStateException("Editing component is not a JTextComponent!");
		}
	}

	private void hideIfNoMatchingItem() {
		if (isPopupVisible()) {
			String selectedItem = (String) getSelectedItem();
			if (selectedItem != null && !selectedItem.startsWith(getValue())) {
				hidePopup();
			}
		}
	}

	@Override
	public int getSelectedIndex() {
		if (getEditor() == null) {
			return -1;
		}
		
		String value = getValue();
		if (value == null) {
			return -1;
		} else {
			int index = -1;
			for (int i = 0; i < getModel().getSize(); i++) {
				String item = getModel().getElementAt(i);
				if (item != null && item.startsWith(value)) {
					index = i;
					break;
				}
			}
			return index;
		}
	}	
	
	@Override
	public void setValue(String text) {
		super.setSelectedItem(text);
	}

	@Override
	public String getValue() {
		Component c = getEditor().getEditorComponent();
		JTextComponent tc = (JTextComponent) c;
		return tc.getText();
	}

}
@@ -82,19 +82,130 @@
 ava.
-util.List;%0A
+awt.event.FocusAdapter;%0Aimport java.awt.event.FocusEvent;%0Aimport java.util.List;%0A%0Aimport javax.swing.DefaultComboBoxModel;
 %0Aimp
@@ -487,16 +487,54 @@
 istener;
+%0Aimport org.minimalj.util.StringUtils;
 %0A%0Apublic
@@ -1548,16 +1548,850 @@
 %0A%09%09%09%7D);%0A
+%09%09%09%0A%09%09%09tc.addFocusListener(new FocusAdapter() %7B%0A%09%09%09%09@Override%0A%09%09%09%09public void focusGained(FocusEvent e) %7B%0A%09%09%09%09%09DefaultComboBoxModel%3CString%3E model = (DefaultComboBoxModel%3CString%3E) getModel();%0A%09%09%09%09%09if (modelNeedsUpdate(model, suggestions)) %7B%0A%09%09%09%09%09%09String selection = tc.getText();%0A%09%09%09%09%09%09model.removeAllElements();%0A%09%09%09%09%09%09for (String s : suggestions) %7B%0A%09%09%09%09%09%09%09model.addElement(s);%0A%09%09%09%09%09%09%7D%0A%09%09%09%09%09%09tc.setText(selection);%0A%09%09%09%09%09%7D%0A%09%09%09%09%7D%0A%0A%09%09%09%09private boolean modelNeedsUpdate(DefaultComboBoxModel%3CString%3E model, List%3CString%3E suggestions) %7B%0A%09%09%09%09%09if (model.getSize() == suggestions.size()) %7B%0A%09%09%09%09%09%09for (int index=0; index%3Cmodel.getSize(); index++) %7B%0A%09%09%09%09%09%09%09if (!StringUtils.equals(model.getElementAt(index), suggestions.get(index))) %7B%0A%09%09%09%09%09%09%09%09return true;%0A%09%09%09%09%09%09%09%7D%0A%09%09%09%09%09%09%7D%0A%09%09%09%09%09%09return false;%0A%09%09%09%09%09%7D else %7B%0A%09%09%09%09%09%09return true;%0A%09%09%09%09%09%7D%0A%09%09%09%09%7D%0A%09%09%09%7D);%0A%0A
 %09%09%7D else
@@ -2475,24 +2475,27 @@
 ent!%22);%0A%09%09%7D%0A
+%09%09%0A
 %09%7D%0A%0A%09private

Update combo when gaining focus