source: josm/trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletingComboBox.java@ 3311

Last change on this file since 3311 was 3311, checked in by bastiK, 14 years ago

fix last commit

  • Property svn:eol-style set to native
File size: 9.0 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.gui.tagging.ac;
3
4import java.awt.Component;
5import java.awt.event.FocusEvent;
6import java.awt.event.FocusListener;
7import java.util.Collection;
8
9import javax.swing.ComboBoxEditor;
10import javax.swing.ComboBoxModel;
11import javax.swing.DefaultComboBoxModel;
12import javax.swing.JComboBox;
13import javax.swing.JLabel;
14import javax.swing.JList;
15import javax.swing.ListCellRenderer;
16import javax.swing.text.AttributeSet;
17import javax.swing.text.BadLocationException;
18import javax.swing.text.JTextComponent;
19import javax.swing.text.PlainDocument;
20import javax.swing.text.StyleConstants;
21
22import org.openstreetmap.josm.Main;
23
24/**
25 * @author guilhem.bonnefille@gmail.com
26 */
27public class AutoCompletingComboBox extends JComboBox {
28
29 private boolean autocompleteEnabled = true;
30
31 /**
32 * Auto-complete a JComboBox.
33 *
34 * Inspired by http://www.orbital-computer.de/JComboBox/
35 */
36 class AutoCompletingComboBoxDocument extends PlainDocument {
37 private JComboBox comboBox;
38 private boolean selecting = false;
39
40 public AutoCompletingComboBoxDocument(final JComboBox comboBox) {
41 this.comboBox = comboBox;
42 }
43
44 @Override public void remove(int offs, int len) throws BadLocationException {
45 if (selecting)
46 return;
47 super.remove(offs, len);
48 }
49
50 @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
51 if (selecting || (offs == 0 && str.equals(getText(0, getLength()))))
52 return;
53 boolean initial = (offs == 0 && getLength() == 0 && str.length() > 1);
54 super.insertString(offs, str, a);
55
56 // return immediately when selecting an item
57 // Note: this is done after calling super method because we need
58 // ActionListener informed
59 if (selecting)
60 return;
61 if (!autocompleteEnabled)
62 return;
63 // input method for non-latin characters (e.g. scim)
64 if (a != null && a.isDefined(StyleConstants.ComposedTextAttribute))
65 return;
66
67 int size = getLength();
68 int start = offs+str.length();
69 int end = start;
70 String curText = getText(0, size);
71
72 // if the text starts with a number we don't autocomplete
73 if (!Main.pref.getBoolean("autocomplete.dont_complete_numbers", false)) {
74 try {
75 Long.parseLong(str);
76 if (curText.length() == 0) {
77 // we don't autocomplete on numbers
78 return;
79 }
80 Long.parseLong(curText);
81 return;
82 } catch (NumberFormatException e) {
83 // either the new text or the current text isn't a number. We continue with
84 // autocompletion
85 }
86 }
87
88 // lookup and select a matching item
89 Object item = lookupItem(curText);
90 setSelectedItem(item);
91 if (initial) {
92 start = 0;
93 }
94 if (item != null) {
95 String newText = ((AutoCompletionListItem) item).getValue();
96 if (!newText.equals(curText))
97 {
98 selecting = true;
99 super.remove(0, size);
100 super.insertString(0, newText, a);
101 selecting = false;
102 start = size;
103 end = getLength();
104 }
105 }
106 JTextComponent editor = (JTextComponent)comboBox.getEditor().getEditorComponent();
107 editor.setSelectionStart(start);
108 editor.setSelectionEnd(end);
109 }
110
111 private void setSelectedItem(Object item) {
112 selecting = true;
113 comboBox.setSelectedItem(item);
114 selecting = false;
115 }
116
117 private Object lookupItem(String pattern) {
118 ComboBoxModel model = comboBox.getModel();
119 AutoCompletionListItem bestItem = null;
120 for (int i = 0, n = model.getSize(); i < n; i++) {
121 AutoCompletionListItem currentItem = (AutoCompletionListItem) model.getElementAt(i);;
122 if (currentItem.getValue().startsWith(pattern)) {
123 if (bestItem == null || currentItem.getPriority().compareTo(bestItem.getPriority()) > 0) {
124 bestItem = currentItem;
125 }
126 }
127 }
128 return bestItem; // may be null
129 }
130 }
131
132 public AutoCompletingComboBox() {
133 setRenderer(new AutoCompleteListCellRenderer());
134 final JTextComponent editor = (JTextComponent) this.getEditor().getEditorComponent();
135 editor.setDocument(new AutoCompletingComboBoxDocument(this));
136 editor.addFocusListener(
137 new FocusListener() {
138 public void focusLost(FocusEvent e) {
139 }
140 public void focusGained(FocusEvent e) {
141 editor.selectAll();
142 }
143 }
144 );
145 }
146
147 /**
148 * Convert the selected item into a String
149 * that can be edited in the editor component.
150 *
151 * @param editor the editor
152 * @param item excepts AutoCompletionListItem, String and null
153 */
154 @Override public void configureEditor(ComboBoxEditor editor, Object item) {
155 if (item == null) {
156 editor.setItem(null);
157 } else if (item instanceof String) {
158 editor.setItem(item);
159 } else if (item instanceof AutoCompletionListItem) {
160 editor.setItem(((AutoCompletionListItem)item).getValue());
161 } else
162 throw new IllegalArgumentException();
163 }
164
165 /**
166 * Selects a given item in the ComboBox model
167 * @param item excepts AutoCompletionListItem, String and null
168 */
169 @Override public void setSelectedItem(Object item) {
170 if (item == null) {
171 super.setSelectedItem(null);
172 } else if (item instanceof AutoCompletionListItem) {
173 super.setSelectedItem(item);
174 } else if (item instanceof String) {
175 String s = (String) item;
176 // find the string in the model or create a new item
177 for (int i=0; i< getModel().getSize(); i++) {
178 AutoCompletionListItem acItem = (AutoCompletionListItem) getModel().getElementAt(i);
179 if (s.equals(acItem.getValue())) {
180 super.setSelectedItem(acItem);
181 return;
182 }
183 }
184 super.setSelectedItem(new AutoCompletionListItem(s, AutoCompletionItemPritority.UNKNOWN));
185 } else
186 throw new IllegalArgumentException();
187 }
188
189 /**
190 * sets the items of the combobox to the given strings
191 */
192 public void setPossibleItems(Collection<String> elems) {
193 DefaultComboBoxModel model = (DefaultComboBoxModel)this.getModel();
194 Object oldValue = this.getEditor().getItem();
195 model.removeAllElements();
196 for (String elem : elems) {
197 model.addElement(new AutoCompletionListItem(elem, AutoCompletionItemPritority.UNKNOWN));
198 }
199 this.getEditor().setItem(oldValue);
200 }
201
202 /**
203 * sets the items of the combobox to the given AutoCompletionListItems
204 */
205 public void setPossibleACItems(Collection<AutoCompletionListItem> elems) {
206 DefaultComboBoxModel model = (DefaultComboBoxModel)this.getModel();
207 Object oldValue = this.getEditor().getItem();
208 model.removeAllElements();
209 for (AutoCompletionListItem elem : elems) {
210 model.addElement(elem);
211 }
212 this.getEditor().setItem(oldValue);
213 }
214
215
216 protected boolean isAutocompleteEnabled() {
217 return autocompleteEnabled;
218 }
219
220 protected void setAutocompleteEnabled(boolean autocompleteEnabled) {
221 this.autocompleteEnabled = autocompleteEnabled;
222 }
223
224 /**
225 * ListCellRenderer for AutoCompletingComboBox
226 * renders an AutoCompletionListItem by showing only the string value part
227 */
228 public class AutoCompleteListCellRenderer extends JLabel implements ListCellRenderer {
229
230 public AutoCompleteListCellRenderer() {
231 setOpaque(true);
232 }
233
234 public Component getListCellRendererComponent(
235 JList list,
236 Object value,
237 int index,
238 boolean isSelected,
239 boolean cellHasFocus)
240 {
241 if (isSelected) {
242 setBackground(list.getSelectionBackground());
243 setForeground(list.getSelectionForeground());
244 } else {
245 setBackground(list.getBackground());
246 setForeground(list.getForeground());
247 }
248
249 AutoCompletionListItem item = (AutoCompletionListItem) value;
250 setText(item.getValue());
251 return this;
252 }
253 }
254}
Note: See TracBrowser for help on using the repository browser.