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

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

see #4429 - Right click menu "undo, cut, copy, paste, delete, select all" for each text component (originally based on patch by NooN)

  • Property svn:eol-style set to native
File size: 8.4 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.TableCellEditorSupport;
23import org.openstreetmap.josm.gui.widgets.JosmTextField;
24
25
26/**
27 * AutoCompletingTextField is an 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 *
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 /**
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
51 // If a maximum number of characters is specified, avoid to exceed it
52 if (maxChars != null && str != null && getLength() + str.length() > maxChars) {
53 int allowedLength = maxChars-getLength();
54 if (allowedLength > 0) {
55 str = str.substring(0, allowedLength);
56 } else {
57 return;
58 }
59 }
60
61 if (autoCompletionList == null) {
62 super.insertString(offs, str, a);
63 return;
64 }
65
66 // input method for non-latin characters (e.g. scim)
67 if (a != null && a.isDefined(StyleConstants.ComposedTextAttribute)) {
68 super.insertString(offs, str, a);
69 return;
70 }
71
72 // if the current offset isn't at the end of the document we don't autocomplete.
73 // If a highlighted autocompleted suffix was present and we get here Swing has
74 // already removed it from the document. getLength() therefore doesn't include the
75 // autocompleted suffix.
76 //
77 if (offs < getLength()) {
78 super.insertString(offs, str, a);
79 return;
80 }
81
82 String currentText = getText(0, getLength());
83 // if the text starts with a number we don't autocomplete
84 if (Main.pref.getBoolean("autocomplete.dont_complete_numbers", true)) {
85 try {
86 Long.parseLong(str);
87 if (currentText.length() == 0) {
88 // we don't autocomplete on numbers
89 super.insertString(offs, str, a);
90 return;
91 }
92 Long.parseLong(currentText);
93 super.insertString(offs, str, a);
94 return;
95 } catch(NumberFormatException e) {
96 // either the new text or the current text isn't a number. We continue with
97 // autocompletion
98 }
99 }
100 String prefix = currentText.substring(0, offs);
101 autoCompletionList.applyFilter(prefix+str);
102 if (autoCompletionList.getFilteredSize()>0) {
103 // there are matches. Insert the new text and highlight the
104 // auto completed suffix
105 //
106 String matchingString = autoCompletionList.getFilteredItem(0).getValue();
107 remove(0,getLength());
108 super.insertString(0,matchingString,a);
109
110 // highlight from insert position to end position to put the caret at the end
111 setCaretPosition(offs + str.length());
112 moveCaretPosition(getLength());
113 } else {
114 // there are no matches. Insert the new text, do not highlight
115 //
116 String newText = prefix + str;
117 remove(0,getLength());
118 super.insertString(0,newText,a);
119 setCaretPosition(getLength());
120
121 }
122 }
123 }
124
125 /** the auto completion list user input is matched against */
126 protected AutoCompletionList autoCompletionList = null;
127
128 /**
129 * creates the default document model for this editor
130 *
131 */
132 @Override
133 protected Document createDefaultModel() {
134 return new AutoCompletionDocument();
135 }
136
137 protected void init() {
138 addFocusListener(
139 new FocusAdapter() {
140 @Override public void focusGained(FocusEvent e) {
141 selectAll();
142 applyFilter(getText());
143 }
144 }
145 );
146
147 addKeyListener(
148 new KeyAdapter() {
149
150 @Override
151 public void keyReleased(KeyEvent e) {
152 if (getText().equals("")) {
153 applyFilter("");
154 }
155 }
156 }
157 );
158 tableCellEditorSupport = new TableCellEditorSupport(this);
159 }
160
161 /**
162 * constructor
163 */
164 public AutoCompletingTextField() {
165 init();
166 }
167
168 public AutoCompletingTextField(int columns) {
169 super(columns);
170 init();
171 }
172
173 protected void applyFilter(String filter) {
174 if (autoCompletionList != null) {
175 autoCompletionList.applyFilter(filter);
176 }
177 }
178
179 /**
180 *
181 * @return the auto completion list; may be null, if no auto completion list is set
182 */
183 public AutoCompletionList getAutoCompletionList() {
184 return autoCompletionList;
185 }
186
187 /**
188 * sets the auto completion list
189 * @param autoCompletionList the auto completion list; if null, auto completion is
190 * disabled
191 */
192 public void setAutoCompletionList(AutoCompletionList autoCompletionList) {
193 this.autoCompletionList = autoCompletionList;
194 }
195
196 public Component getEditorComponent() {
197 return this;
198 }
199
200 public Object getItem() {
201 return getText();
202 }
203
204 public void setItem(Object anObject) {
205 if (anObject == null) {
206 setText("");
207 } else {
208 setText(anObject.toString());
209 }
210 }
211
212 /**
213 * Sets the maximum number of characters allowed.
214 * @param max maximum number of characters allowed
215 * @since 5579
216 */
217 public void setMaxChars(Integer max) {
218 maxChars = max;
219 }
220
221 /* ------------------------------------------------------------------------------------ */
222 /* TableCellEditor interface */
223 /* ------------------------------------------------------------------------------------ */
224
225 private TableCellEditorSupport tableCellEditorSupport;
226 private String originalValue;
227
228 public void addCellEditorListener(CellEditorListener l) {
229 tableCellEditorSupport.addCellEditorListener(l);
230 }
231
232 protected void rememberOriginalValue(String value) {
233 this.originalValue = value;
234 }
235
236 protected void restoreOriginalValue() {
237 setText(originalValue);
238 }
239
240 public void removeCellEditorListener(CellEditorListener l) {
241 tableCellEditorSupport.removeCellEditorListener(l);
242 }
243 public void cancelCellEditing() {
244 restoreOriginalValue();
245 tableCellEditorSupport.fireEditingCanceled();
246
247 }
248
249 public Object getCellEditorValue() {
250 return getText();
251 }
252
253 public boolean isCellEditable(EventObject anEvent) {
254 return true;
255 }
256
257 public boolean shouldSelectCell(EventObject anEvent) {
258 return true;
259 }
260
261 public boolean stopCellEditing() {
262 tableCellEditorSupport.fireEditingStopped();
263 return true;
264 }
265
266 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
267 setText( value == null ? "" : value.toString());
268 rememberOriginalValue(getText());
269 return this;
270 }
271}
Note: See TracBrowser for help on using the repository browser.