Statistics
| Revision:

root / trunk / libraries / libUI / src / org / gvsig / gui / beans / comboBoxItemsSeeker / JComboBoxItemsSeekerDynamic.java @ 6577

History | View | Annotate | Download (42.2 KB)

1
package org.gvsig.gui.beans.comboBoxItemsSeeker;
2

    
3
import java.awt.Color;
4
import java.awt.PopupMenu;
5
import java.awt.event.ActionEvent;
6
import java.awt.event.ActionListener;
7
import java.awt.event.FocusAdapter;
8
import java.awt.event.FocusEvent;
9
import java.awt.event.FocusListener;
10
import java.awt.event.KeyAdapter;
11
import java.awt.event.KeyEvent;
12
import java.awt.event.KeyListener;
13
import java.awt.event.MouseAdapter;
14
import java.awt.event.MouseEvent;
15
import java.awt.event.MouseListener;
16
import java.beans.PropertyChangeEvent;
17
import java.beans.PropertyChangeListener;
18
import java.lang.reflect.Field;
19
import java.util.Iterator;
20

    
21
import javax.swing.ComboBoxEditor;
22
import javax.swing.ComboBoxModel;
23
import javax.swing.JButton;
24
import javax.swing.JComboBox;
25
import javax.swing.JOptionPane;
26
import javax.swing.ListCellRenderer;
27
import javax.swing.event.DocumentEvent;
28
import javax.swing.event.DocumentListener;
29
import javax.swing.event.ListDataEvent;
30
import javax.swing.event.ListDataListener;
31
import javax.swing.plaf.basic.BasicComboBoxRenderer;
32
import javax.swing.plaf.basic.BasicComboBoxUI;
33
import javax.swing.text.AttributeSet;
34
import javax.swing.text.BadLocationException;
35
import javax.swing.text.JTextComponent;
36
import javax.swing.text.PlainDocument;
37

    
38
import org.gvsig.gui.beans.comboBoxItemsSeeker.JComboBoxItemsSeekerDynamic;
39
import org.gvsig.gui.beans.comboBoxItemsSeeker.ComboBoxItemsSeekerDynamicModel;
40

    
41

    
42
import com.iver.andami.PluginServices;
43

    
44
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
45
 *
46
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
47
 *
48
 * This program is free software; you can redistribute it and/or
49
 * modify it under the terms of the GNU General Public License
50
 * as published by the Free Software Foundation; either version 2
51
 * of the License, or (at your option) any later version.
52
 *
53
 * This program is distributed in the hope that it will be useful,
54
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
55
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
56
 * GNU General Public License for more details.
57
 *
58
 * You should have received a copy of the GNU General Public License
59
 * along with this program; if not, write to the Free Software
60
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
61
 *
62
 * For more information, contact:
63
 *
64
 *  Generalitat Valenciana
65
 *   Conselleria d'Infraestructures i Transport
66
 *   Av. Blasco Ib??ez, 50
67
 *   46010 VALENCIA
68
 *   SPAIN
69
 *
70
 *      +34 963862235
71
 *   gvsig@gva.es
72
 *      www.gvsig.gva.es
73
 *
74
 *    or
75
 *
76
 *   IVER T.I. S.A
77
 *   Salamanca 50
78
 *   46005 Valencia
79
 *   Spain
80
 *
81
 *   +34 963163400
82
 *   dac@iver.es
83
 */
