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

Last change on this file since 10626 was 10626, checked in by Don-vip, 8 years ago

simplify handling of ignored/traced exceptions

  • Property svn:eol-style set to native
File size: 9.6 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.Objects;
11
12import javax.swing.ComboBoxEditor;
13import javax.swing.JTable;
14import javax.swing.event.CellEditorListener;
15import javax.swing.table.TableCellEditor;
16import javax.swing.text.AttributeSet;
17import javax.swing.text.BadLocationException;
18import javax.swing.text.Document;
19import javax.swing.text.PlainDocument;
20import javax.swing.text.StyleConstants;
21
22import org.openstreetmap.josm.Main;
23import org.openstreetmap.josm.gui.util.CellEditorSupport;
24import org.openstreetmap.josm.gui.widgets.JosmTextField;
25
26/**
27 * AutoCompletingTextField is a text field with autocompletion behaviour. It
28 * can be used as table cell editor in {@link JTable}s.
29 *
30 * Autocompletion is controlled by a list of {@link AutoCompletionListItem}s
31 * managed in a {@link AutoCompletionList}.
32 *
33 * @since 1762
34 */
35public class AutoCompletingTextField extends JosmTextField implements ComboBoxEditor, TableCellEditor {
36
37 private Integer maxChars;
38
39 /**
40 * The document model for the editor
41 */
42 class AutoCompletionDocument extends PlainDocument {
43
44 @Override
45 public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
46
47 // If a maximum number of characters is specified, avoid to exceed it
48 if (maxChars != null && str != null && getLength() + str.length() > maxChars) {
49 int allowedLength = maxChars-getLength();
50 if (allowedLength > 0) {
51 str = str.substring(0, allowedLength);
52 } else {
53 return;
54 }
55 }
56
57 if (autoCompletionList == null) {
58 super.insertString(offs, str, a);
59 return;
60 }
61
62 // input method for non-latin characters (e.g. scim)
63 if (a != null && a.isDefined(StyleConstants.ComposedTextAttribute)) {
64 super.insertString(offs, str, a);
65 return;
66 }
67
68 // if the current offset isn't at the end of the document we don't autocomplete.
69 // If a highlighted autocompleted suffix was present and we get here Swing has
70 // already removed it from the document. getLength() therefore doesn't include the
71 // autocompleted suffix.
72 //
73 if (offs < getLength()) {
74 super.insertString(offs, str, a);
75 return;
76 }
77
78 String currentText = getText(0, getLength());
79 // if the text starts with a number we don't autocomplete
80 if (Main.pref.getBoolean("autocomplete.dont_complete_numbers", true)) {
81 try {
82 Long.parseLong(str);
83 if (currentText.isEmpty()) {
84 // we don't autocomplete on numbers
85 super.insertString(offs, str, a);
86 return;
87 }
88 Long.parseLong(currentText);
89 super.insertString(offs, str, a);
90 return;
91 } catch (NumberFormatException e) {
92 // either the new text or the current text isn't a number. We continue with autocompletion
93 Main.trace(e);
94 }
95 }
96 String prefix = currentText.substring(0, offs);
97 autoCompletionList.applyFilter(prefix+str);
98 if (autoCompletionList.getFilteredSize() > 0 && !Objects.equals(str, noAutoCompletionString)) {
99 // there are matches. Insert the new text and highlight the auto completed suffix
100 String matchingString = autoCompletionList.getFilteredItem(0).getValue();
101 remove(0, getLength());
102 super.insertString(0, matchingString, a);
103
104 // highlight from insert position to end position to put the caret at the end
105 setCaretPosition(offs + str.length());
106 moveCaretPosition(getLength());
107 } else {
108 // there are no matches. Insert the new text, do not highlight
109 //
110 String newText = prefix + str;
111 remove(0, getLength());
112 super.insertString(0, newText, a);
113 setCaretPosition(getLength());
114 }
115 }
116 }
117
118 /** the auto completion list user input is matched against */
119 protected AutoCompletionList autoCompletionList;
120 /** a string which should not be auto completed */
121 protected String noAutoCompletionString;
122
123 @Override
124 protected Document createDefaultModel() {
125 return new AutoCompletionDocument();
126 }
127
128 protected final void init() {
129 addFocusListener(
130 new FocusAdapter() {
131 @Override public void focusGained(FocusEvent e) {
132 selectAll();
133 applyFilter(getText());
134 }
135 }
136 );
137
138 addKeyListener(
139 new KeyAdapter() {
140
141 @Override
142 public void keyReleased(KeyEvent e) {
143 if (getText().isEmpty()) {
144 applyFilter("");
145 }
146 }
147 }
148 );
149 tableCellEditorSupport = new CellEditorSupport(this);
150 }
151
152 /**
153 * Constructs a new {@code AutoCompletingTextField}.
154 */
155 public AutoCompletingTextField() {
156 this(0);
157 }
158
159 /**
160 * Constructs a new {@code AutoCompletingTextField}.
161 * @param columns the number of columns to use to calculate the preferred width;
162 * if columns is set to zero, the preferred width will be whatever naturally results from the component implementation
163 */
164 public AutoCompletingTextField(int columns) {
165 this(columns, true);
166 }
167
168 /**
169 * Constructs a new {@code AutoCompletingTextField}.
170 * @param columns the number of columns to use to calculate the preferred width;
171 * if columns is set to zero, the preferred width will be whatever naturally results from the component implementation
172 * @param undoRedo Enables or not Undo/Redo feature. Not recommended for table cell editors, unless each cell provides its own editor
173 */
174 public AutoCompletingTextField(int columns, boolean undoRedo) {
175 super(null, null, columns, undoRedo);
176 init();
177 }
178
179 protected void applyFilter(String filter) {
180 if (autoCompletionList != null) {
181 autoCompletionList.applyFilter(filter);
182 }
183 }
184
185 /**
186 * Returns the auto completion list.
187 * @return the auto completion list; may be null, if no auto completion list is set
188 */
189 public AutoCompletionList getAutoCompletionList() {
190 return autoCompletionList;
191 }
192
193 /**
194 * Sets the auto completion list.
195 * @param autoCompletionList the auto completion list; if null, auto completion is
196 * disabled
197 */
198 public void setAutoCompletionList(AutoCompletionList autoCompletionList) {
199 this.autoCompletionList = autoCompletionList;
200 }
201
202 @Override
203 public Component getEditorComponent() {
204 return this;
205 }
206
207 @Override
208 public Object getItem() {
209 return getText();
210 }
211
212 @Override
213 public void setItem(Object anObject) {
214 if (anObject == null) {
215 setText("");
216 } else {
217 setText(anObject.toString());
218 }
219 }
220
221 @Override
222 public void setText(String t) {
223 // disallow auto completion for this explicitly set string
224 this.noAutoCompletionString = t;
225 super.setText(t);
226 }
227
228 /**
229 * Sets the maximum number of characters allowed.
230 * @param max maximum number of characters allowed
231 * @since 5579
232 */
233 public void setMaxChars(Integer max) {
234 maxChars = max;
235 }
236
237 /* ------------------------------------------------------------------------------------ */
238 /* TableCellEditor interface */
239 /* ------------------------------------------------------------------------------------ */
240
241 private transient CellEditorSupport tableCellEditorSupport;
242 private String originalValue;
243
244 @Override
245 public void addCellEditorListener(CellEditorListener l) {
246 tableCellEditorSupport.addCellEditorListener(l);
247 }
248
249 protected void rememberOriginalValue(String value) {
250 this.originalValue = value;
251 }
252
253 protected void restoreOriginalValue() {
254 setText(originalValue);
255 }
256
257 @Override
258 public void removeCellEditorListener(CellEditorListener l) {
259 tableCellEditorSupport.removeCellEditorListener(l);
260 }
261
262 @Override
263 public void cancelCellEditing() {
264 restoreOriginalValue();
265 tableCellEditorSupport.fireEditingCanceled();
266 }
267
268 @Override
269 public Object getCellEditorValue() {
270 return getText();
271 }
272
273 @Override
274 public boolean isCellEditable(EventObject anEvent) {
275 return true;
276 }
277
278 @Override
279 public boolean shouldSelectCell(EventObject anEvent) {
280 return true;
281 }
282
283 @Override
284 public boolean stopCellEditing() {
285 tableCellEditorSupport.fireEditingStopped();
286 return true;
287 }
288
289 @Override
290 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
291 setText(value == null ? "" : value.toString());
292 rememberOriginalValue(getText());
293 return this;
294 }
295}
Note: See TracBrowser for help on using the repository browser.