source: josm/trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletingTextField.java@ 4095

Last change on this file since 4095 was 4095, checked in by bastiK, 13 years ago

applied #6256 (patch by Hojoe) - Cursor Right behaviour after autocomplete not consistent

  • Property svn:eol-style set to native
File size: 7.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.tagging.ac;
3
4import java.awt.Component;
5import java.awt.event.FocusAdapter;
6import java.awt.event.FocusEvent;
7import java.awt.event.KeyAdapter;
8import java.awt.event.KeyEvent;
9import java.util.EventObject;
10import java.util.logging.Logger;
11
12import javax.swing.ComboBoxEditor;
13import javax.swing.JTable;
14import javax.swing.JTextField;
15import javax.swing.event.CellEditorListener;
16import javax.swing.table.TableCellEditor;
17import javax.swing.text.AttributeSet;
18import javax.swing.text.BadLocationException;
19import javax.swing.text.Document;
20import javax.swing.text.PlainDocument;
21import javax.swing.text.StyleConstants;
22
23import org.openstreetmap.josm.Main;
24import org.openstreetmap.josm.gui.util.TableCellEditorSupport;
25
26/**
27 * AutoCompletingTextField is an text field with autocompletion behaviour. It
28 * can be used as table cell editor in {@see JTable}s.
29 *
30 * Autocompletion is controlled by a list of {@see AutoCompletionListItem}s
31 * managed in a {@see AutoCompletionList}.
32 *
33 *
34 */
35public class AutoCompletingTextField extends JTextField implements ComboBoxEditor, TableCellEditor {
36 @SuppressWarnings("unused")
37 static private Logger logger = Logger.getLogger(AutoCompletingTextField.class.getName());
38
39 /**
40 * The document model for the editor
41 */
42 class AutoCompletionDocument extends PlainDocument {
43
44 /**
45 * inserts a string at a specific position
46 *
47 */
48 @Override
49 public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
50 if (autoCompletionList == null) {
51 super.insertString(offs, str, a);
52 return;
53 }
54
55 // input method for non-latin characters (e.g. scim)
56 if (a != null && a.isDefined(StyleConstants.ComposedTextAttribute)) {
57 super.insertString(offs, str, a);
58 return;
59 }
60
61 // if the current offset isn't at the end of the document we don't autocomplete.
62 // If a highlighted autocompleted suffix was present and we get here Swing has
63 // already removed it from the document. getLength() therefore doesn't include the
64 // autocompleted suffix.
65 //
66 if (offs < getLength()) {
67 super.insertString(offs, str, a);
68 return;
69 }
70
71 String currentText = getText(0, getLength());
72 // if the text starts with a number we don't autocomplete
73 if (Main.pref.getBoolean("autocomplete.dont_complete_numbers", true)) {
74 try {
75 Long.parseLong(str);
76 if (currentText.length() == 0) {
77 // we don't autocomplete on numbers
78 super.insertString(offs, str, a);
79 return;
80 }
81 Long.parseLong(currentText);
82 super.insertString(offs, str, a);
83 return;
84 } catch(NumberFormatException e) {
85 // either the new text or the current text isn't a number. We continue with
86 // autocompletion
87 }
88 }
89 String prefix = currentText.substring(0, offs);
90 autoCompletionList.applyFilter(prefix+str);
91 if (autoCompletionList.getFilteredSize()>0) {
92 // there are matches. Insert the new text and highlight the
93 // auto completed suffix
94 //
95 String matchingString = autoCompletionList.getFilteredItem(0).getValue();
96 remove(0,getLength());
97 super.insertString(0,matchingString,a);
98
99 // highlight from insert position to end position to put the caret at the end
100 setCaretPosition(offs + str.length());
101 moveCaretPosition(getLength());
102 } else {
103 // there are no matches. Insert the new text, do not highlight
104 //
105 String newText = prefix + str;
106 remove(0,getLength());
107 super.insertString(0,newText,a);
108 setCaretPosition(getLength());
109
110 }
111 }
112 }
113
114 /** the auto completion list user input is matched against */
115 protected AutoCompletionList autoCompletionList = null;
116
117 /**
118 * creates the default document model for this editor
119 *
120 */
121 @Override
122 protected Document createDefaultModel() {
123 return new AutoCompletionDocument();
124 }
125
126 protected void init() {
127 addFocusListener(
128 new FocusAdapter() {
129 @Override public void focusGained(FocusEvent e) {
130 selectAll();
131 applyFilter(getText());
132 }
133 }
134 );
135
136 addKeyListener(
137 new KeyAdapter() {
138
139 @Override
140 public void keyReleased(KeyEvent e) {
141 if (getText().equals("")) {
142 applyFilter("");
143 }
144 }
145 }
146 );
147 tableCellEditorSupport = new TableCellEditorSupport(this);
148 }
149
150 /**
151 * constructor
152 */
153 public AutoCompletingTextField() {
154 init();
155 }
156
157 public AutoCompletingTextField(int columns) {
158 super(columns);
159 init();
160 }
161
162 protected void applyFilter(String filter) {
163 if (autoCompletionList != null) {
164 autoCompletionList.applyFilter(filter);
165 }
166 }
167
168 /**
169 *
170 * @return the auto completion list; may be null, if no auto completion list is set
171 */
172 public AutoCompletionList getAutoCompletionList() {
173 return autoCompletionList;
174 }
175
176 /**
177 * sets the auto completion list
178 * @param autoCompletionList the auto completion list; if null, auto completion is
179 * disabled
180 */
181 public void setAutoCompletionList(AutoCompletionList autoCompletionList) {
182 this.autoCompletionList = autoCompletionList;
183 }
184
185 public Component getEditorComponent() {
186 return this;
187 }
188
189 public Object getItem() {
190 return getText();
191 }
192
193 public void setItem(Object anObject) {
194 if (anObject == null) {
195 setText("");
196 } else {
197 setText(anObject.toString());
198 }
199 }
200
201 /* ------------------------------------------------------------------------------------ */
202 /* TableCellEditor interface */
203 /* ------------------------------------------------------------------------------------ */
204
205 private TableCellEditorSupport tableCellEditorSupport;
206 private String originalValue;
207
208 public void addCellEditorListener(CellEditorListener l) {
209 tableCellEditorSupport.addCellEditorListener(l);
210 }
211
212 protected void rememberOriginalValue(String value) {
213 this.originalValue = value;
214 }
215
216 protected void restoreOriginalValue() {
217 setText(originalValue);
218 }
219
220 public void removeCellEditorListener(CellEditorListener l) {
221 tableCellEditorSupport.removeCellEditorListener(l);
222 }
223 public void cancelCellEditing() {
224 restoreOriginalValue();
225 tableCellEditorSupport.fireEditingCanceled();
226
227 }
228
229 public Object getCellEditorValue() {
230 return getText();
231 }
232
233 public boolean isCellEditable(EventObject anEvent) {
234 return true;
235 }
236
237 public boolean shouldSelectCell(EventObject anEvent) {
238 return true;
239 }
240
241 public boolean stopCellEditing() {
242 tableCellEditorSupport.fireEditingStopped();
243 return true;
244 }
245
246 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
247 setText( value == null ? "" : value.toString());
248 rememberOriginalValue(getText());
249 return this;
250 }
251}
Note: See TracBrowser for help on using the repository browser.