// License: GPL. Copyright 2007 by Immanuel Scholz and others package org.openstreetmap.josm.gui.widgets; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.util.Collection; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.JComboBox; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.JTextComponent; import javax.swing.text.PlainDocument; /** * @author guilhem.bonnefille@gmail.com */ public class AutoCompleteComboBox extends JComboBox { private boolean autocompleteEnabled = true; /** * Auto-complete a JComboBox. * * Inspired by http://www.orbital-computer.de/JComboBox/ */ class AutoCompleteComboBoxDocument extends PlainDocument { private JComboBox comboBox; private boolean selecting = false; public AutoCompleteComboBoxDocument(final JComboBox comboBox) { this.comboBox = comboBox; } @Override public void remove(int offs, int len) throws BadLocationException { if (selecting) return; super.remove(offs, len); } @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { if(selecting || (offs == 0 && str.equals(getText(0, getLength())))) return; boolean initial = (offs == 0 && getLength() == 0 && str.length() > 1); super.insertString(offs, str, a); // return immediately when selecting an item // Note: this is done after calling super method because we need // ActionListener informed if (selecting) return; if (!autocompleteEnabled) return; int size = getLength(); int start = offs+str.length(); int end = start; String curText = getText(0, size); // lookup and select a matching item Object item = lookupItem(curText); setSelectedItem(item); if(initial) { start = 0; } if (item != null) { String newText = item.toString(); if(!newText.equals(curText)) { selecting = true; super.remove(0, size); super.insertString(0, newText, a); selecting = false; start = size; end = getLength(); } } JTextComponent editor = (JTextComponent)comboBox.getEditor().getEditorComponent(); editor.setSelectionStart(start); editor.setSelectionEnd(end); } private void setSelectedItem(Object item) { selecting = true; comboBox.setSelectedItem(item); selecting = false; } private Object lookupItem(String pattern) { ComboBoxModel model = comboBox.getModel(); for (int i = 0, n = model.getSize(); i < n; i++) { Object currentItem = model.getElementAt(i); if (currentItem.toString().startsWith(pattern)) return currentItem; } return null; } } public AutoCompleteComboBox() { final JTextComponent editor = (JTextComponent) this.getEditor().getEditorComponent(); editor.setDocument(new AutoCompleteComboBoxDocument(this)); editor.addFocusListener( new FocusListener() { public void focusLost(FocusEvent e) { } public void focusGained(FocusEvent e) { editor.selectAll(); } } ); } public void setPossibleItems(Collection<String> elems) { DefaultComboBoxModel model = (DefaultComboBoxModel)this.getModel(); Object oldValue = this.getEditor().getItem(); model.removeAllElements(); for (String elem : elems) { model.addElement(elem); } this.getEditor().setItem(oldValue); } protected boolean isAutocompleteEnabled() { return autocompleteEnabled; } protected void setAutocompleteEnabled(boolean autocompleteEnabled) { this.autocompleteEnabled = autocompleteEnabled; } }