Statistics
| Revision:

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
}