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

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

fix #11064 - disable undo/redo feature for table cell editors

  • Property svn:eol-style set to native
File size: 9.3 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;
10
11import javax.swing.ComboBoxEditor;
12import javax.swing.JTable;
13import javax.swing.event.CellEditorListener;
14import javax.swing.table.TableCellEditor;
15import javax.swing.text.AttributeSet;
16import javax.swing.text.BadLocationException;
17import javax.swing.text.Document;
18import javax.swing.text.PlainDocument;
19import javax.swing.text.StyleConstants;
20
21import org.openstreetmap.josm.Main;
22import org.openstreetmap.josm.gui.util.CellEditorSupport;
23import org.openstreetmap.josm.gui.widgets.JosmTextField;
24
25/**
26 * AutoCompletingTextField is a text field with autocompletion behaviour. It
27 * can be used as table cell editor in {@link JTable}s.
28 *
29 * Autocompletion is controlled by a list of {@link AutoCompletionListItem}s
30 * managed in a {@link AutoCompletionList}.
31 *
32 * @since 1762
33 */
34public class AutoCompletingTextField extends JosmTextField implements ComboBoxEditor, TableCellEditor {
35
36 private Integer maxChars;
37
38 /**
39 * The document model for the editor
40 */
41 class AutoCompletionDocument extends PlainDocument {
42
43 @Override
44 public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
45
46 // If a maximum number of characters is specified, avoid to exceed it
47 if (maxChars != null && str != null && getLength() + str.length() > maxChars) {
48 int allowedLength = maxChars-getLength();
49 if (allowedLength > 0) {
50 str = str.substring(0, allowedLength);
51 } else {
52 return;
53 }
54 }
55
56 if (autoCompletionList == null) {
57 super.insertString(offs, str, a);
58 return;
59 }
60
61 // input method for non-latin characters (e.g. scim)
62 if (a != null && a.isDefined(StyleConstants.ComposedTextAttribute)) {
63 super.insertString(offs, str, a);
64 return;
65 }
66
67 // if the current offset isn't at the end of the document we don't autocomplete.
68 // If a highlighted autocompleted suffix was present and we get here Swing has
69 // already removed it from the document. getLength() therefore doesn't include the
70 // autocompleted suffix.
71 //
72 if (offs < getLength()) {
73 super.insertString(offs, str, a);
74 return;
75 }
76
77 String currentText = getText(0, getLength());
78 // if the text starts with a number we don't autocomplete
79 if (Main.pref.getBoolean("autocomplete.dont_complete_numbers", true)) {
80 try {
81 Long.parseLong(str);
82 if (currentText.length() == 0) {
83 // we don't autocomplete on numbers
84 super.insertString(offs, str, a);
85 return;
86 }
87 Long.parseLong(currentText);
88 super.insertString(offs, str, a);
89 return;
90 } catch(NumberFormatException e) {
91 // either the new text or the current text isn't a number. We continue with
92 // autocompletion
93 }
94 }
95 String prefix = currentText.substring(0, offs);
96 autoCompletionList.applyFilter(prefix+str);
97 if (autoCompletionList.getFilteredSize()>0) {
98 // there are matches. Insert the new text and highlight the
99 // auto completed suffix
100 //
101 String matchingString = autoCompletionList.getFilteredItem(0).getValue();
102 remove(0,getLength());
103 super.insertString(0,matchingString,a);
104
105 // highlight from insert position to end position to put the caret at the end
106 setCaretPosition(offs + str.length());
107 moveCaretPosition(getLength());
108 } else {
109 // there are no matches. Insert the new text, do not highlight
110 //
111 String newText = prefix + str;
112 remove(0,getLength());
113 super.insertString(0,newText,a);
114 setCaretPosition(getLength());
115
116 }
117 }
118 }
119
120 /** the auto completion list user input is matched against */
121 protected AutoCompletionList autoCompletionList = null;
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 /**
222 * Sets the maximum number of characters allowed.
223 * @param max maximum number of characters allowed
224 * @since 5579
225 */
226 public void setMaxChars(Integer max) {
227 maxChars = max;
228 }
229
230 /* ------------------------------------------------------------------------------------ */
231 /* TableCellEditor interface */
232 /* ------------------------------------------------------------------------------------ */
233
234 private CellEditorSupport tableCellEditorSupport;
235 private String originalValue;
236
237 @Override
238 public void addCellEditorListener(CellEditorListener l) {
239 tableCellEditorSupport.addCellEditorListener(l);
240 }
241
242 protected void rememberOriginalValue(String value) {
243 this.originalValue = value;
244 }
245
246 protected void restoreOriginalValue() {
247 setText(originalValue);
248 }
249
250 @Override
251 public void removeCellEditorListener(CellEditorListener l) {
252 tableCellEditorSupport.removeCellEditorListener(l);
253 }
254
255 @Override
256 public void cancelCellEditing() {
257 restoreOriginalValue();
258 tableCellEditorSupport.fireEditingCanceled();
259 }
260
261 @Override
262 public Object getCellEditorValue() {
263 return getText();
264 }
265
266 @Override
267 public boolean isCellEditable(EventObject anEvent) {
268 return true;
269 }
270
271 @Override
272 public boolean shouldSelectCell(EventObject anEvent) {
273 return true;
274 }
275
276 @Override
277 public boolean stopCellEditing() {
278 tableCellEditorSupport.fireEditingStopped();
279 return true;
280 }
281
282 @Override
283 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
284 setText( value == null ? "" : value.toString());
285 rememberOriginalValue(getText());
286 return this;
287 }
288}
Note: See TracBrowser for help on using the repository browser.