84

    
85
/**  VERSI?N EN DESARROLLO
86
 *  REVISAR COMENTARIOS Y C?DIGO QUE PUEDA SOBRAR
87
* This class allows users to insert a chain of characters and show all the sentences of the JComboBox that match its first ones characters with it.
88
* This class is also a Java Bean, and is made according the MVC (Model - View - Controller) pattern.
89
* This class has the View, the Control and can access to the Model.
90
* The behavior of this componet can be configurated by 7 flags: (Esto lo cambio!!!!!)
91
*  + The appearence of the items showed at the beginning and when the user presses the ESCAPE key: (This is configured with 2 flags -> 3 different states are possible) 
92
*             -> maintainPositionItems -> When we see the list of all items, this are showed in the ordenation as they have been introduced (if true); (if false) each new item 
93
*           when we write on the TextField of this Component will be showed at the end (esto ?ltimo creo q. no -> revisarlo)
94
*      -> all_Alphanumeric_Sorted -> All items we can see in this Component will be showed in alphanumeric ordenation (if true)
95
*  + The list of the items showed when the user makes a search writting or pressing the BACK-SPACE key (This is configured with 1 flag -> 2 different states are possible)
96
*      -> alphanumericSortedSearches -> When we write on the TextField of this Component all results (items) are showed in alphanumeric ordenation (if true)
97
*  + Key Sensitive or not when the user writes 
98
*      -> key_Sensitive -> When we write on the TextField it can discriminate upper cases from down cases (if true) or not (if false) (This is configured with 1 flag -> 2 different states are possible)
99
*  + Show all items always
100
*      -> showAllItems -> If true -> this component shows all items always; if false -> this component only shows items that their first characters match with the string written by the user
101
*  + Use one color (black) or 2 colors (black by default and red if the string written doesn't match with the beginning of all items)
102
*      -> only_One_Color -> The text on the textField only will be showed on black color (if true); false -> if the text on the textField doesn't match with any current item of this component -> the text
103
*            will be showed on red color
104
*  +            * @param boolean (completeMatchedItem (explicar))
105
*  + @param boolean (useBeep (explicar))
106
* 
107
* Default Values of the Flags:
108
*  -> maintainPositionItems -> true
109
*  -> all_Alphanumeric_Sorted -> true
110
*  -> alphanumericSortedSearches -> false 
111
*  -> key_Sensitive -> false
112
*  -> showAllItems -> false
113
*  -> only_One_Color -> false
114
*  
115
*  The flags are distributed in two classes:
116
*  -> ComboBoxSearcheableDynamicModel -> maintainPositionItems, all_Alphanumeric_Sorted, alphanumericSortedSearches, key_Sensitive, showAllItems 
117
*  -> JComboBoxSearcheableDynamic -> only_One_Color
118
* 
119
* Combinations of flags not allowed:
120
*         ->        maintainPositionItems == allAlphanumericSorted == true
121
*        ->        ((maintain_Position_Items == false) && (all_Alphanumeric_Sorted == true) && (alphanumeric_Sorted_Searches == false))
122
*   ->  showAllItems == true && maintainPositionItems == false (Creo que esta mal)
123
* 
124
* Limitations:
125
* -> When we add more than one item with the same name (string value) -> the behavior of this component only considers one item in most of the cases when it does a search
126
* -> If this component has Hundreds,Thousands or even Million/s of items is probably that had quite delay to respond the evens of the user; this also depends of the machine where it's executed and other factors
127
* 
128
* @author Pablo Piqueras Bartolom? (p_queras@hotmail.com)
129
*/
130
public class JComboBoxItemsSeekerDynamic extends JComboBox implements java.io.Serializable {
131
        //private static final long serialVersionUID = -1853812970336818959L;
132

    
133
        // eSTAS HAY QUE BORRARLAS!
134
/*        private Vector defaultItems;
135
        private Set notRemovedItems;
136
        private Set removedItems;*/
137
        
138
        
139
        // CONFIGURATION FLAGS
140
        private boolean onlyOneColor;
141
        private boolean completeMatchedItem;
142
        private boolean useBeep;
143
        // END FLAGS
144
        
145
        // PUEDE QUE TB. sOBren
146
//        private boolean allItemsAreSorted;
147
        
148
        // Index in the showed list of the last selected item
149
        private int lastSelectedIndex;
150
        
151
        // pueDE QUE TB. SOBRE
152
//        private int num = 0;
153
//        private JTextField txtField;
154
        
155
        // Reference to the ui
156
        //private MetalComboBoxItemsSeekerUI ui;
157
        
158
        // Reference to the model
159
        private ComboBoxItemsSeekerDynamicModel model;
160
        
161
        // Some listeners for the Control between the View and de Model
162
        private KeyListener editorKeyListener;
163
        private FocusListener editorFocusListener;
164
        private DocumentListener documentListener;
165
        private ListDataListener modelListDataListener;        
166
        
167
        // Reference to the document of the Editor of this component for optimize the seeks
168
        private PlainDocumentSeeker document;
169
        
170
        private String writtenString;
171
        
172
        private boolean upOrDownKeyPressed;
173
        
174
        // OTRAS FLAGS que puede que sobren alguNAS
175
        private boolean selecting=false;
176
        private boolean hidePopupOnFocusLoss;
177
        private boolean hitBackspace=false;
178
        private boolean hitBackspaceOnSelection;        
179
        
180
        /**
181
         * Default Constructor
182
         */
183
        public JComboBoxItemsSeekerDynamic() {
184
                // Invokes to the parent class constructor                
185
                super();
186

    
187
                // Create attributes and set initial values
188
                this.initialize();
189
                
190
                // Set the default values of the flags
191
                this.onlyOneColor = false;
192
                this.completeMatchedItem = false; //true;
193
                this.useBeep = false; //true;
194
                
195
                // Other configuration tasks
196
                this.createDefaultListeners();
197
                this.configure();
198
                //this.configure();
199
        }
200
        
201
        /**
202
         * Default Constructor with four parameters: configure the 4 flags
203
         * 
204
         * @param boolean (true -> maintains the position of the items; false -> don't maintains the position of the items)
205
         * @param boolean (true -> all items showed when we write on the textfield will be showed in alphanumeric ordenation; false -> they don't have to be in alphanumeric ordenation)
206
         * @param boolean (true -> all items showed will be in alphanumeric ordenation; false -> they don't have to be in alphanumeric ordenation)
207
         * @param boolean (true -> discriminates capital letters from small letters; false -> don't discriminates capital letters from small letters)
208
         */
209
        public JComboBoxItemsSeekerDynamic(boolean maintain_Position_Items, boolean alphanumeric_Sorted_Searches, boolean all_Alphanumeric_Sorted, boolean key_Sensitive)        {
210
                // Invokes to the parent class constructor                
211
                super();        
212

    
213
                // Create attributes and set initial values
214
                this.initialize();
215
                
216
                // Sets the options selected by the user
217
                this.model.setMaintainPositionItems(maintain_Position_Items);
218
                this.model.setAllAlphanumericSorted(all_Alphanumeric_Sorted);
219
                this.model.setAlphanumericSortedSearches(alphanumeric_Sorted_Searches);
220
                this.model.setKeySensitive(key_Sensitive);
221
                this.model.setShowAllItems(false);
222
                this.onlyOneColor = false;
223
                this.completeMatchedItem = true;
224
                this.useBeep = false; //true;
225
                
226
                if (!testFlagsConfigurationOK())
227
                        JOptionPane.showMessageDialog(this, PluginServices.getText(this, "error_message_JComboBoxSearcheableDynamic"), PluginServices.getText(this, "exportJOP2Title"), JOptionPane.ERROR_MESSAGE);
228
                else
229
                        this.configure();
230
        }
231

    
232
        /**
233
         * Default Constructor with six parameters: configure the 6 flags
234
         * 
235
         * @param boolean (true -> maintains the position of the items; false -> don't maintains the position of the items)
236
         * @param boolean (true -> all items showed when we write on the textfield will be showed in alphanumeric ordenation; false -> they don't have to be in alphanumeric ordenation)
237
         * @param boolean (true -> all items showed will be in alphanumeric ordenation; false -> they don't have to be in alphanumeric ordenation)
238
         * @param boolean (true -> discriminates capital letters from small letters; false -> don't discriminates capital letters from small letters)
239
         * @param boolean (true -> the text on the textField only will be showed on black color (if true); false -> if the text on the textField doesn't match with any current item of this component -> the text
240
         *                           will be showed on red color)
241
           * @param boolean (true -> this component shows all items always; false -> this component only shows items that their first characters match with the string written by the user)
242
           * @param boolean (completeMatchedItem (explicar))
243
           * @param boolean (useBeep (explicar))
244
         */
245
        public JComboBoxItemsSeekerDynamic(boolean maintain_Position_Items, boolean alphanumeric_Sorted_Searches, boolean all_Alphanumeric_Sorted, boolean key_Sensitive, boolean only_One_Color, boolean show_All_Items, boolean complete_Matched_Item, boolean use_Beep) {
246
                // Invokes to the parent class constructor                
247
                super();        
248

    
249
                // Create attributes and set initial values
250
                this.initialize();
251
                
252
                // Sets the options selected by the user
253
                this.model.setMaintainPositionItems(maintain_Position_Items);
254
                this.model.setAllAlphanumericSorted(all_Alphanumeric_Sorted);
255
                this.model.setAlphanumericSortedSearches(alphanumeric_Sorted_Searches);
256
                this.model.setKeySensitive(key_Sensitive);
257
                this.model.setShowAllItems(show_All_Items);
258
                this.onlyOneColor = only_One_Color;
259
                this.completeMatchedItem = complete_Matched_Item;
260
                this.useBeep = use_Beep;
261
                
262
                if (!testFlagsConfigurationOK())
263
                        JOptionPane.showMessageDialog(this, PluginServices.getText(this, "error_message_JComboBoxSearcheableDynamic"), PluginServices.getText(this, "exportJOP2Title"), JOptionPane.ERROR_MESSAGE);
264
                else
265
                        this.configure();
266
        }
267
        
268

    
269
        /**
270
         * 
271
         */
272
        private void initialize() {
273
//                // Creates the ui for this component and gets it reference
274
//                super.setUI(new MetalComboBoxItemsSeekerUI());
275
//                this.ui = (MetalComboBoxItemsSeekerUI) super.getUI();
276
                
277
                // Creates the model for this component and gets it reference
278
                super.setModel(new ComboBoxItemsSeekerDynamicModel());
279
                this.model = (ComboBoxItemsSeekerDynamicModel) super.getModel();
280
                
281
        // Allows user to edit on the combobox
282
                super.setEditable(true);
283
                
284
                // Set the last selected item -> if there isn't any item -> -1; else -> this will be 0
285
                this.lastSelectedIndex = -1;
286
                super.setSelectedIndex(lastSelectedIndex);
287
//                System.out.println("lastselecteditem: " + this.getSelectedIndex());
288
                
289
                // By default the keys Up and Down aren't pressed
290
                this.upOrDownKeyPressed = false;
291
        }
292
        
293
        /**
294
         * 
295
         */
296
        private void createDefaultListeners() {
297
                // TODO Auto-generated method stub
298
                
299
        // Define the key listener for the editor of this component
300
        this.defineEditorKeyListener(this);
301
        
302
        // Define the focus listener for the editor of this component
303
        this.defineEditorFocusListener(this);
304
        
305
        // Define a document listener for changes of text
306
        this.defineDocumentListener();
307
         
308
                // Define the list data listener for the model of this component
309
        this.defineModelListDataListener();
310
        }
311
        
312
        /**
313
         *  Define a document listener for changes of text
314
         */
315
        private void defineDocumentListener() {
316
                // TODO Auto-generated method stub
317
               documentListener = new DocumentListener() {
318

    
319
                        public void changedUpdate(DocumentEvent arg0) {
320
                                // TODO Auto-generated method stub
321
//                                System.out.println("NUM: " + num + " DocumentListener->changedUpdate");
322
//                                num++;
323
                        }
324

    
325
                        public void insertUpdate(DocumentEvent arg0) {
326
                                // TODO Auto-generated method stub
327
//                                System.out.println("NUM: " + num + " DocumentListener->insertUpdate");
328
//                                num++;
329
                                
330
                                // This flag indicates to the 'insertString' and 'remove' method of the PlainDocumentSeeker that the text of the item selected or written by the user
331
                                //  has been written on the TextEditor of ths component
332
                                selecting = true;
333
                                
334
                                // Indicate to the model than there has been a change of item selected
335
                                if (!upOrDownKeyPressed)  // If items have to be showed disordered, if we have pushed the UP or DOWN key -> we don't disorder the items this time
336
                                        model.setWrittenString("AAA");
337
                                else
338
                                        upOrDownKeyPressed = false;
339
                                //model.setWrittenString(writtenString);
340
                        }
341

    
342
                        public void removeUpdate(DocumentEvent arg0) {
343
                                // TODO Auto-generated method stub
344
//                                System.out.println("NUM: " + num + " DocumentListener->removeUpdate");
345
//                                num++;
346
                        }                        
347
                };
348
        }
349

    
350
        /**
351
         * 
352
         */
353
        private void configure() {
354
                // TODO Auto-generated method stub
355
                
356
                // Configure the document of the editor of this component
357
                this.configureDocument();
358
                
359
                // Configure the editor (ComboBoxEditor) of this component
360
                this.configureEditor(this.getEditor());        
361
                
362
                // Configure the model of this component
363
                this.configureModel();
364
        }
365
        
366
//        /**
367
//         * 
368
//         */
369
//        private void uninstallDefaultListeners() {
370
//        
371
//
372
//        }
373

    
374
        /**
375
         * 
376
         */
377
        private void configureModel() {
378
                // TODO Auto-generated method stub
379
                this.model.addListDataListener(this.modelListDataListener);
380
        }        
381

    
382
        /**
383
         * 
384
         */
385
        private void configureDocument() {
386
                // TODO Auto-generated method stub
387
                
388
                // Creates the document of the editor of this component
389
        document = new PlainDocumentSeeker();
390
        document.setJComboBoxItemsSeekerDynamicReference(this);
391
        
392
                // Set the written String
393
                writtenString = "";
394
                
395
                // Remove all Previous document Listeners
396
//                DocumentListener documentListener[] = document.getDocumentListeners();
397
//                for (int i=0; i < documentListener.length; i++)
398
//                        document.removeDocumentListener(documentListener[i]);
399
                
400
                // Defines and add a Document listener for changes on the document of the editor of this component
401
                document.addDocumentListener(this.documentListener);
402

    
403
        }
404
        
405
        
406
        /**
407
         * Define the list data listener for the model of this component
408
         */
409
    public void defineModelListDataListener() {
410
                
411
                this.modelListDataListener = new ListDataListener()        {
412

    
413
                        public void contentsChanged(ListDataEvent e) {
414
                                // TODO Auto-generated method stub
415
//                                System.out.println("ContentsChanged");
416
                                
417
                                // This flag indicates to the 'insertString' and 'remove' methods of the PlainDocumentSeeker that the text of the item selected or written by the user
418
                                //  hasn't been written on the TextEditor of ths component
419
                                selecting = false;
420
                        }
421

    
422
                        public void intervalAdded(ListDataEvent e) {
423
                                // TODO Auto-generated method stub
424
        //                        System.out.println("intervalAdded");
425
                        }
426

    
427
                        public void intervalRemoved(ListDataEvent e) {
428
                                // TODO Auto-generated method stub
429
        //                        System.out.println("intervalRemoved");
430
                        }
431
                        
432
                };
433

    
434
    }
435

    
436
        /**
437
         * ?Sobra? Contiene c?digo interesante
438
         */
439
        private void defineAndAddPropertyChangeListener() {
440
                // Define and add a Listener for changes on the editor or the model of the JComboBox
441
        super.addPropertyChangeListener(new PropertyChangeListener() {
442
            public void propertyChange(PropertyChangeEvent ev) {
443
                if (ev.getPropertyName().equals("editor"))
444
                        configureEditor((ComboBoxEditor) ev.getNewValue());
445
                if (ev.getPropertyName().equals("model"))
446
                        model = (ComboBoxItemsSeekerDynamicModel) ev.getNewValue();
447
            }
448
        });
449
        }
450

    
451
        /**
452
         * ?SOBRA? De momento la estoy usando, pero no s? si sobra o no
453
         */
454
        private void defineEditorFocusListener(JComboBoxItemsSeekerDynamic combo_Box) {
455
                final JComboBoxItemsSeekerDynamic comboBox = combo_Box;
456
                
457
                // TODO Auto-generated method stub
458
                // Highlight whole text when gaining focus
459
                editorFocusListener = new FocusAdapter() {
460
                        public void focusGained(FocusEvent e) {
461
                                highlightCompletedText(0);
462
                        }
463
                        
464
                        public void focusLost(FocusEvent e) {
465
                                // Workaround for Bug 5100422 - Hide Popup on focus loss
466
                                if (hidePopupOnFocusLoss) comboBox.setPopupVisible(false);
467
                        }
468
                };
469
        }
470

    
471
        /**
472
         * 
473
         */
474
        private void defineEditorKeyListener(JComboBoxItemsSeekerDynamic combo_Box) {
475
                final JComboBoxItemsSeekerDynamic comboBoxReference = combo_Box;
476

    
477
                // TODO Auto-generated method stub
478
                editorKeyListener = new KeyAdapter()
479
                {
480
                        public void keyPressed(KeyEvent ke)
481
                        {
482
                                // This flag indicates to the 'insertString' and 'remove' methods of the PlainDocumentSeeker that the text of the item selected or written by the user
483
                                //  hasn't been written on the TextEditor of ths component
484
                                selecting = false;
485
                                
486
                                if (comboBoxReference.isDisplayable())
487
                                        comboBoxReference.setPopupVisible(true);
488
                                hitBackspace=false;
489
                    
490
                                JTextComponent editor = (JTextComponent) comboBoxReference.getEditor().getEditorComponent();
491
                                
492
                                switch (ke.getKeyCode())
493
                                {
494
                                        // determine if the pressed key is backspace (needed by the remove method)
495
                                        case KeyEvent.VK_BACK_SPACE :
496
                                                
497
                                                // Delete the last character written
498
//                                                String currentString = model.getCurrentString();
499
//                                                if (currentString.length() > 0)
500
//                                                        model.setCurrentString(currentString.substring(0,model.getCurrentString().length()-1));
501
                                                
502
                                                hitBackspace=true;
503
                                                hitBackspaceOnSelection=editor.getSelectionStart()!=editor.getSelectionEnd();
504
                                                break;
505
                                        // ignore delete key
506
                                        case KeyEvent.VK_DELETE : // supr key in spanish keyboard
507
                                                // Do nothing -> use the default behavior
508
                                                //ke.consume();
509
                                                break;
510
                                        case KeyEvent.VK_DOWN :
511
                                            // If the key (typed, pressed and) released has been the Down Key -> when there isn't any text (item of the list) selected, select the first
512
                                                ke.consume();
513
        //                                        selecting = true; // For indicate to the 'insertString' of the 'PlainDocumentSeeker' class that an item has been selected
514
                                                upOrDownKeyPressed = true;
515
                                                
516
                                                if (getItemCount() > 0)
517
                                                {
518
                                                        if (lastSelectedIndex == (getItemCount()-1))
519
                                                                ((JComboBox)comboBoxReference).setSelectedIndex(0);
520
                                                        else
521
                                                                ((JComboBox)comboBoxReference).setSelectedIndex(lastSelectedIndex+1);
522
                                                }
523
                                                
524
//                                                model.setCurrentString(getSelectedItem().toString());
525
                                                
526
                                                lastSelectedIndex = getSelectedIndex();
527
                                                showPopup();
528
                                                break;
529
                                        case KeyEvent.VK_UP :
530
                                            // If the key (typed, pressed and) released has been the Up Key -> when there isn't any text (item of the list) selected, select the last
531
                                                ke.consume();
532
        //                                        selecting = true; // For indicate to the 'insertString' of the 'PlainDocumentSeeker' class that an item has been selected
533
                                                upOrDownKeyPressed = true;
534
                                                
535
                                                switch(lastSelectedIndex)
536
                                                {
537
                                                        case -1: case 0:
538
                                                                ((JComboBox)comboBoxReference).setSelectedIndex(getItemCount()-1);
539
                                                                break;
540
                                                        default:
541
                                                                ((JComboBox)comboBoxReference).setSelectedIndex(lastSelectedIndex-1);
542
                                                }
543
                                                
544
//                                                model.setCurrentString(getSelectedItem().toString());
545
                                                lastSelectedIndex = getSelectedIndex();
546
                                                showPopup();
547
                                                break;
548
                                        case KeyEvent.VK_LEFT :
549
                                                // Do nothing -> use the default behavior
550
                                                //ke.consume();
551
                                                break;
552
                                        case  KeyEvent.VK_RIGHT :
553
                                                // Do nothing -> use the default behavior
554
                                                //ke.consume();
555
                                                break;
556
                                        case  KeyEvent.VK_PAGE_DOWN :
557
                                                // Do nothing -> use the default behavior
558
                                        //        ke.consume();
559
                                                break;
560
                                        case KeyEvent.VK_PAGE_UP :
561
                                                // Do nothing -> use the default behavior
562
                                        //        ke.consume();
563
                                                break;                                        
564
                                        case KeyEvent.VK_TAB :
565
                                                if (model.getSize() > 0)
566
                                                {
567
//                                                        System.out.println("SelectedIndex: " + getSelectedIndex());
568
                                                        if (((JComboBox)comboBoxReference).getSelectedIndex() == -1)
569
                                                        {
570
                                                                lastSelectedIndex = 0;
571
                                                                ((JComboBox)comboBoxReference).setSelectedIndex(lastSelectedIndex);
572
                                                        }
573
                                                        else
574
                                                        {
575
                                                                lastSelectedIndex = getSelectedIndex();
576
                                                                setSelectedIndex(lastSelectedIndex);        // Complete the item string value in the document of the editor                                                        
577
                                                        }
578
                                                        
579
                                                        hidePopup();
580
                                                }
581
                                                break;
582
                                        case KeyEvent.VK_ESCAPE :
583
                                                // Reset to the beginning behavior
584
                                                setSelectedIndex(0);
585
                                                highlightCompletedText(0);
586
                                                break;
587

    
588
                                        default:
589
                                                //System.out.println("Key Pressed:" + ke.getKeyCode());
590
                                                 if (editor.getText().trim().equalsIgnoreCase("")) {
591
                                                        // If the current string in the JTextField of the Editor is an empty string -> hide the popup list and the reset the index
592
                                                        lastSelectedIndex = -1;
593
                                                        setSelectedIndex(lastSelectedIndex);
594
                                                        hidePopup();
595
                                                 }
596
                                                
597
                                                
598
                                                
599
//                                        // If the key (typed, pressed and) released has been the TAB Key -> try to complete the current selected item from the list and hide the popup list
600
//
601
//                                        // If there isn't any item selected and there are items, select and show the first item
602
//                                        if (this.getModel().getSize() > 0)
603
//                                        {
604
//                                                if (!showAllItems)
605
//                                                {
606
//                                                        int numItems = this.getItemCount();
607
//                                                        
608
//                                                        if (alphanumericSortedSearches)
609
//                                                        {
610
//                                                                for (int i=1; i < numItems; i++)
611
//                                                                {
612
//                                                                        removedItems.add(this.getModel().getElementAt(1));
613
//                                                                        notRemovedItems.remove(this.getModel().getElementAt(1));
614
//                                                                        this.removeItemAt(1);
615
//                                                                }
616
//                                                        }
617
//                                                        else
618
//                                                        {
619
//                                                                for (int i=1; i < numItems; i++)
620
//                                                                {
621
//                                                                        removedItems.add(this.getModel().getElementAt(1));
622
//                                                                        this.removeItemAt(1);
623
//                                                                }                                                        
624
//                                                        }
625
//                                                
626
//                                                        // Show a item
627
//                                                        this.setSelectedIndex(0);
628
//                                                }
629
//                                        }
630
                                                // A?ADIR LOS CASOS DE TECLA-ESCAPE; y ??
631
//                                } else if (ke.getKeyChar() == KeyEvent.VK_ESCAPE) {
632
//                                        // If the key (typed, pressed and) released has been the Escape Key -> hide the popup list and empty the JTextField                        
633
//                                        this.hidePopup();
634
//                                        
635
//                                        if ((!maintainPositionItems) && (!allAlphanumericSorted))
636
//                                        {
637
//                                                if (removedItems.size() > 0)
638
//                                                {
639
//                                                        Iterator it = removedItems.iterator();
640
//                                                        
641
//                                                        while(it.hasNext())
642
//                                                                super.addItem(it.next());
643
//                                                        
644
//                                                        removedItems.clear();
645
//                                                }
646
//                                        }
647
//                                        else
648
//                                                this.setModel(getCopyOfModel());
649
//
650
//                                        txtField.setText("");
651
//                                        txtField.setForeground(Color.BLACK);
652
//                                        lastSelectedItem = -1;
653
//                                        this.setSelectedIndex(lastSelectedItem);
654
//
655
//                                
656
//
657
                                                //                                    } else if (txtField.getText().trim().equalsIgnoreCase("")) {
658
//                                                // If the current string in the JTextField of the Editor is an empty string -> hide the popup list and the reset the index
659
//                                            lastSelectedItem = -1;
660
//                                                this.setSelectedIndex(lastSelectedItem);
661
//                                                this.hidePopup();                                                
662
                        //        default: // Alphanumeric and simbols keys
663
                                                // Add the new character written
664
//                                                model.setCurrentString(model.getCurrentString().concat(String.valueOf(ke.getKeyChar())));
665
                }
666
            }
667
                };
668
        }
669
        
670
        private void configureEditor(ComboBoxEditor newEditor) {
671
            JTextComponent editor = (JTextComponent) this.getEditor().getEditorComponent();                
672

    
673
            // If there isn't any change on the editor
674
            if (editor == newEditor)
675
                    return;
676
            
677
                // Remove the default or last keyListener and FocusListener of the editor of this component
678
        if (editor != null) {
679
            editor.removeKeyListener(this.editorKeyListener);
680
            editor.removeFocusListener(this.editorFocusListener);            
681
        }
682
        
683
        // Add the new keyListener and FocusListener for this editor and sets
684
        //   it document as a PlainDocument to optimize the searches of items
685
        //   when user writes on this editor
686
        if (newEditor != null) {
687
            editor = (JTextComponent) newEditor.getEditorComponent();
688
            editor.addKeyListener(this.editorKeyListener);
689
            editor.addFocusListener(this.editorFocusListener);
690
            editor.setDocument(this.document);
691
            
692
                    // Disable the focus transversal keys (Example: CTRL+TAB) for enable the TAB key
693
                    editor.setFocusTraversalKeysEnabled(false);
694
        }
695
        }
696
        
697
        /**
698
         * Marks text since 'start' position to its end on a grey color
699
         *  
700
         * @param start Start position for mark the text
701
         */
702
    private void highlightCompletedText(int start) {
703
            JTextComponent editor = (JTextComponent) this.getEditor().getEditorComponent();
704
            
705
        editor.setCaretPosition(document.getLength());
706
        editor.moveCaretPosition(start);
707
    }
708
    
709
////// REDEFINITION OF SOME METHODS OF JCOMBOBOX //////
710

    
711

    
712
        /*
713
         *  (non-Javadoc)
714
         * @see javax.swing.JComboBox#actionPerformed(java.awt.event.ActionEvent)
715
         */
716
        public void actionPerformed(ActionEvent e)
717
        {
718
                super.actionPerformed(e);
719
//                System.out.println("Action-Performed");
720

    
721
                // This flag indicates to the 'insertString' method of the PlainDocumentSeeker that the text of the item selected or written by the user
722
                //  hasn't been written on the TextEditor of ths component
723
                selecting = false;
724
        }
725

    
726
    
727
    /*
728
     * (non-Javadoc)
729
     * @see javax.swing.JComboBox#addItem(java.lang.Object)
730
     */
731
    public void addItem(Object anObject) {
732
                // Add the item to this component                
733
                model.addElement(anObject);
734
                
735
//                System.out.println("LastSelectedIndexWas: " + this.lastSelectedIndex);
736
                // Set the last selected item -> by default select the first item
737
                if (this.lastSelectedIndex == -1)
738
                {
739
                        this.lastSelectedIndex = 0;
740
                        this.setSelectedIndex(this.lastSelectedIndex);
741
//                        model.setCurrentString(anObject.toString());
742
                }
743
        }
744
    
745
//    /*
746
//     * (non-Javadoc)
747
//     * @see javax.swing.JComboBox#getSelectedIndex()
748
//     */
749
//    public int getSelectedIndex() {
750
//            // ??Modificarlo??
751
//            return super.getSelectedIndex();
752
//    }
753
    
754
    /*
755
     * (non-Javadoc)
756
     * @see javax.swing.JComboBox#getItemCount()
757
     */
758
    public int getItemCount() {
759
            return model.getSize();
760
    }
761
    
762
    /*
763
     * (non-Javadoc)
764
     * @see javax.swing.JComboBox#getItemAt(int)
765
     */
766
    public Object getItemAt(int index) {
767
            return model.getElementAt(index);
768
    }
769
    
770
    /*
771
     * (non-Javadoc)
772
     * @see javax.swing.JComboBox#setModel(javax.swing.ComboBoxModel)
773
     */
774
    public void setModel(ComboBoxModel aModel) { //PROBLEMA
775
            
776
            // Depending on the type of class of the current object, this object will execute different code
777
            if (aModel instanceof ComboBoxItemsSeekerDynamicModel)
778
            {
779
//                    System.out.println("A");
780
                    //super.setModel(aModel);
781
                    super.setModel(aModel);
782
                    model = (ComboBoxItemsSeekerDynamicModel)super.getModel();
783
                    
784
                    // If we insert a model with items -> select by default the first
785
                    if (aModel.getSize() > 0)
786
                    {
787
                            this.lastSelectedIndex = 0;
788
                            this.setSelectedIndex(this.lastSelectedIndex);
789
//                            model.setCurrentString(this.getSelectedItem().toString());
790
                    }
791
                    else
792
                    {
793
                            // Else -> set the default index (-1) and current showed string ("")
794
                            this.lastSelectedIndex = -1;
795
                            this.setSelectedIndex(this.lastSelectedIndex);
796
//                            model.setCurrentString("");
797
                    }
798
                    
799
                    this.configureModel();
800
            }
801
            else
802
            {
803
                    // If it's an instance of DefaultComboBoxModel:
804
                    
805
//                    System.out.println("B");
806
                    super.setModel(aModel);                    
807
            }                    
808
     }
809
    
810
    /*
811
     * (non-Javadoc)
812
     * @see javax.swing.JComboBox#setSelectedIndex(int)
813
     */
814
    public void setSelectedIndex(int anIndex) {
815
            super.setSelectedIndex(anIndex);
816
            
817
            this.lastSelectedIndex = anIndex;
818
            
819
            try {
820
                        document.remove(0, document.getLength());
821
                        if (getSelectedIndex() > -1)
822
                                document.insertString(0, getSelectedItem().toString(), null);
823
                        else
824
                                this.lastSelectedIndex = -1;
825
                        
826
                } catch (BadLocationException e) {
827
                        // TODO Auto-generated catch block
828
                        e.printStackTrace();
829
                }                
830
    }
831
    
832
    /*
833
     *  (non-Javadoc)
834
     * @see javax.swing.JComboBox#setSelectedItem(java.lang.Object)
835
     */
836
    public void setSelectedItem(Object anObject) {
837
            super.setSelectedItem(anObject);
838
            this.lastSelectedIndex = model.getIndexOf(anObject);
839
//            System.out.println("Posici?n: " + this.lastSelectedIndex);
840
            
841
            //super.setSelectedIndex(this.lastSelectedIndex);
842
            
843
//            try {
844
//                        document.remove(0, document.getLength());
845
//                        if (getSelectedIndex() > -1)
846
//                                document.insertString(0, getSelectedItem().toString(), null);
847
//                        else
848
//                                this.lastSelectedIndex = -1;
849
//                        
850
//                } catch (BadLocationException e) {
851
//                        // TODO Auto-generated catch block
852
//                        e.printStackTrace();
853
//                }                
854
    }
855
    
856
//    
857
    ////// END REDEFINITION OF SOME METHODS OF JCOMBOBOX //////
858
        
859
    
860
    
861
    
862
        
863
        ////// METHODS FOR THE BEHAVIOR FLAGS  //////
864

    
865
        /**
866
         * This method tests the configuration of the flags and returns true or false if its ok or not with the
867
         *   logical behavior of this component
868
         * 
869
         * @return boolean True if the configuration of the flags is oks, false if not
870
         */
871
        public boolean testFlagsConfigurationOK() {
872
                return this.model.testFlagsConfigurationOK();
873
        }
874
        
875
        /**
876
         * Gets the flag of the configuration of the policy for maintain the position of the items of this component 
877
         * (true -> maintains the position of the items, false -> don't maintains the position of the items)
878
         * 
879
         * @return boolean The value of the flag
880
         */
881
        public boolean isMaintainPositionItems() {
882
                return this.model.isMaintainPositionItems();
883
        }
884
        
885
        /**
886
         * Sets the flag of the configuration of the policy for maintain the position of the items of this component 
887
         * (true -> maintains the position of the items, false -> don't maintains the position of the items)
888
         * 
889
         * @param boolean The value of the flag
890
         */
891
        public void setMaintainPositionItems(boolean maintain_Position_Items) {
892
                this.model.setMaintainPositionItems(maintain_Position_Items);
893

    
894
                if (!this.model.testFlagsConfigurationOK())
895
                        JOptionPane.showMessageDialog(this, PluginServices.getText(this, "error_message_JComboBoxSearcheableDynamic"), PluginServices.getText(this, "exportJOP2Title"), JOptionPane.ERROR_MESSAGE);
896
        }
897
        
898
        /**
899
         * Gets the flag of the configuration of the alphanumericSortedSearches flag of this component 
900
         * (true -> all items showed when we write on the textfield will be showed in alphanumeric ordenation; false -> they don't have to be in alphanumeric ordenation)
901
         * 
902
         * @return boolean The value of the flag
903
         */
904
        public boolean isAlphanumericSortedSearches() {
905
                return this.model.isAlphanumericSortedSearches();
906
        }
907
        
908
        /**
909
         * Sets the flag of the configuration of the alphanumericSortedSearches flag of this component 
910
         * (true -> all items showed when we write on the textfield will be showed in alphanumeric ordenation; false -> they don't have to be in alphanumeric ordenation)
911
         * 
912
         * @param boolean The value of the flag
913
         */
914
        public void setAlphanumericSortedSearches(boolean alphanumeric_Sorted_Searches) {
915
                this.model.setAlphanumericSortedSearches(alphanumeric_Sorted_Searches);
916
                
917
                if (!this.model.testFlagsConfigurationOK())
918
                        JOptionPane.showMessageDialog(this, PluginServices.getText(this, "error_message_JComboBoxSearcheableDynamic"), PluginServices.getText(this, "exportJOP2Title"), JOptionPane.ERROR_MESSAGE);
919

    
920
//                if (this.model.isAlphanumericSortedSearches())
921
//                {
922
//                        notRemovedItems = new HashSet();
923
//                        
924
//                        for (int i=0; i < this.getItemCount(); i++)
925
//                                notRemovedItems.add(this.getItemAt(i));
926
//                }
927
//                else
928
//                        notRemovedItems.clear();
929

    
930
        }
931
        
932
        /**
933
         * Gets the flag of the configuration of the allAlphanumericSorted flag of this component 
934
         * (true -> all items showed will be in alphanumeric ordenation; false -> they don't have to be in alphanumeric ordenation)
935
         * 
936
         * @return boolean The value of the flag
937
         */
938
        public boolean isAllAlphanumericSorted() {
939
                return this.model.isAllAlphanumericSorted();
940
        }
941
        
942
        /**
943
         * Sets the flag of the configuration of the allAlphanumericSorted flag of this component 
944
         * (true -> all items showed will be in alphanumeric ordenation; false -> they don't have to be in alphanumeric ordenation)
945
         * 
946
         * @param boolean The value of the flag
947
         */
948
        public void setAllAlphanumericSorted(boolean all_Alphanumeric_Sorted) {
949
                this.model.setAllAlphanumericSorted(all_Alphanumeric_Sorted);
950
                
951
//                if (allAlphanumericSorted)
952
                
953
                if (!this.model.testFlagsConfigurationOK())
954
                        JOptionPane.showMessageDialog(this, PluginServices.getText(this, "error_message_JComboBoxSearcheableDynamic"), PluginServices.getText(this, "exportJOP2Title"), JOptionPane.ERROR_MESSAGE);
955
        }
956
        
957
        /**
958
         * Gets the flag of the configuration of the keySensitive flag of this component 
959
         * (true -> discriminates capital letters from small letters ,false -> don't discriminates capital letters from small letters)
960
         * 
961
         * @return boolean The value of the flag
962
         */
963
        public boolean isKeySensitive() {
964
                return this.model.isKeySensitive();
965
        }
966
        
967
        /**
968
         * Sets the flag of the configuration of the keySensitive flag of this component 
969
         * (true -> discriminates capital letters from small letters ,false -> don't discriminates capital letters from small letters)
970
         * 
971
         * @param boolean The value of the flag
972
         */
973
        public void setKeySensitive(boolean key_Sensitive) {
974
                this.model.setKeySensitive(key_Sensitive);
975
                
976
                if (!this.model.testFlagsConfigurationOK())
977
                        JOptionPane.showMessageDialog(this, PluginServices.getText(this, "error_message_JComboBoxSearcheableDynamic"), PluginServices.getText(this, "exportJOP2Title"), JOptionPane.ERROR_MESSAGE);
978
        }
979

    
980
        /**
981
         * Gets the flag of the configuration of the onlyOneColor flag of this component
982
         * (true -> The text on the textField only will be showed on black color; false -> if the text on the textField doesn't match with any current item of this 
983
         *            component -> the text will be showed on red color)
984
         * 
985
         * @return boolean The value of the flag
986
         */
987
        public boolean isOnlyOneColor() {
988
                return onlyOneColor;
989
        }
990

    
991
        
992
        /**
993
         * Sets the flag of the configuration of the onlyOneColor flag of this component 
994
         * (true -> discriminates capital letters from small letters ,false -> don't discriminates capital letters from small letters)
995
         * 
996
         * @param boolean The value of the flag
997
         */
998
        public void setOnlyOneColor(boolean only_One_Color) {
999
                this.onlyOneColor = only_One_Color;
1000
                
1001
                if (!this.model.testFlagsConfigurationOK())
1002
                        JOptionPane.showMessageDialog(this, PluginServices.getText(this, "error_message_JComboBoxSearcheableDynamic"), PluginServices.getText(this, "exportJOP2Title"), JOptionPane.ERROR_MESSAGE);
1003
        }
1004
        
1005
        /**
1006
         * Gets the flag of the configuration of the showAllItems flag of this component
1007
         * (true -> this component shows all items always; false -> this component only shows items that their first characters match with the string written by the user) 
1008
         * 
1009
         * @return boolean The value of the flag
1010
         */
1011
        public boolean isShowAllItems() {
1012
                return this.model.isShowAllItems();
1013
        }
1014

    
1015
        /**
1016
         * Sets the flag of the configuration of the showAllItems flag of this component
1017
         * (true -> this component shows all items always; false -> this component only shows items that their first characters match with the string written by the user)
1018
         * 
1019
         * @return boolean The value of the flag
1020
         */
1021
        public void setShowAllItems(boolean show_All_Items) {
1022
                this.model.setShowAllItems(show_All_Items);
1023
                
1024
//                if (this.model.isShowAllItems() == false)
1025
//                        this.setModel(getCopyOfModel());
1026
        }
1027
        
1028
        ////// END METHODS FOR THE BEHAVIOR FLAGS  //////
1029
        
1030
        
1031
        /** REVISAR COMENTARIOS Y C?DIGO
1032
         * Inner class for optimize the seek of items
1033
         * 
1034
         * @author Pablo Piqueras Bartolom? (p_queras@hotmail.com)
1035
         *
1036
         */
1037
        private class PlainDocumentSeeker extends PlainDocument{
1038
                private JComboBoxItemsSeekerDynamic comboBox;
1039

    
1040
                /**
1041
                 * Default Constructor
1042
                 */
1043
                public PlainDocumentSeeker() {
1044
                        super();
1045
                }
1046
                
1047
                /**
1048
                 * Sets a reference of the combo_Box
1049
                 * 
1050
                 * @param combo_Box
1051
                 */
1052
                public void setJComboBoxItemsSeekerDynamicReference(JComboBoxItemsSeekerDynamic combo_Box) {
1053
                        comboBox = combo_Box;
1054
                }
1055
                
1056
                /* REVISAR
1057
                 *  (non-Javadoc)
1058
                 * @see javax.swing.text.Document#remove(int, int)
1059
                 */
1060
                public void remove(int offs, int len) throws BadLocationException {
1061
                // return immediately when selecting an item
1062
                if (selecting) return;
1063

    
1064
                if (hitBackspace)
1065
                {
1066
                    // user hit backspace => move the selection backwards
1067
                    // old item keeps being selected
1068
                    if (offs>0)
1069
                    {
1070
                        if (hitBackspaceOnSelection)
1071
                                offs--;
1072
                    }
1073
                    else
1074
                    {
1075
                        // User hit backspace with the cursor positioned on the start => beep
1076
                            if (useBeep)
1077
                                    comboBox.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
1078
                    }
1079
                    
1080
                    highlightCompletedText(offs);
1081
                }
1082
                else
1083
                {
1084
                    super.remove(offs, len);
1085
                }
1086
            }
1087

    
1088
                /*REVISAR
1089
                 *  (non-Javadoc)
1090
                 * @see javax.swing.text.Document#insertString(int, java.lang.String, javax.swing.text.AttributeSet)
1091
                 */
1092
            public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
1093
//                    super.insertString(offs, str, a);
1094
//                    System.out.println("INSERTSTRING: " + str);
1095
//                    model.setCurrentString(str);
1096
                                        
1097
             
1098
                if (comboBox.getSelectedIndex() > -1) // No s? si sobra o no
1099
                {
1100
                            // return immediately when selecting an item
1101
                        if (selecting) return;                        
1102
                        
1103
                        // Insert the string into the document
1104
                        super.insertString(offs, str, a);
1105
                        
1106
                
1107
                        // Lookup and select a matching item
1108
                        Object item = lookupItem(getText(0, getLength()));
1109
                        
1110
                        if (item != null)
1111
                        {
1112
                            setSelectedItem(item);
1113
//                            model.setCurrentString(getSelectedItem().toString());
1114
//                            lastSelectedIndex = getSelectedIndex();
1115
                        }
1116
                        else
1117
                        {
1118
                            // Keep old item selected if there is no match
1119
                            item = comboBox.getSelectedItem();
1120
                            
1121
                            // Imitate no insert (later on offs will be incremented by str.length(): selection won't move forward)
1122
                            offs = offs-str.length();
1123
                            
1124
                            // Provide feedback to the user that his input has been received but can not be accepted
1125
                            if (useBeep)
1126
                                    comboBox.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
1127
                        }
1128
                        
1129
                        // Set the complete item value matched
1130
                        if (completeMatchedItem)
1131
                                setText(item.toString());
1132
                        
1133
                        // Select the completed part
1134
                        highlightCompletedText(offs+str.length());
1135
                }
1136
            }
1137

    
1138
            /** ?Sobra?
1139
             * This method sets the string value of the item to the PlainDocument removing the previous value of the PlainDocument
1140
             * 
1141
             * @param text The string value of the item
1142
             */
1143
            private void setText(String text) {
1144
                try
1145
                {
1146
                    // remove all text and insert the completed string
1147
                    super.remove(0, super.getLength());
1148
                    super.insertString(0, text, null);
1149
                }
1150
                catch (BadLocationException e)
1151
                {
1152
                    throw new RuntimeException(e.toString());
1153
                }
1154
            }
1155

    
1156
            /**
1157
             * 
1158
             */
1159
            private Object lookupItem(String pattern) {
1160
                    
1161
                    // Reset the color to the default
1162
                    editor.getEditorComponent().setForeground(Color.BLACK);
1163
                    
1164
                Object selectedItem = model.getSelectedItem();
1165
                
1166
                // only search for a different item if the currently selected does not match
1167
                if ((selectedItem != null) && (startsWithIgnoreCase(selectedItem.toString(), pattern)))
1168
                {
1169
                    return selectedItem;
1170
                }
1171
                else
1172
                {
1173
                    // iterate over all items
1174
                    for (int i=0, n=model.getSize(); i < n; i++)
1175
                    {
1176
                        Object currentItem = model.getElementAt(i);
1177
                        
1178
                        // current item starts with the pattern?
1179
                        if ((currentItem != null) && (startsWithIgnoreCase(currentItem.toString(), pattern)))
1180
                        {
1181
                            return currentItem;
1182
                        }
1183
                    }
1184
                }                
1185
                  
1186
                // If no item starts with the pattern => return null and set the text written on red color if it's allowed                
1187
                if (!isOnlyOneColor())
1188
                        editor.getEditorComponent().setForeground(Color.RED);
1189
                
1190
                return null;
1191
            }
1192
            
1193

    
1194
            /**
1195
             * Checks if the starts of two strings agrees
1196
             */
1197
            private boolean startsWithIgnoreCase(String str1, String str2) {
1198
                    if (comboBox.isKeySensitive())
1199
                            return str1.startsWith(str2);
1200
                    else
1201
                            return str1.toUpperCase().startsWith(str2.toUpperCase());
1202
            }
1203
        }
1204
}