svn-gvsig-desktop / trunk / libraries / libUI / src / org / gvsig / gui / beans / swing / jComboBoxItemsSeeker / JComboBoxItemsSeekerConfigurable.java @ 11762
History | View | Annotate | Download (24.9 KB)
1 | 10413 | ppiqueras | package org.gvsig.gui.beans.swing.jComboBoxItemsSeeker; |
---|---|---|---|
2 | |||
3 | import java.awt.Color; |
||
4 | import java.awt.event.FocusAdapter; |
||
5 | import java.awt.event.FocusEvent; |
||
6 | import java.awt.event.FocusListener; |
||
7 | import java.awt.event.KeyAdapter; |
||
8 | import java.awt.event.KeyEvent; |
||
9 | import java.awt.event.KeyListener; |
||
10 | import java.awt.event.MouseAdapter; |
||
11 | import java.awt.event.MouseEvent; |
||
12 | 11656 | ppiqueras | import java.util.Vector; |
13 | 10413 | ppiqueras | |
14 | 11656 | ppiqueras | import javax.accessibility.Accessible; |
15 | 10413 | ppiqueras | import javax.swing.ComboBoxEditor; |
16 | import javax.swing.ComboBoxModel; |
||
17 | import javax.swing.JComboBox; |
||
18 | 11656 | ppiqueras | import javax.swing.JList; |
19 | 10413 | ppiqueras | import javax.swing.event.PopupMenuListener; |
20 | 11656 | ppiqueras | import javax.swing.plaf.basic.BasicComboBoxUI; |
21 | import javax.swing.plaf.basic.ComboPopup; |
||
22 | 10413 | ppiqueras | import javax.swing.text.AttributeSet; |
23 | import javax.swing.text.BadLocationException; |
||
24 | import javax.swing.text.JTextComponent; |
||
25 | import javax.swing.text.PlainDocument; |
||
26 | |||
27 | |||
28 | /* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
|
||
29 | *
|
||
30 | * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
|
||
31 | *
|
||
32 | * This program is free software; you can redistribute it and/or
|
||
33 | * modify it under the terms of the GNU General Public License
|
||
34 | * as published by the Free Software Foundation; either version 2
|
||
35 | * of the License, or (at your option) any later version.
|
||
36 | *
|
||
37 | * This program is distributed in the hope that it will be useful,
|
||
38 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
39 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
40 | * GNU General Public License for more details.
|
||
41 | *
|
||
42 | * You should have received a copy of the GNU General Public License
|
||
43 | * along with this program; if not, write to the Free Software
|
||
44 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA.
|
||
45 | *
|
||
46 | * For more information, contact:
|
||
47 | *
|
||
48 | * Generalitat Valenciana
|
||
49 | * Conselleria d'Infraestructures i Transport
|
||
50 | * Av. Blasco Ib??ez, 50
|
||
51 | * 46010 VALENCIA
|
||
52 | * SPAIN
|
||
53 | *
|
||
54 | * +34 963862235
|
||
55 | * gvsig@gva.es
|
||
56 | * www.gvsig.gva.es
|
||
57 | *
|
||
58 | * or
|
||
59 | *
|
||
60 | * IVER T.I. S.A
|
||
61 | * Salamanca 50
|
||
62 | * 46005 Valencia
|
||
63 | * Spain
|
||
64 | *
|
||
65 | * +34 963163400
|
||
66 | * dac@iver.es
|
||
67 | */
|
||
68 | |||
69 | 11656 | ppiqueras | |
70 | /**
|
||
71 | 10413 | ppiqueras | * @author Pablo Piqueras Bartolom? (p_queras@hotmail.com)
|
72 | */
|
||
73 | public class JComboBoxItemsSeekerConfigurable extends JComboBox implements java.io.Serializable { |
||
74 | 11762 | ppiqueras | // AQU? ID
|
75 | 10413 | ppiqueras | |
76 | // CONSTANTS FOR CONFIGURE THE BEHAVIOR
|
||
77 | public static final boolean DEFAULT_ONLY_ONE_COLOR_ON_TEXT_CONFIGURATION = false; |
||
78 | 11656 | ppiqueras | public static final boolean DEFAULT_BEEP_ENABLED_CONFIGURATION = false; |
79 | public static final boolean DEFAULT_HIDE_POPUP_IF_THERE_ARE_NO_ITEMS_CONFIGURATION = true; |
||
80 | public static final boolean DEFAULT_TO_FORCE_SELECT_AN_ITEM_CONFIGURATION = true; |
||
81 | 10413 | ppiqueras | // END CONSTANTS FOR CONFIGURE THE BEHAVIOR
|
82 | |||
83 | // EDITOR DOCUMENT REFERENCE
|
||
84 | 11656 | ppiqueras | /**
|
85 | * A reference to the document of this component
|
||
86 | */
|
||
87 | 10413 | ppiqueras | private PlainDocumentTextFormatter document;
|
88 | // END EDITOR DOCUMENT REFERENCE
|
||
89 | |||
90 | 11656 | ppiqueras | // NEW ATTRIBUTES
|
91 | 10413 | ppiqueras | /**
|
92 | 11656 | ppiqueras | * A reference to the model of this component (according to the MVC <i>(Model-View-Controller)</i> pattern)
|
93 | 10413 | ppiqueras | */
|
94 | 11762 | ppiqueras | private DefaultComboBoxItemsSeekerConfigurableModel model;
|
95 | 10413 | ppiqueras | |
96 | /**
|
||
97 | 11656 | ppiqueras | * Has or not to hide the popup on focus loss
|
98 | 10413 | ppiqueras | */
|
99 | 11656 | ppiqueras | private boolean hidePopupOnFocusLoss; |
100 | |||
101 | 10413 | ppiqueras | /**
|
102 | 11656 | ppiqueras | * Has an item of the popup been selected or not by the user
|
103 | 10413 | ppiqueras | */
|
104 | 11656 | ppiqueras | private boolean popupItemSelected; |
105 | // END NEW ATTRIBUTES
|
||
106 | 10413 | ppiqueras | |
107 | 11656 | ppiqueras | // LISTENERS
|
108 | 10413 | ppiqueras | /**
|
109 | 11656 | ppiqueras | * Listener for the editor key
|
110 | 10413 | ppiqueras | */
|
111 | 11656 | ppiqueras | private KeyListener editorKeyListener; |
112 | 10413 | ppiqueras | |
113 | /**
|
||
114 | 11656 | ppiqueras | * Listener for the editor focus
|
115 | 10413 | ppiqueras | */
|
116 | 11656 | ppiqueras | private FocusListener editorFocusListener; |
117 | 10413 | ppiqueras | |
118 | /**
|
||
119 | 11656 | ppiqueras | * Listener for the popup menu
|
120 | 10413 | ppiqueras | */
|
121 | 11656 | ppiqueras | private PopupMenuListener popupMenuListener; |
122 | 10413 | ppiqueras | |
123 | /**
|
||
124 | 11656 | ppiqueras | * Last item selected
|
125 | 10413 | ppiqueras | */
|
126 | 11656 | ppiqueras | private Object previousSelected; |
127 | // END LISTENERS
|
||
128 | 10413 | ppiqueras | |
129 | 11656 | ppiqueras | // CONFIGURATION FLAGS
|
130 | private boolean onlyOneColorOnText_Flag; |
||
131 | private boolean beepEnabled_Flag; |
||
132 | private boolean hidePopupIfThereAreNoItems_Flag; |
||
133 | private boolean toForceSelectAnItem_Flag; |
||
134 | // END FLAGS
|
||
135 | |||
136 | 10413 | ppiqueras | /**
|
137 | 11656 | ppiqueras | * Default constructor without parameters
|
138 | 10413 | ppiqueras | */
|
139 | 11656 | ppiqueras | public JComboBoxItemsSeekerConfigurable() {
|
140 | super();
|
||
141 | initialize(); |
||
142 | 10413 | ppiqueras | } |
143 | |||
144 | /**
|
||
145 | 11656 | ppiqueras | * Default constructor with a {@link ComboBoxModel} as parameter
|
146 | 10413 | ppiqueras | *
|
147 | 11656 | ppiqueras | * @param aModel javax.swing.ComboBoxModel
|
148 | 10413 | ppiqueras | */
|
149 | 11656 | ppiqueras | public JComboBoxItemsSeekerConfigurable(ComboBoxModel aModel) { |
150 | super(aModel);
|
||
151 | initialize(); |
||
152 | } |
||
153 | 10413 | ppiqueras | |
154 | /**
|
||
155 | 11656 | ppiqueras | * Default constructor with an array of objects as parameter
|
156 | 10413 | ppiqueras | *
|
157 | 11656 | ppiqueras | * @param items An array of objects. All them must implement a <i>'String toStrin()'</i> method
|
158 | 10413 | ppiqueras | */
|
159 | 11656 | ppiqueras | public JComboBoxItemsSeekerConfigurable(Object[] items) { |
160 | super(items);
|
||
161 | initialize(); |
||
162 | 10413 | ppiqueras | } |
163 | |||
164 | /**
|
||
165 | 11656 | ppiqueras | * Default constructor with a Vector of objects as parameter
|
166 | *
|
||
167 | * @param items A {@link Vector} of objects. All them must implement a <i>'String toStrin()'</i> method
|
||
168 | 10413 | ppiqueras | */
|
169 | 11656 | ppiqueras | public JComboBoxItemsSeekerConfigurable(Vector items) { |
170 | super(items);
|
||
171 | initialize(); |
||
172 | 10413 | ppiqueras | } |
173 | 11656 | ppiqueras | |
174 | 10413 | ppiqueras | /**
|
175 | 11656 | ppiqueras | * This method sets the start values of inner attributes and creates the necessary inner objects
|
176 | 10413 | ppiqueras | */
|
177 | 11656 | ppiqueras | private void initialize() { |
178 | // By default user hasn't selected an item of the popup
|
||
179 | popupItemSelected = false;
|
||
180 | 10413 | ppiqueras | |
181 | 11656 | ppiqueras | // By default no item has been selected
|
182 | previousSelected = null;
|
||
183 | |||
184 | // Set default flags configuration
|
||
185 | this.setDefaultBehaviorFlagsConfiguration();
|
||
186 | |||
187 | // Creates the model for this component and gets it reference
|
||
188 | 11762 | ppiqueras | model = new DefaultComboBoxItemsSeekerConfigurableModel();
|
189 | 11656 | ppiqueras | super.setModel(model);
|
190 | |||
191 | // Allows user to edit on the combobox
|
||
192 | super.setEditable(true); |
||
193 | |||
194 | // Other configuration tasks
|
||
195 | this.configure();
|
||
196 | |||
197 | // If there are items -> select the first
|
||
198 | if (model.getSize() > 0) { |
||
199 | model.setSelectedItem(model.getElementAt(0));
|
||
200 | } |
||
201 | 10413 | ppiqueras | } |
202 | |||
203 | /**
|
||
204 | 11656 | ppiqueras | * Configures the component and some of its elements
|
205 | 10413 | ppiqueras | */
|
206 | private void configure() { |
||
207 | 11656 | ppiqueras | // Defines a key listener for the editor of this component
|
208 | this.defineEditorKeyListener(this); |
||
209 | |||
210 | // Defines a focus listener for the editor of this component
|
||
211 | this.defineEditorFocusListener(this); |
||
212 | |||
213 | 10413 | ppiqueras | // Configures the document of the editor of this component
|
214 | this.configureDocument();
|
||
215 | |||
216 | // Configures the editor (ComboBoxEditor) of this component
|
||
217 | this.configureEditor(this.getEditor()); |
||
218 | |||
219 | // Configures the popup of this component
|
||
220 | 11656 | ppiqueras | this.configurePopUp(this); |
221 | 10413 | ppiqueras | } |
222 | |||
223 | /**
|
||
224 | 11656 | ppiqueras | * Configures the editor ( {@link ComboBoxEditor} ) of this component
|
225 | 10413 | ppiqueras | *
|
226 | * @param newEditor The new editor to configure
|
||
227 | */
|
||
228 | private void configureEditor(ComboBoxEditor newEditor) { |
||
229 | if (newEditor != null) { |
||
230 | JTextComponent jTextComponentOfEditor = (JTextComponent) newEditor.getEditorComponent(); |
||
231 | 11656 | ppiqueras | |
232 | // Adds the new document (tries to remove it if it existed before)
|
||
233 | jTextComponentOfEditor.setDocument(this.document);
|
||
234 | |||
235 | 10413 | ppiqueras | // Adds the new Key Listener (tries to remove it if it existed before)
|
236 | jTextComponentOfEditor.removeKeyListener(this.editorKeyListener);
|
||
237 | jTextComponentOfEditor.addKeyListener(this.editorKeyListener);
|
||
238 | 11656 | ppiqueras | |
239 | 10413 | ppiqueras | // Adds the new Focus Listener (tries to remove it if it existed before)
|
240 | jTextComponentOfEditor.removeFocusListener(this.editorFocusListener);
|
||
241 | jTextComponentOfEditor.addFocusListener(this.editorFocusListener);
|
||
242 | } |
||
243 | } |
||
244 | |||
245 | /**
|
||
246 | * Configures the document of the editor of this component
|
||
247 | */
|
||
248 | private void configureDocument() { |
||
249 | // Creates the document of the editor of this component
|
||
250 | document = new PlainDocumentTextFormatter();
|
||
251 | |||
252 | 11656 | ppiqueras | // Set reference to the container component
|
253 | document.setJComboBoxReference(this);
|
||
254 | 10413 | ppiqueras | } |
255 | 11656 | ppiqueras | |
256 | /**
|
||
257 | * Configures the popup of this component
|
||
258 | *
|
||
259 | * @param combo_Box A reference of this component
|
||
260 | 10413 | ppiqueras | */
|
261 | 11656 | ppiqueras | private void configurePopUp(JComboBoxItemsSeekerConfigurable combo_Box) { |
262 | final JComboBoxItemsSeekerConfigurable comboBoxReference = combo_Box;
|
||
263 | this.addPopupMenuListener(this.popupMenuListener); |
||
264 | |||
265 | BasicComboBoxUI comboBoxUi = (BasicComboBoxUI)comboBoxReference.getUI(); |
||
266 | Accessible a = comboBoxUi.getAccessibleChild(comboBoxReference, 0); |
||
267 | if (a instanceof ComboPopup) { |
||
268 | JList jlist = ((ComboPopup)a).getList(); |
||
269 | |||
270 | jlist.addMouseListener(new MouseAdapter() { |
||
271 | /*
|
||
272 | * (non-Javadoc)
|
||
273 | * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
|
||
274 | */
|
||
275 | public void mousePressed(MouseEvent e) { |
||
276 | // User selects an item of the popup using the mouse
|
||
277 | popupItemSelected = true;
|
||
278 | } |
||
279 | }); |
||
280 | } |
||
281 | 10413 | ppiqueras | } |
282 | |||
283 | /**
|
||
284 | 11656 | ppiqueras | * Sets the default values of the flags
|
285 | 10413 | ppiqueras | */
|
286 | 11656 | ppiqueras | private void setDefaultBehaviorFlagsConfiguration() { |
287 | this.onlyOneColorOnText_Flag = DEFAULT_ONLY_ONE_COLOR_ON_TEXT_CONFIGURATION;
|
||
288 | this.beepEnabled_Flag = DEFAULT_BEEP_ENABLED_CONFIGURATION;
|
||
289 | this.hidePopupIfThereAreNoItems_Flag = DEFAULT_HIDE_POPUP_IF_THERE_ARE_NO_ITEMS_CONFIGURATION;
|
||
290 | this.toForceSelectAnItem_Flag = DEFAULT_TO_FORCE_SELECT_AN_ITEM_CONFIGURATION;
|
||
291 | 10413 | ppiqueras | } |
292 | |||
293 | /**
|
||
294 | 11762 | ppiqueras | * Defines a key listener for the editor of this component. <br>
|
295 | * This method is another important difference from the JComboBox; and could work badly with some keymaps.
|
||
296 | 10413 | ppiqueras | *
|
297 | 11656 | ppiqueras | * @param combo_Box A reference of this component
|
298 | 10413 | ppiqueras | */
|
299 | 11656 | ppiqueras | private void defineEditorKeyListener(JComboBoxItemsSeekerConfigurable combo_Box) { |
300 | final JComboBoxItemsSeekerConfigurable comboBoxReference = combo_Box;
|
||
301 | 10413 | ppiqueras | |
302 | 11656 | ppiqueras | editorKeyListener = new KeyAdapter() { |
303 | /*
|
||
304 | * (non-Javadoc)
|
||
305 | * @see java.awt.event.KeyAdapter#keyPressed(java.awt.event.KeyEvent)
|
||
306 | */
|
||
307 | public void keyPressed(KeyEvent ke) // Executed on the Start view state or Search view state |
||
308 | 10413 | ppiqueras | { |
309 | 11656 | ppiqueras | // According the key pressed, do some actions or others
|
310 | switch (ke.getKeyCode())
|
||
311 | { |
||
312 | case KeyEvent.VK_ENTER : |
||
313 | // Don't allow execute the default instructions because they have a bug (first time we remove some characteres, no item will be displayed in the popup)
|
||
314 | ke.consume(); |
||
315 | 10413 | ppiqueras | |
316 | 11656 | ppiqueras | // Sets the caret position of the text in the document to the end:
|
317 | ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(document.getLength());
|
||
318 | |||
319 | if (toForceSelectAnItem_Flag) {
|
||
320 | // Select now the first item or the previous selected
|
||
321 | switch (comboBoxReference.getModel().getSize()) {
|
||
322 | case 0: |
||
323 | if (previousSelected != null) { |
||
324 | ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
|
||
325 | } |
||
326 | break;
|
||
327 | default:
|
||
328 | previousSelected = comboBoxReference.getItemAt(0); // Select the first |
||
329 | comboBoxReference.setSelectedIndex(0);
|
||
330 | } |
||
331 | 10413 | ppiqueras | } |
332 | |||
333 | 11656 | ppiqueras | // Hide the popup
|
334 | comboBoxReference.hidePopup(); |
||
335 | break;
|
||
336 | 10413 | ppiqueras | |
337 | 11656 | ppiqueras | case KeyEvent.VK_UP: case KeyEvent.VK_DOWN: |
338 | // User selects an item of the popup using the mouse
|
||
339 | popupItemSelected = true;
|
||
340 | break;
|
||
341 | } |
||
342 | 10413 | ppiqueras | } |
343 | 11656 | ppiqueras | }; |
344 | 10413 | ppiqueras | } |
345 | |||
346 | /**
|
||
347 | 11656 | ppiqueras | * Defines a focus listener for the editor of this component
|
348 | 10413 | ppiqueras | *
|
349 | 11656 | ppiqueras | * @param combo_Box A reference of this component
|
350 | 10413 | ppiqueras | */
|
351 | 11656 | ppiqueras | private void defineEditorFocusListener(JComboBoxItemsSeekerConfigurable combo_Box) { |
352 | final JComboBoxItemsSeekerConfigurable comboBoxReference = combo_Box;
|
||
353 | |||
354 | // Bug 5100422 on Java 1.5: Editable JComboBox won't hide popup when tabbing out
|
||
355 | hidePopupOnFocusLoss=System.getProperty("java.version").startsWith("1.5"); |
||
356 | |||
357 | // Highlight whole text when gaining focus
|
||
358 | editorFocusListener = new FocusAdapter() { |
||
359 | |||
360 | /*
|
||
361 | * (non-Javadoc)
|
||
362 | * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
|
||
363 | */
|
||
364 | public void focusLost(FocusEvent e) { |
||
365 | if (toForceSelectAnItem_Flag) {
|
||
366 | // Select now the first item or the previous selected
|
||
367 | switch (comboBoxReference.getModel().getSize()) {
|
||
368 | case 0: |
||
369 | if (previousSelected != null) { |
||
370 | ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
|
||
371 | } |
||
372 | break;
|
||
373 | default:
|
||
374 | previousSelected = comboBoxReference.getItemAt(0); // Select the first |
||
375 | comboBoxReference.setSelectedIndex(0);
|
||
376 | } |
||
377 | 10413 | ppiqueras | } |
378 | 11656 | ppiqueras | |
379 | comboBoxReference.hidePopup(); |
||
380 | |||
381 | // Workaround for Bug 5100422 - Hide Popup on focus loss
|
||
382 | if (hidePopupOnFocusLoss) {
|
||
383 | comboBoxReference.setPopupVisible(false);
|
||
384 | 10413 | ppiqueras | } |
385 | 11656 | ppiqueras | } |
386 | }; |
||
387 | 10413 | ppiqueras | } |
388 | |||
389 | ////// METHODS FOR THE BEHAVIOR FLAGS //////
|
||
390 | /**
|
||
391 | 11762 | ppiqueras | * Returns the 'only_One_Color_On_Text' configuration value of this component. Configuration values are: <br>
|
392 | * + true: always uses black color on text. <br>
|
||
393 | * + false: by default uses black color on text, but if text written by user doesn't match with any item, text will be on red color.
|
||
394 | 10413 | ppiqueras | *
|
395 | * @return 'only_One_Color_On_Text' configuration
|
||
396 | */
|
||
397 | public boolean isOnlyOneColorOnText_Flag() { |
||
398 | return onlyOneColorOnText_Flag;
|
||
399 | } |
||
400 | |||
401 | /**
|
||
402 | 11762 | ppiqueras | * Sets the 'only_One_Color_On_Text' configuration value for this component. Configuration values are: <br>
|
403 | * + true: always uses black color on text. <br>
|
||
404 | * + false: by default uses black color on text, but if text written by user doesn't match with any item, text will be on red color.
|
||
405 | 10413 | ppiqueras | *
|
406 | 11762 | ppiqueras | * @param A boolean value for 'only_One_Color_On_Text' configuration flag
|
407 | 10413 | ppiqueras | */
|
408 | public void setOnlyOneColorOnText_Flag(boolean only_One_Color) { |
||
409 | this.onlyOneColorOnText_Flag = only_One_Color;
|
||
410 | } |
||
411 | |||
412 | /**
|
||
413 | 11762 | ppiqueras | * Returns the 'beep_Enabled' configuration value of this component. Configuration values are: <br>
|
414 | * + true: a beep-sound is listened when no item matches with the text written. <br>
|
||
415 | * + false: no sound is listened.
|
||
416 | 10413 | ppiqueras | *
|
417 | * @return 'beep_Enabled' configuration
|
||
418 | */
|
||
419 | public boolean isBeepEnabled_Flag() { |
||
420 | return this.beepEnabled_Flag; |
||
421 | } |
||
422 | |||
423 | /**
|
||
424 | 11762 | ppiqueras | * Sets the 'beep_Enabled' configuration value for this component. Configuration values are: <br>
|
425 | * + true: a beep-sound is listened when no item matches with the text written. <br>
|
||
426 | * + false: no sound is listened.
|
||
427 | 10413 | ppiqueras | *
|
428 | 11762 | ppiqueras | * @param A boolean value for 'beep_Enabled' configuration flag
|
429 | 10413 | ppiqueras | */
|
430 | public void setBeepEnabled_Flag(boolean beep_Enabled) { |
||
431 | this.beepEnabled_Flag = beep_Enabled;
|
||
432 | } |
||
433 | |||
434 | /**
|
||
435 | 11762 | ppiqueras | * Returns the 'hidePopupIfThereAreNoItems_Flag' configuration value of this component. Configuration values are: <br>
|
436 | * + true: hides the popup if there are no items when you write.
|
||
437 | * + false: default behaviour (if there are no items when you write, popup c <br>ontinues visible) .
|
||
438 | 10413 | ppiqueras | *
|
439 | 11656 | ppiqueras | * @return 'hidePopupIfThereAreNoItems_Flag' configuration
|
440 | 10413 | ppiqueras | */
|
441 | 11656 | ppiqueras | public boolean isHidePopupIfThereAreNoItems_Flag() { |
442 | return this.hidePopupIfThereAreNoItems_Flag; |
||
443 | 10413 | ppiqueras | } |
444 | |||
445 | /**
|
||
446 | 11762 | ppiqueras | * Sets the 'hidePopupIfThereAreNoItems_Flag' configuration value for this component. Configuration values are: <br>
|
447 | * + true: hides the popup if there are no items when you write. <br>
|
||
448 | * + false: default behaviour (if there are no items when you write, popup continues visible) .
|
||
449 | 10413 | ppiqueras | *
|
450 | 11762 | ppiqueras | * @param A boolean value for 'hidePopupIfThereAreNoItems_Flag' configuration flag
|
451 | 10413 | ppiqueras | */
|
452 | 11656 | ppiqueras | public void setHidePopupIfThereAreNoItems_Flag(boolean hide) { |
453 | this.hidePopupIfThereAreNoItems_Flag = hide;
|
||
454 | 10413 | ppiqueras | } |
455 | |||
456 | /**
|
||
457 | 11762 | ppiqueras | * Returns the 'toForceSelectAnItem_Flag' configuration value of this component. Configuration values are: <br>
|
458 | * + true: selects the previous selected item or the first of the list when user presses the Enter key or when the component loses the focus . <br>
|
||
459 | * + false: default behaviour .
|
||
460 | 10413 | ppiqueras | *
|
461 | 11656 | ppiqueras | * @return 'toForceSelectAnItem_Flag' configuration
|
462 | 10413 | ppiqueras | */
|
463 | 11656 | ppiqueras | public boolean isToForceSelectAnItem_Flag() { |
464 | return this.toForceSelectAnItem_Flag; |
||
465 | 10413 | ppiqueras | } |
466 | |||
467 | /**
|
||
468 | 11762 | ppiqueras | * Sets the 'toForceSelectAnItem_Flag' configuration value for this component. Configuration values are: <br>
|
469 | * + true: selects the previous selected item or the first of the list when user presses the Enter key or when the component loses the focus . <br>
|
||
470 | * + false: default behaviour .
|
||
471 | 10413 | ppiqueras | *
|
472 | 11762 | ppiqueras | * @param A boolean value for 'toForceSelectAnItem_Flag' configuration flag
|
473 | 10413 | ppiqueras | */
|
474 | 11656 | ppiqueras | public void setToForceSelectAnItem_Flag(boolean force) { |
475 | this.toForceSelectAnItem_Flag = force;
|
||
476 | 10413 | ppiqueras | } |
477 | 11656 | ppiqueras | ////// END METHODS FOR THE BEHAVIOR FLAGS //////
|
478 | 10413 | ppiqueras | |
479 | |||
480 | /**
|
||
481 | 11762 | ppiqueras | * Inner class that inherits of the class PlainDocument, and is used for manipulate the textWritten that has the document of the editor of this component. <br>
|
482 | * This class is also optimized for items seek.
|
||
483 | 10413 | ppiqueras | *
|
484 | * @author Pablo Piqueras Bartolom? (p_queras@hotmail.com)
|
||
485 | */
|
||
486 | private class PlainDocumentTextFormatter extends PlainDocument { |
||
487 | private static final long serialVersionUID = 4158213349939840209L; |
||
488 | 11656 | ppiqueras | private JComboBoxItemsSeekerConfigurable comboBoxReference;
|
489 | private String textWritten; |
||
490 | private boolean updatedModel; |
||
491 | private String textOfReplacement; |
||
492 | private boolean textInRedColor; |
||
493 | private int old_caretPosition; |
||
494 | 10413 | ppiqueras | |
495 | /**
|
||
496 | * Default Constructor
|
||
497 | */
|
||
498 | public PlainDocumentTextFormatter() {
|
||
499 | super();
|
||
500 | this.initialize();
|
||
501 | } |
||
502 | |||
503 | /**
|
||
504 | * This method makes some initialize operations
|
||
505 | */
|
||
506 | private void initialize() { |
||
507 | 11656 | ppiqueras | textWritten = "";
|
508 | textOfReplacement = "";
|
||
509 | textInRedColor = false;
|
||
510 | 10413 | ppiqueras | } |
511 | |||
512 | /**
|
||
513 | 11656 | ppiqueras | * Sets a reference of this component
|
514 | 10413 | ppiqueras | *
|
515 | * @param combo_Box A reference to the class that contains this.
|
||
516 | */
|
||
517 | 11656 | ppiqueras | private void setJComboBoxReference(JComboBoxItemsSeekerConfigurable combo_Box) { |
518 | 10413 | ppiqueras | comboBoxReference = combo_Box; |
519 | } |
||
520 | 11656 | ppiqueras | |
521 | 10413 | ppiqueras | /*
|
522 | * (non-Javadoc)
|
||
523 | 11656 | ppiqueras | * @see javax.swing.text.Document#insertString(int, java.lang.String, javax.swing.text.AttributeSet)
|
524 | 10413 | ppiqueras | */
|
525 | 11656 | ppiqueras | public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { |
526 | if (updatedModel) {
|
||
527 | model.setTextWritten(textWritten); |
||
528 | super.insertString(offs, textWritten, a);
|
||
529 | |||
530 | return;
|
||
531 | } |
||
532 | 10413 | ppiqueras | |
533 | 11656 | ppiqueras | hidePopup(); |
534 | |||
535 | if (textWritten.length() > 0) { |
||
536 | if (offs < textWritten.length()) {
|
||
537 | String old_textWritten = textWritten;
|
||
538 | |||
539 | // End of the text
|
||
540 | textWritten = textWritten.substring(offs, textWritten.length()); |
||
541 | |||
542 | // Beginning of the text
|
||
543 | if (offs > 0) { |
||
544 | // Reset (without text written)
|
||
545 | textWritten = old_textWritten.substring(0, offs) + str + textWritten;
|
||
546 | } |
||
547 | else {
|
||
548 | textWritten = str + textWritten; |
||
549 | } |
||
550 | } |
||
551 | else {
|
||
552 | textWritten = textWritten.substring(0, offs) + str;
|
||
553 | } |
||
554 | } |
||
555 | else {
|
||
556 | textWritten = str; |
||
557 | } |
||
558 | |||
559 | model.setTextWritten(textWritten); |
||
560 | |||
561 | super.insertString(offs, str, a);
|
||
562 | 10413 | ppiqueras | |
563 | 11656 | ppiqueras | // Update the color of the text
|
564 | updateTextColorAndRingBeep(); |
||
565 | |||
566 | if (model.getSize() > 0) { |
||
567 | showPopup(); |
||
568 | } |
||
569 | else {
|
||
570 | if ((textWritten.compareTo("") != 0) && (!hidePopupIfThereAreNoItems_Flag)) { |
||
571 | showPopup(); |
||
572 | } |
||
573 | } |
||
574 | 10413 | ppiqueras | |
575 | 11656 | ppiqueras | // Update the caret position -> at the same place it was or at the end
|
576 | updateCaretPosition(textWritten.length()); |
||
577 | 10413 | ppiqueras | } |
578 | |||
579 | 11656 | ppiqueras | /*
|
580 | * (non-Javadoc)
|
||
581 | * @see javax.swing.text.AbstractDocument#replace(int, int, java.lang.String, javax.swing.text.AttributeSet)
|
||
582 | */
|
||
583 | public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException { |
||
584 | // Avoid two replaces for the same operation
|
||
585 | if ((text.compareTo("") == 0) && (length == textWritten.length())) |
||
586 | return;
|
||
587 | 10413 | ppiqueras | |
588 | 11656 | ppiqueras | // Only remove if there is text to be replaced (text selected)
|
589 | if (length > 0) { |
||
590 | textOfReplacement = text; |
||
591 | remove(offset, length); |
||
592 | } |
||
593 | else {
|
||
594 | if ((offset > 0) && (offset != textWritten.length())) { |
||
595 | // Must replace the model for update the data in the popup correctly
|
||
596 | String old_textWritten;
|
||
597 | |||
598 | // There is a bug that when text has been removed, the elements in the popup aren seen.
|
||
599 | // The solution to this bug is add them as a new model
|
||
600 | hidePopup(); |
||
601 | |||
602 | updatedModel = true;
|
||
603 | |||
604 | old_textWritten = textWritten; |
||
605 | old_caretPosition = ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).getCaretPosition() + text.length();
|
||
606 | |||
607 | textWritten = "";
|
||
608 | model.setTextWritten(textWritten); |
||
609 | |||
610 | super.remove(0, old_textWritten.length()); |
||
611 | |||
612 | // Must replace the model for update the data in the popup correctly
|
||
613 | 11762 | ppiqueras | model = new DefaultComboBoxItemsSeekerConfigurableModel(model.getData());
|
614 | 11656 | ppiqueras | comboBoxReference.setModel(model); |
615 | |||
616 | // Reset (without text written)
|
||
617 | insertString(0, textWritten, null); |
||
618 | |||
619 | // Insert the new text
|
||
620 | textWritten = old_textWritten.substring(0, offset) + text + old_textWritten.substring(offset, old_textWritten.length());
|
||
621 | |||
622 | insertString(0, textWritten, null); |
||
623 | |||
624 | updatedModel = false;
|
||
625 | |||
626 | // Update the color of the text
|
||
627 | updateTextColorAndRingBeep(); |
||
628 | |||
629 | // Update the caret position -> at the same place it was or at the end
|
||
630 | updateCaretPosition(old_caretPosition); |
||
631 | |||
632 | // Only show the popup if there are items to show
|
||
633 | if (model.getSize() > 0) { |
||
634 | showPopup(); |
||
635 | } |
||
636 | else {
|
||
637 | if ((textWritten.compareTo("") != 0) && (!hidePopupIfThereAreNoItems_Flag)) { |
||
638 | showPopup(); |
||
639 | } |
||
640 | } |
||
641 | } |
||
642 | else {
|
||
643 | // Default replacement
|
||
644 | super.replace(offset, length, text, attrs);
|
||
645 | } |
||
646 | } |
||
647 | 10413 | ppiqueras | } |
648 | 11656 | ppiqueras | |
649 | /*
|
||
650 | * (non-Javadoc)
|
||
651 | * @see javax.swing.text.Document#remove(int, int)
|
||
652 | */
|
||
653 | public void remove(int offs, int len) throws BadLocationException { |
||
654 | String old_textWritten;
|
||
655 | |||
656 | // There is a bug that when text has been removed, the elements in the popup aren seen.
|
||
657 | // The solution to this bug is add them as a new model
|
||
658 | hidePopup(); |
||
659 | |||
660 | updatedModel = true;
|
||
661 | |||
662 | old_textWritten = textWritten; |
||
663 | old_caretPosition = Math.min(((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).getCaretPosition(), offs); |
||
664 | |||
665 | textWritten = "";
|
||
666 | model.setTextWritten(textWritten); |
||
667 | |||
668 | super.remove(0, old_textWritten.length()); |
||
669 | |||
670 | // Must replace the model for update the data in the popup correctly
|
||
671 | 11762 | ppiqueras | model = new DefaultComboBoxItemsSeekerConfigurableModel(model.getData());
|
672 | 11656 | ppiqueras | comboBoxReference.setModel(model); |
673 | |||
674 | // Reset (without text written)
|
||
675 | insertString(0, textWritten, null); |
||
676 | |||
677 | // Insert the new text
|
||
678 | textWritten = old_textWritten.substring(0, offs) + textOfReplacement + old_textWritten.substring(offs + len, old_textWritten.length());
|
||
679 | textOfReplacement = "";
|
||
680 | |||
681 | insertString(0, textWritten, null); |
||
682 | |||
683 | updatedModel = false;
|
||
684 | |||
685 | // Update the color of the text
|
||
686 | updateTextColorAndRingBeep(); |
||
687 | |||
688 | // Only show the popup if there are items to show
|
||
689 | if (model.getSize() > 0) { |
||
690 | showPopup(); |
||
691 | } |
||
692 | else {
|
||
693 | if ((textWritten.compareTo("") != 0) && (!hidePopupIfThereAreNoItems_Flag)) { |
||
694 | showPopup(); |
||
695 | } |
||
696 | } |
||
697 | |||
698 | // Update the caret position -> at the same place it was or at the end
|
||
699 | updateCaretPosition(old_caretPosition); |
||
700 | } |
||
701 | 10413 | ppiqueras | |
702 | /**
|
||
703 | 11656 | ppiqueras | * Updates the color of the text in the {@link ComboBoxEditor} of this component.<br>
|
704 | * Also rings a beep if there is no item
|
||
705 | 10413 | ppiqueras | *
|
706 | 11656 | ppiqueras | * <ul>
|
707 | * <li> Text in red color: if no item starts with the text written by the user.
|
||
708 | * <li> Text in black color: if there is at least one item that starts with the text written by the user.
|
||
709 | * </ul>
|
||
710 | 10413 | ppiqueras | */
|
711 | 11656 | ppiqueras | private void updateTextColorAndRingBeep() { |
712 | if (! comboBoxReference.isOnlyOneColorOnText_Flag()) {
|
||
713 | // Set text into red color if no items matches with the text written, or in black color if it was in red
|
||
714 | // color and now there is almost one element that starts with the characteres written by the user
|
||
715 | if (textWritten.compareTo("") != 0) { |
||
716 | if (model.getSize() == 0) { |
||
717 | comboBoxReference.getEditor().getEditorComponent().setForeground(Color.RED);
|
||
718 | textInRedColor = true;
|
||
719 | |||
720 | // Rings a beep if allowed
|
||
721 | if (beepEnabled_Flag)
|
||
722 | comboBoxReference.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
|
||
723 | } |
||
724 | else {
|
||
725 | comboBoxReference.getEditor().getEditorComponent().setForeground(Color.BLACK);
|
||
726 | textInRedColor = false;
|
||
727 | } |
||
728 | 10413 | ppiqueras | } |
729 | else {
|
||
730 | 11656 | ppiqueras | if (textInRedColor) {
|
731 | comboBoxReference.getEditor().getEditorComponent().setForeground(Color.BLACK);
|
||
732 | textInRedColor = false;
|
||
733 | } |
||
734 | 10413 | ppiqueras | } |
735 | 11656 | ppiqueras | } |
736 | else {
|
||
737 | // Rings a beep if no there is no item, and if it's allowed
|
||
738 | if ((textWritten.compareTo("") != 0) && (model.getSize() == 0)) { |
||
739 | if (beepEnabled_Flag)
|
||
740 | comboBoxReference.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
|
||
741 | 10413 | ppiqueras | } |
742 | 11656 | ppiqueras | } |
743 | 10413 | ppiqueras | } |
744 | |||
745 | /**
|
||
746 | 11656 | ppiqueras | * Updates the position of the caret in the {@link ComboBoxEditor} of this component.
|
747 | 10413 | ppiqueras | *
|
748 | 11656 | ppiqueras | * @param position The new position of the caret.
|
749 | 10413 | ppiqueras | */
|
750 | 11656 | ppiqueras | private void updateCaretPosition(int position) { |
751 | // If user has selected an item of the popup (using the mouse) -> set the caret position to the end of the text
|
||
752 | if (popupItemSelected) {
|
||
753 | ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(textWritten.length());
|
||
754 | popupItemSelected = false;
|
||
755 | return;
|
||
756 | } |
||
757 | |||
758 | if (position > textWritten.length())
|
||
759 | ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(textWritten.length());
|
||
760 | else
|
||
761 | ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(position);
|
||
762 | 10413 | ppiqueras | } |
763 | } |
||
764 | } |