Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.ui / src / main / java / org / gvsig / gui / beans / comboboxconfigurablelookup / JComboBoxConfigurableLookUp.java @ 40561

History | View | Annotate | Download (55.4 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.gui.beans.comboboxconfigurablelookup;
25

    
26
import java.awt.Color;
27
import java.awt.event.FocusAdapter;
28
import java.awt.event.FocusEvent;
29
import java.awt.event.FocusListener;
30
import java.awt.event.KeyAdapter;
31
import java.awt.event.KeyEvent;
32
import java.awt.event.KeyListener;
33
import java.awt.event.MouseAdapter;
34
import java.awt.event.MouseEvent;
35
import java.awt.event.MouseListener;
36
import java.util.Vector;
37

    
38
import javax.accessibility.Accessible;
39
import javax.swing.ComboBoxEditor;
40
import javax.swing.ComboBoxModel;
41
import javax.swing.JButton;
42
import javax.swing.JComboBox;
43
import javax.swing.JList;
44
import javax.swing.MutableComboBoxModel;
45
import javax.swing.event.DocumentListener;
46
import javax.swing.event.PopupMenuEvent;
47
import javax.swing.event.PopupMenuListener;
48
import javax.swing.event.UndoableEditListener;
49
import javax.swing.plaf.ComponentUI;
50
import javax.swing.plaf.basic.BasicComboBoxUI;
51
import javax.swing.plaf.basic.BasicComboPopup;
52
import javax.swing.plaf.basic.ComboPopup;
53
import javax.swing.text.AttributeSet;
54
import javax.swing.text.BadLocationException;
55
import javax.swing.text.JTextComponent;
56
import javax.swing.text.PlainDocument;
57

    
58
import org.gvsig.gui.beans.editabletextcomponent.IEditableText;
59
import org.gvsig.gui.beans.editabletextcomponent.event.UndoRedoEditEvent;
60
import org.gvsig.gui.beans.editabletextcomponent.event.UndoRedoEditListener;
61

    
62

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

    
104

    
105
/** VERSION: BETA
106
 * <p>A configurable combo box component that lists items that carry out with the criterions of a <code>ILookUp</code> agent,
107
 *  considering the text in its inner editor.</p>
108
 * 
109
 * <p>Key features:
110
 *  <ul>
111
 *   <li>Allows configure it's behaviour.</li>
112
 *          <li>Inherits from JComboBox.</li>
113
 *          <li>Has 6 flags to configure its behaviour.</li>
114
 *          <li>It's made according the MVC (Model-View-Controller) pattern.</li>
115
 *          <li>Uses a {@link DefaultComboBoxConfigurableLookUpModel DefaultComboBoxConfigurableLookUpModel} as a dataModel, which it's also configurable.</li>
116
 *  </ul>
117
 * </p>
118
 * 
119
 * <p>Configuration flags:
120
 *  <ul>
121
 *   <li><b>OnlyOneColorOnText:</b> uses red if there is no item or only items that matches with the text written according the <code>ILookUp</code> agent, or uses always black color.</li>
122
 *   <li><b>BeepEnabled:</b> rings a beep sound if there is no item that matches with the text written according the <code>ILookUp</code> agent, or not.</li>
123
 *   <li><b>HidePopupIfThereAreNoItems:</b> hides popup (list box) if there is no item that matches with the text written according the <code>ILookUp</code> agent, or uses the default (JComboBox and more) behaviour.</li>
124
 *   <li><b>ToForceSelectAnItem:</b> forces to select an item (if the component looses the focus or user presses the Enter keyboard key), or uses the default (JComboBox and more) behaviour.</li>
125
 *   <li><b>CompleteArrowKeySelection:</b> writes in the editor the value of the element selected by the arrow keys (up or down) if its enabled, otherwise holds the previous text.</li>
126
 *   <li><b>DisplayAllItemsWithArrowButton:</b> <i>true</i>: displays all this component's dataModel items if its <i>popup</i> it's hided, and this component's dataModel listed only the matches
127
 *    <i>(flag: <code>DefaultComboBoxConfigurableLookUpModel.showAllItemsInListBox == false</code>)</i>; otherwise, if this flag isn't enabled,
128
 *    won't display all items in that situation.</li>
129
 *  </ul>
130
 * </p>
131
 * 
132
 * <p>Default flag values are:
133
 *  <ul>
134
 *   <li><b>OnlyOneColorOnText:</b> <i>false</i>.</li>
135
 *   <li><b>BeepEnabled:</b> <i>false</i>.</li>
136
 *   <li><b>HidePopupIfThereAreNoItems:</b> <i>true</i>.</li>
137
 *   <li><b>ToForceSelectAnItem:</b> <i>true</i>.</li>
138
 *   <li><b>CompleteArrowKeySelection:</b> <i>false</i>.</li>
139
 *   <li><b>DisplayAllItemsWithArrowButton:</b> <i>true</i>.</li>
140
 *  </ul>
141
 * </p>
142
 * 
143
 * <p><i>More information about the behaviour of it's dataModel in {@link DefaultComboBoxConfigurableLookUpModel DefaultComboBoxConfigurableLookUpModel} .</i></p>
144
 * 
145
 * @see JComboBox
146
 * @see DefaultComboBoxConfigurableLookUpModel
147
 * 
148
 * @author Pablo Piqueras Bartolom? (pablo.piqueras@iver.es)
149
 * @version 07/02/2008
150
 */
151
public class JComboBoxConfigurableLookUp extends JComboBox implements java.io.Serializable {
152

    
153

    
154
        // CONSTANTS FOR CONFIGURE THE BEHAVIOR
155
        public static final boolean DEFAULT_ONLY_ONE_COLOR_ON_TEXT_CONFIGURATION = false;
156
        public static final boolean DEFAULT_BEEP_ENABLED_CONFIGURATION = false;
157
        public static final boolean DEFAULT_HIDE_POPUP_IF_THERE_ARE_NO_ITEMS_CONFIGURATION = true;
158
        public static final boolean DEFAULT_TO_FORCE_SELECT_AN_ITEM_CONFIGURATION = true;
159
        public static final boolean DEFAULT_COMPLETE_ARROW_KEY_SELECTION_CONFIGURATION = false;
160
        public static final boolean DEFAULT_DISPLAY_ALL_ITEMS_WITH_ARROW_BUTTON_CONFIGURATION = true;
161
        // END CONSTANTS FOR CONFIGURE THE BEHAVIOR
162
        
163
        // EDITOR DOCUMENT REFERENCE
164
        /**
165
         * <p>A reference to the document of this component.</p> 
166
         */
167
        private PlainDocumentTextFormatter document;
168
        // END EDITOR DOCUMENT REFERENCE
169
        
170
        // NEW ATTRIBUTES 
171
        /**
172
         * <p>A reference to the dataModel of this component (according to the MVC <i>(Model-View-Controller)</i> pattern).</p>
173
         */
174
        private DefaultComboBoxConfigurableLookUpModel model;
175

    
176
        /**
177
         * <p>Has or not to hide the popup on focus loss.</p>
178
         */
179
        private boolean hidePopupOnFocusLoss;
180

    
181
        /**
182
         * <p>Has an item of the popup been selected or not by the user.</p>
183
         */
184
        private boolean popupItemSelected;
185
        
186
        /**
187
         * <p>Determines if an arrow key (meanwhile down or up) has been pressed.</p>
188
         */
189
        private boolean arrowKeyPressed;
190

    
191
        /**
192
         * <p>Determines if the arrow button of the GUI has been clicked.</p>
193
         */
194
        private boolean arrowButtonClicked;
195

    
196
        /**
197
         * <p>Determines if is showing all items temporally in the GUI .</p>
198
         */
199
        private boolean showingAllItemsTemporally;
200

    
201
        /**
202
         * <p>Flag to ensure the we don't get multiple ActionEvents on item selection.</p>
203
         */
204
        private boolean selectingItem = false;
205
        
206
        /**
207
         * <p>Last item selected.</p>
208
         */
209
        private Object previousSelected;
210

    
211
        /**
212
         * <p>Determines if the UI of this component has been updated.</p>
213
         * <p>This parameter is used by the listener that shows all items when user presses the <i>arrow button</i>
214
         *  and its enabled the flag <code>displayAllItemsWithArrowButton</code>.</p>
215
         */
216
        private boolean updatedUI = true;
217
        
218
        private boolean blockPopupHided = false;
219
        // END NEW ATTRIBUTES
220
        
221
        // LISTENERS
222
        /**
223
         * <p>Listener for the editor key.</p> 
224
         */
225
        private KeyListener editorKeyListener;
226
        
227
        /**
228
         * <p>Listener for the editor focus.</p>
229
         */
230
        private FocusListener editorFocusListener;
231
        
232
        /**
233
         * <p>Listener for the popup menu.</p> 
234
         */
235
        private PopupMenuListener popupMenuListener;
236
        
237
        /**
238
         * <p>Listener for the arrow button.</p>
239
         */
240
        private MouseListener arrowMouseListener;
241
        // END LISTENERS
242
        
243
        // CONFIGURATION FLAGS
244
        /**
245
         * <p>Flag: use red if there is no item that matches with the text written according the <code>ILookUp</code> agent, or uses always black colour.</p>
246
         */
247
        private boolean onlyOneColorOnText;
248
        
249
        /**
250
         * <p>Flag: rings a beep sound if there is no item that matches with the text written according the <code>ILookUp</code> agent, otherwise no.</p>
251
         */
252
        private boolean beepEnabled;
253
        
254
        /**
255
         * <p>Flag: hide popup (list box) if there is no item that matches with the text written according the <code>ILookUp</code> agent, or uses the default (JComboBox and more) behaviour.</p>
256
         */
257
        private boolean hidePopupIfThereAreNoItems;
258
        
259
        /**
260
         * <p>Flag: forces to select an item (if the component looses the focus or user presses the Enter keyboard key), or uses the default (JComboBox and more) behaviour.</p>
261
         */
262
        private boolean toForceSelectAnItem;
263

    
264
        /**
265
         * <p>Flag: determines if has to write in the editor the value of the element selected by the 
266
         * arrow keys (up or down) if its enabled, or hold the previous text if isn't.</p>
267
         */
268
        private boolean completeArrowKeySelection;
269
        
270
        /**
271
         * <p>Flag: displays all this component's dataModel items if its <i>popup</i> it's hided, this component's dataModel displayed only the matches, and this flag enabled; if this flag isn't enabled,
272
         *  won't display all items in that situation.</p>
273
         */
274
        private boolean displayAllItemsWithArrowButton;
275
        // END FLAGS
276
        
277
        /**
278
         * <p>Default constructor without parameters.</p>
279
         */
280
        public JComboBoxConfigurableLookUp() {
281
                super();
282
                initialize();
283
        }
284

    
285
        /**
286
         * <p>Default constructor with a {@link DefaultComboBoxConfigurableLookUpModel} as parameter.</p>
287
         * 
288
         * @param aModel javax.swing.ComboBoxModel
289
         */
290
        public JComboBoxConfigurableLookUp(DefaultComboBoxConfigurableLookUpModel aModel) {
291
                super(aModel);
292

    
293
                initialize();
294
        }        
295

    
296
        /**
297
         * <p>Default constructor with an array of objects as parameter.</p>
298
         * 
299
         * @param items An array of objects. All them must implement a <i>'String toStrin()'</i> method
300
         */
301
        public JComboBoxConfigurableLookUp(Object[] items) {
302
                super(items);
303

    
304
                initialize();
305
        }
306

    
307
        /**
308
         * <p>Default constructor with a Vector of objects as parameter.</p>
309
         * 
310
         * @param items A {@link Vector} of objects. All them must implement a <i>'String toStrin()'</i> method
311
         */
312
        public JComboBoxConfigurableLookUp(Vector<Object> items) {
313
                super(items);
314

    
315
                initialize();
316
        }
317
        
318
        ///// NEW METHODS /////
319
        
320
        /**
321
         * <p>This method sets the start values of inner attributes and creates the necessary inner objects.</p>
322
         * 
323
         * @param dataModel dataModel used by this combo box instance
324
         */
325
        protected void initialize() {
326
                // By default user hasn't selected an item of the popup
327
                popupItemSelected = false;
328
                
329
                // By default no arrow key has been pressed
330
                arrowKeyPressed = false;
331
                
332
                // By default the arrow button of the GUI hasn't been clicked
333
                arrowButtonClicked = false;
334
                
335
                // By default isn't showing all items temporally in the GUI
336
                showingAllItemsTemporally = false;
337
                
338
                // By default no item has been selected
339
                previousSelected = null;
340

    
341
                // Set default flags configuration
342
                this.setDefaultBehaviorFlagsConfiguration();
343

    
344
                // Allows user to edit on the combobox
345
                super.setEditable(true);
346
                                
347
                // Other configuration tasks
348
                configure();
349

    
350
                // If there are items -> select the first
351
                if ((toForceSelectAnItem) && (model.getData().size() > 0)) {
352
                        model.setSelectedItem(model.getData().elementAt(0));
353
                }
354

    
355
                // Resets the UI property to a value from the current look and feel
356
                updateUI();
357
        }
358
        
359
        /**
360
         * <p>Configures the component and some of its elements.</p>
361
         */
362
        protected void configure() {
363
                // Defines a key listener for the editor of this component
364
                defineEditorKeyListener(this);
365

    
366
                // Defines a focus listener for the editor of this component
367
                defineEditorFocusListener(this);
368
                                
369
                // Configures the document of the editor of this component
370
                configureDocument();
371
                
372
                // Configures the editor (ComboBoxEditor) of this component
373
                configureEditor(this.getEditor());
374
                
375
                // Configures the popup of this component
376
                configurePopUp(this);
377
        }
378
        
379
        /**
380
         * <p>Configures the editor ( {@link ComboBoxEditor} ) of this component.</p>
381
         * 
382
         * @param newEditor The new editor to configure
383
         */
384
        protected void configureEditor(ComboBoxEditor newEditor) {
385
                if (newEditor != null) {
386
                        JTextComponent jTextComponentOfEditor = (JTextComponent) newEditor.getEditorComponent();
387

    
388
                        // Adds the new document (tries to remove it if it existed before)
389
                        jTextComponentOfEditor.setDocument(this.document);
390

    
391
                        // Adds the new Key Listener (tries to remove it if it existed before)
392
                        jTextComponentOfEditor.removeKeyListener(this.editorKeyListener);
393
                        jTextComponentOfEditor.addKeyListener(this.editorKeyListener);
394

    
395
                        // Adds the new Focus Listener (tries to remove it if it existed before)
396
                        jTextComponentOfEditor.removeFocusListener(this.editorFocusListener);
397
                        jTextComponentOfEditor.addFocusListener(this.editorFocusListener);
398
                }
399
        }
400

    
401
        /**
402
         * <p>Configures the document of the editor of this component.</p>
403
         */
404
        protected void configureDocument() {
405
                // Creates the document of the editor of this component
406
                document = new PlainDocumentTextFormatter();
407

    
408
                // Set reference to the container component
409
                document.setJComboBoxReference(this);
410
        }
411

    
412
        /**
413
         * <p>Configures the popup of this component.</p>
414
         *
415
         * @param comboBox A reference of this component
416
         */
417
        protected void configurePopUp(JComboBoxConfigurableLookUp comboBox) {
418
                final JComboBoxConfigurableLookUp comboBoxReference = comboBox;
419
                this.addPopupMenuListener(this.popupMenuListener);
420
                                
421
                BasicComboBoxUI comboBoxUi = (BasicComboBoxUI)comboBoxReference.getUI();
422
                Accessible aC = comboBoxUi.getAccessibleChild(comboBoxReference, 0);
423

    
424
                if (aC instanceof ComboPopup) {
425
                        JList jlist = ((ComboPopup)aC).getList();
426

    
427
                        jlist.addMouseListener(new MouseAdapter() {
428
                                /*
429
                                 *  (non-Javadoc)
430
                                 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
431
                                 */
432
                                public void mousePressed(MouseEvent e) {
433
                                        // User selects an item of the popup using the mouse
434
                                        popupItemSelected = true;
435
                                        System.out.println("Pulsado");
436
                                }
437
                        });
438
                                
439
                        if (aC instanceof BasicComboPopup) {
440
                                ((BasicComboPopup)aC).addPopupMenuListener(new PopupMenuListener() {
441
                                        /*
442
                                         * (non-Javadoc)
443
                                         * @see javax.swing.event.PopupMenuListener#popupMenuCanceled(javax.swing.event.PopupMenuEvent)
444
                                         */
445
                                        public void popupMenuCanceled(PopupMenuEvent e) {
446
                                                if (arrowButtonClicked) {
447
                                                        arrowButtonClicked = false;
448
                                                }
449
                                        }
450

    
451
                                        /*
452
                                         * (non-Javadoc)
453
                                         * @see javax.swing.event.PopupMenuListener#popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent)
454
                                         */
455
                                        public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
456
                                                if (arrowButtonClicked) {
457
                                                        arrowButtonClicked = false;
458
                                                }
459
                                        }
460

    
461
                                        /*
462
                                         * (non-Javadoc)
463
                                         * @see javax.swing.event.PopupMenuListener#popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent)
464
                                         */
465
                                        public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
466
                                                if (arrowButtonClicked) {
467
                                                        arrowButtonClicked = false;
468
                                                }
469
                                        }
470
                                });
471
                        }
472
                }
473
        }
474

    
475
        /**
476
         * <p>Returns the listener invoked when user presses the arrow button of this <code>JComboBox</code>.</p>
477
         * 
478
         * @return java.awt.event.MouseListener
479
         */
480
        public MouseListener getArrowMouseListener() {
481
                if (arrowMouseListener == null) {
482
                        // New mouse listener
483
                        arrowMouseListener = new MouseAdapter() {
484
                                /*
485
                                 * (non-Javadoc)
486
                                 * @see java.awt.event.MouseAdapter#mousePressed(java.awt.event.MouseEvent)
487
                                 */
488
                                public void mousePressed(MouseEvent e) {
489
                                        arrowButtonClicked = true;
490
                                        
491
                                        // Avoids a bug: when the component is created an shown, first time the arrow button is pressed, the method
492
                                        // #isPopupVisible() returns 'true' instead of returning 'false'
493
                                        boolean popupVisible;
494
                                        
495
                                        if (updatedUI) {
496
                                                popupVisible = false;
497
                                        }
498
                                        else {
499
                                                popupVisible = isPopupVisible();
500
                                        }
501
                
502
                                        // Shows all items temporally in the GUI
503
                                        if ((! model.isShowAllItemsInListBox()) && (displayAllItemsWithArrowButton) && (! popupVisible)) {
504
                                                showingAllItemsTemporally = true;
505
                                                
506
                                                // Stores the configuration of the flags                                
507
                                                int itemsOrderFlag = model.getItemsOrder();
508
                                                String languageRules = model.getLocaleRules();
509
                                                boolean caseSensitive = model.isCaseSensitive();
510
                                                ILookUp lookUpAgent = model.getLookUpAgent();
511
                                                
512
                                                // Must replace the dataModel for update the data in the popup correctly
513
                                                setModel(new DefaultComboBoxConfigurableLookUpModel(model.getData()));
514
                                                
515
                                                // Restores the configuration of the flags
516
                                                model.setItemsOrder(itemsOrderFlag);
517
                                                model.setShowAllItemsInListBox(true);
518
                                                model.setLocaleRules(languageRules);
519
                                                model.setCaseSensitive(caseSensitive);
520
                                                model.setLookUpAgent(lookUpAgent);
521
                
522
                                                model.setTextWritten(document.textWritten);
523
                                                
524
                                                if (updatedUI) {
525
                                                        updatedUI = false;
526
                                                        showPopup();
527
                                                }
528
                                        }
529
                                }
530
                        };
531
                }
532
                
533
                return arrowMouseListener;
534
        }
535
        
536
        /**
537
         * <p>Sets the default values of the flags.</p>
538
         */
539
        protected void setDefaultBehaviorFlagsConfiguration() {
540
                onlyOneColorOnText = DEFAULT_ONLY_ONE_COLOR_ON_TEXT_CONFIGURATION;
541
                beepEnabled = DEFAULT_BEEP_ENABLED_CONFIGURATION;
542
                hidePopupIfThereAreNoItems = DEFAULT_HIDE_POPUP_IF_THERE_ARE_NO_ITEMS_CONFIGURATION;
543
                toForceSelectAnItem = DEFAULT_TO_FORCE_SELECT_AN_ITEM_CONFIGURATION;
544
                completeArrowKeySelection = DEFAULT_COMPLETE_ARROW_KEY_SELECTION_CONFIGURATION;
545
                displayAllItemsWithArrowButton = DEFAULT_DISPLAY_ALL_ITEMS_WITH_ARROW_BUTTON_CONFIGURATION;
546
        }
547
        
548
        /**
549
         * <p>Defines a key listener for the editor of this component.</p>
550
         * 
551
         * <p><b>Warning:</b><i>This method is another important difference from the JComboBox; and could work badly with some key-maps.</i></p>
552
         * 
553
         * @param comboBox A reference of this component
554
         */
555
        private void defineEditorKeyListener(JComboBoxConfigurableLookUp comboBox) {
556
                final JComboBoxConfigurableLookUp comboBoxReference = comboBox;
557
                
558
                editorKeyListener = new KeyAdapter() {
559
                        /*
560
                         * (non-Javadoc)
561
                         * @see java.awt.event.KeyAdapter#keyPressed(java.awt.event.KeyEvent)
562
                         */
563
                        public void keyPressed(KeyEvent ke)  // Executed on the Start view state or Search view state
564
                        {
565
                                // Restore the status if was showing all items temporally
566
                                if (showingAllItemsTemporally) {
567
                                        showingAllItemsTemporally = false;
568
                                        
569
                                        // Stores the configuration of the flags                                
570
                                        int itemsOrderFlag = model.getItemsOrder();
571
                                        String languageRules = model.getLocaleRules();
572
                                        boolean caseSensitive = model.isCaseSensitive();
573
                                        ILookUp lookUpAgent = model.getLookUpAgent();
574
                                        
575
                                        // Must replace the dataModel for update the data in the popup correctly
576
                                        comboBoxReference.setModel(new DefaultComboBoxConfigurableLookUpModel(model.getData()));
577
                                        
578
                                        // Restores the configuration of the flags
579
                                        model.setItemsOrder(itemsOrderFlag);
580
                                        model.setShowAllItemsInListBox(false);
581
                                        model.setLocaleRules(languageRules);
582
                                        model.setCaseSensitive(caseSensitive);
583
                                        model.setLookUpAgent(lookUpAgent);
584
                                        model.setTextWritten(document.textWritten);
585
                                }
586
                                
587
                                // According the key pressed, do some actions or others
588
                                switch (ke.getKeyCode())
589
                                {
590
                                        case KeyEvent.VK_ENTER :
591
                                                // Don't allow execute the default instructions because they have a bug (first time we remove some characters, no item will be displayed in the popup)
592
                                                ke.consume();
593

    
594
                                                // Sets the caret position of the text in the document to the end:
595
                                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(document.getLength());
596

    
597
                                                final DefaultComboBoxConfigurableLookUpModel c_model = (DefaultComboBoxConfigurableLookUpModel)comboBoxReference.getModel();
598
                                                
599
                                                if (toForceSelectAnItem) {
600
                                                        if (c_model.isShowAllItemsInListBox()) {
601
                                                                // Select now the first item or the previous selected
602
                                                                if (c_model.getSelectedItem() == null) {
603
                                                                        if (c_model.getData().size() > 0) {
604
                                                                                if (previousSelected == null)
605
                                                                                        previousSelected = c_model.getDataAccordingItemsOrder().elementAt(0);
606
                                                                                else {
607
                                                                                        ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
608
                                                                                }
609
                                                                        }
610
                                                                        else {
611
                                                                                previousSelected = null;
612
                                                                        }
613
                                                                }
614
                                                                else {                                                                
615
                                                                        previousSelected = c_model.getSelectedItem();                                                                        
616
                                                                        comboBoxReference.setSelectedItem(previousSelected);
617
                                                                        
618
                                                                        ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
619
                                                                }
620
                                                        }
621
                                                        else {
622
                                                                // Select now the first item or the previous selected
623
                                                                switch (comboBoxReference.getModel().getSize()) {
624
                                                                        case 0:
625
                                                                                if (previousSelected == null) {
626
                                                                                        if (c_model.getData().size() > 0) {
627
                                                                                                previousSelected = c_model.getDataAccordingItemsOrder().elementAt(0);
628
                                                                                        }
629
                                                                                        else {
630
                                                                                                previousSelected = null;
631
                                                                                        }
632
                                                                                }
633
                                                                                
634
                                                                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
635
                                                                                break;
636
                                                                        case 1:
637
                                                                                // If there is only one item -> select it
638
                                                                                previousSelected = comboBoxReference.getItemAt(0); // Select the first
639
                                                                                comboBoxReference.setSelectedIndex(0);
640
                                                                                break;
641
                                                                        default:
642
                                                                                if (previousSelected == null) {
643
                                                                                        previousSelected = comboBoxReference.getItemAt(0); // Select the first
644
                                                                                        comboBoxReference.setSelectedIndex(0);
645
                                                                                }
646
                                                                                else
647
                                                                                        ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
648
                                                                }
649
                                                        }
650
                                                }                                                
651
                                                
652
                                                // Hide the popup
653
                                                comboBoxReference.hidePopup();
654
                                                
655
                                                // Force select one item
656
                                                if (completeArrowKeySelection) {
657
                                                        model.setTextWritten(document.textWritten);
658
                                                }
659
                                                break;
660
                                                
661
                                        case KeyEvent.VK_UP: case KeyEvent.VK_DOWN:
662
                                                // User selects an item of the popup using the mouse
663
                                                popupItemSelected = true;
664
                                                arrowKeyPressed = true;
665
                                                break;
666
                                }
667
                        }
668
                };
669
        }
670
        
671
        /**
672
         * <p>Defines a focus listener for the editor of this component.</p>
673
         * 
674
         * @param comboBox A reference of this component
675
         */
676
        private void defineEditorFocusListener(JComboBoxConfigurableLookUp comboBox) {
677
                final JComboBoxConfigurableLookUp comboBoxReference = comboBox;
678
                
679
                // Bug 5100422 on Java 1.5: Editable JComboBox won't hide popup when tabbing out                
680
                hidePopupOnFocusLoss = System.getProperty("java.version").startsWith("1.5");
681
                
682
                // Highlight whole text when gaining focus
683
                editorFocusListener = new FocusAdapter() {
684
                        /*
685
                         *  (non-Javadoc)
686
                         * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
687
                         */
688
                        public void focusLost(FocusEvent e) {
689
                                // Restore the status if was showing all items temporally
690
                                if (showingAllItemsTemporally) {
691
                                        showingAllItemsTemporally = false;
692
                                        
693
                                        // Stores the configuration of the flags                                
694
                                        int itemsOrderFlag = model.getItemsOrder();
695
                                        String languageRules = model.getLocaleRules();
696
                                        boolean caseSensitive = model.isCaseSensitive();
697
                                        ILookUp lookUpAgent = model.getLookUpAgent();
698
                                        
699
                                        // Must replace the dataModel for update the data in the popup correctly
700
                                        comboBoxReference.setModel(new DefaultComboBoxConfigurableLookUpModel(model.getData()));
701
                                        
702
                                        // Restores the configuration of the flags
703
                                        model.setItemsOrder(itemsOrderFlag);
704
                                        model.setShowAllItemsInListBox(false);
705
                                        model.setLocaleRules(languageRules);
706
                                        model.setCaseSensitive(caseSensitive);
707
                                        model.setLookUpAgent(lookUpAgent);
708
                                        model.setTextWritten(document.textWritten);
709
                                }
710
                                
711
                                
712
                                // Sets the caret position of the text in the document to the end:
713
                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(document.getLength());
714

    
715
                                final DefaultComboBoxConfigurableLookUpModel c_model = (DefaultComboBoxConfigurableLookUpModel)comboBoxReference.getModel();
716

    
717
                                if (toForceSelectAnItem) {
718
                                        if (c_model.isShowAllItemsInListBox()) {
719
                                                // Select now the first item or the previous selected
720
                                                if (c_model.getSelectedItem() == null) {
721
                                                        if (c_model.getData().size() > 0) {
722
                                                                if (previousSelected == null)
723
                                                                        previousSelected = c_model.getDataAccordingItemsOrder().elementAt(0);
724
                                                                else {
725
                                                                        ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
726
                                                                }
727
                                                        }
728
                                                        else {
729
                                                                previousSelected = null;
730
                                                        }
731
                                                }
732
                                                else {                                                                
733
                                                        previousSelected = c_model.getSelectedItem();                                                                        
734
                                                        comboBoxReference.setSelectedItem(previousSelected);
735
                                                }
736

    
737
                                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
738
                                        }
739
                                        else {
740
                                                // Select now the first item or the previous selected
741
                                                switch (model.getData().size()) {
742
                                                        case 0:
743
                                                                if (previousSelected == null) {
744
                                                                        if (c_model.getData().size() > 0) {
745
                                                                                previousSelected = c_model.getDataAccordingItemsOrder().elementAt(0);
746

    
747
                                                                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
748
                                                                        }
749
                                                                        else {
750
                                                                                previousSelected = null;
751
                                                                        }
752
                                                                }
753
                                                                break;
754
                                                        default:
755
                                                                if (previousSelected == null) {
756
                                                                        previousSelected = comboBoxReference.getItemAt(0); // Select the first
757
                                                                        comboBoxReference.setSelectedIndex(0);
758
                                                                }
759
                                                                else
760
                                                                        ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
761
                                                }
762
                                        }
763
                                }
764

    
765
                                comboBoxReference.hidePopup();
766

    
767
                                // Workaround for Bug 5100422 - Hide Popup on focus loss
768
                                if (hidePopupOnFocusLoss)
769
                                        comboBoxReference.setPopupVisible(false);
770
                        }                        
771
                };
772
        }
773
        
774
        ///// END NEW METHODS /////
775
        
776
        ///// REIMPLEMENTATION OF METHODS OF 'JComboBox' /////
777
        
778
        /**
779
         * <p>Sets the editor used to paint and edit the selected item in the 
780
     * <code>JComboBox</code> field.  The editor is used only if the
781
     * receiving <code>JComboBox</code> is editable. If not editable,
782
     * the combo box uses the renderer to paint the selected item.</p>
783
     * 
784
     * <p>The editor must be a <code>JTextComponent</code>, and its document a <code>PlainDocument</code> object.</p>
785
     *  
786
     * @param anEditor  the <code>ComboBoxEditor</code> that
787
     *                        displays the selected item
788
     * @see #setRenderer
789
     * @beaninfo
790
     *     bound: true
791
     *    expert: true
792
     *  description: The editor that combo box uses to edit the current value
793
         */
794
        public void setEditor(ComboBoxEditor anEditor) {
795
                if (anEditor == null) {
796
                        super.setEditor(anEditor);
797
                        return;
798
                }
799
                
800
                JTextComponent jTextComponentOfEditor = (JTextComponent) anEditor.getEditorComponent();
801

    
802
                // Adds the new ''PlainDocumentTextFormatter'', adding the listeners of the new editor's document
803
                PlainDocument old_document = ((PlainDocument)jTextComponentOfEditor.getDocument());
804
                
805
                DocumentListener[] documentListeners = old_document.getDocumentListeners();
806
                UndoableEditListener[] undoableEditListeners = old_document.getUndoableEditListeners();
807
                
808
                // Defines a key listener for the editor of this component
809
                defineEditorKeyListener(this);
810
                jTextComponentOfEditor.addKeyListener(editorKeyListener);
811
                
812
                // Defines a focus listener for the editor of this component
813
                defineEditorFocusListener(this);
814
                jTextComponentOfEditor.addFocusListener(editorFocusListener);
815
                
816
                document = new PlainDocumentTextFormatter();
817
                                
818
                // Set reference to the container component
819
                document.setJComboBoxReference(this);
820
                        
821
                // Removes all previous 'document' and 'undoableEdit' listeners
822
                DocumentListener[] removableDocumentListeners = document.getDocumentListeners();
823
                for (DocumentListener dL : removableDocumentListeners)
824
                        document.removeDocumentListener(dL);
825

    
826
                UndoableEditListener[] removableUndoableEditListeners = document.getUndoableEditListeners();
827
                for (UndoableEditListener dUEL : removableUndoableEditListeners)
828
                        document.removeUndoableEditListener(dUEL);
829

    
830
                for (DocumentListener rdL : documentListeners)
831
                        document.addDocumentListener(rdL);
832
                
833
                // The undo-redo listeners fail
834
                for (UndoableEditListener uEL : undoableEditListeners) 
835
                        document.addUndoableEditListener(uEL);
836
                
837
                if (undoableEditListeners.length > 0) {
838
                        if (jTextComponentOfEditor instanceof IEditableText) {
839
                                ((IEditableText)jTextComponentOfEditor).addUndoRedoEditListener(new UndoRedoEditListener() {
840
                                        /*
841
                                         * (non-Javadoc)
842
                                         * @see org.gvsig.gui.beans.editabletextcomponent.event.UndoRedoEditListener#operationExecuted(org.gvsig.gui.beans.editabletextcomponent.event.UndoRedoEditEvent)
843
                                         */
844
                                        public void operationExecuted(UndoRedoEditEvent e) {
845
                                                model.setTextWritten(e.getNewText());
846
                                                document.updateOnlyTextColor();
847
                                        }
848
                                });
849
                        }
850
                }
851

    
852
                jTextComponentOfEditor.setDocument(document);
853
                
854
                super.setEditor(anEditor);
855
        }
856

    
857
        /*
858
         *  (non-Javadoc)
859
         * @see javax.swing.JComboBox#setModel(javax.swing.ComboBoxModel)
860
         */
861
        public void setModel(ComboBoxModel aModel) {
862
                // If model isn't DefaultComboBoxConfigurableLookUpModel, sets as model a new DefaultComboBoxConfigurableLookUpModel, with the data
863
                //  of ''aModel'':
864
                if (! (aModel instanceof DefaultComboBoxConfigurableLookUpModel) ) {
865
                        Vector<Object> data = new Vector<Object>(aModel.getSize());
866
                        
867
                        for (int i = 0; i < aModel.getSize(); i++) {
868
                                data.add(aModel.getElementAt(i));
869
                        }
870
                        
871
                        aModel = new DefaultComboBoxConfigurableLookUpModel(data);
872
                }
873
                
874
                super.setModel(aModel);
875
                
876
                model = (DefaultComboBoxConfigurableLookUpModel)super.getModel();
877
        }
878
        
879
        /*
880
         *  (non-Javadoc)
881
         * @see javax.swing.JComboBox#setSelectedIndex(int)
882
         */
883
        public void setSelectedIndex(int anIndex) {
884
                if (anIndex < -1 || anIndex >= model.getSize())
885
                        // Fails because index is out of bounds.
886
                        throw new IllegalArgumentException("setSelectedIndex: " + anIndex + " out of bounds");
887
                else
888
                        // Selects the item at the given index or clears the selection if the
889
                        // index value is -1.
890
                        setSelectedItem((anIndex == -1) ? null : model.getElementAt(anIndex));
891
        }
892
        
893
        /*
894
         *  (non-Javadoc)
895
         * @see javax.swing.JComboBox#setSelectedItem(java.lang.Object)
896
         */
897
        public void setSelectedItem(Object anObject) {                
898
                if ((selectedItemReminder == null) || (!selectedItemReminder.equals(anObject))) {
899
                        if (arrowKeyPressed) {
900
                                
901
                                selectingItem = true;
902
                                model.setSelectedItem(anObject);
903
                                selectingItem = false;
904
                                
905
                                if (model.getSize() > 0)
906
                                        previousSelected = anObject;
907
                        }
908
                        else {
909
                                selectingItem = true;
910
                                model.setSelectedItem(anObject);
911
                                selectingItem = false;
912
                                
913
                                editor.setItem(anObject);
914
                                
915
                                if (model.getSize() > 0)
916
                                        previousSelected = anObject;
917
                        }
918
                        
919
                        if (selectedItemReminder != model.getSelectedItem()) {
920
                                // In case a users implementation of ComboBoxModel
921
                                // doesn't fire a ListDataEvent when the selection
922
                                // changes.
923
                                selectedItemChanged();
924
                        }
925
                }                        
926
                fireActionEvent();
927
                document.updateOnlyTextColor();
928
        }
929

    
930
        /*
931
         * <p>Unsupported operation. A <code>JComboBoxConfigurableLookUp</code> is always editable.</p>
932
         *
933
         * (non-Javadoc)
934
         * @see javax.swing.JComboBox#setEditable(boolean)
935
         */
936
        public void setEditable(boolean b) {
937
                throw new UnsupportedOperationException();
938
        }
939
        
940
        /*
941
         * (non-Javadoc)
942
         * @see javax.swing.JComboBox#removeAllItems()
943
         */
944
        public void removeAllItems() {
945
                if ( !(model instanceof MutableComboBoxModel) )
946
                        throw new RuntimeException("Cannot use this method with a non-Mutable data dataModel.");
947

    
948
                //if ( model instanceof DefaultComboBoxConfigurableLookUpModel ) {
949
                model.setTextWritten("");
950
                ((DefaultComboBoxConfigurableLookUpModel)model).removeAllElements();
951

    
952
                selectedItemReminder = null;
953

    
954
                if (isEditable()) {
955
                        editor.setItem(null);
956
                }
957
                
958
                document.updateTextColorAndRingBeep();
959
        }
960
        
961
        public void addItem(Object anObject) {
962
                super.addItem(anObject);
963

    
964
                if ((toForceSelectAnItem) && (getSelectedIndex() == -1))
965
                        setSelectedIndex(0);
966
                
967
                document.updateTextColorAndRingBeep();
968
        }
969

    
970
        /*
971
         * (non-Javadoc)
972
         * @see javax.swing.JComboBox#removeItem(java.lang.Object)
973
         */
974
        public void removeItem(Object anObject) {
975
                super.removeItem(anObject);
976
                
977
                document.updateTextColorAndRingBeep();
978
        }
979

    
980
        /*
981
         * (non-Javadoc)
982
         * @see javax.swing.JComboBox#removeItemAt(int)
983
         */
984
        public void removeItemAt(int anIndex) {
985
                super.removeItemAt(anIndex);
986
                
987
                document.updateTextColorAndRingBeep();
988
        }
989

    
990
        /*
991
         * (non-Javadoc)
992
         * @see javax.swing.JComponent#setUI(javax.swing.plaf.ComponentUI)
993
         */
994
        protected void setUI(ComponentUI newUI) {
995
                super.setUI(newUI);
996
                ComponentUI oldUI = newUI;
997
                
998
                // Remove the default key selection manager
999
                super.setKeySelectionManager(null);
1000
                
1001
        firePropertyChange("UI", oldUI, newUI);
1002
        revalidate();
1003
        repaint();
1004
        }
1005

    
1006
        /*
1007
         * <p>Unsupported operation.</p>
1008
         * 
1009
         * (non-Javadoc)
1010
         * @see javax.swing.JComboBox#selectWithKeyChar(char)
1011
         */
1012
        public boolean selectWithKeyChar(char keyChar) {
1013
                throw new UnsupportedOperationException();
1014
        }
1015

    
1016
        /*
1017
         * <p>Unsupported operation.</p>
1018
         * 
1019
         * (non-Javadoc)
1020
         * @see javax.swing.JComboBox#processKeyEvent(java.awt.event.KeyEvent)
1021
         */
1022
        public void processKeyEvent(KeyEvent e) {
1023
                throw new UnsupportedOperationException();
1024
        }
1025

    
1026
        /*
1027
         * <p>Unsupported operation.</p>
1028
         * 
1029
         * (non-Javadoc)
1030
         * @see javax.swing.JComboBox#createDefaultKeySelectionManager()
1031
         */
1032
        protected KeySelectionManager createDefaultKeySelectionManager() {
1033
                throw new UnsupportedOperationException();
1034
        }
1035

    
1036
        /*
1037
         * (non-Javadoc)
1038
         * @see javax.swing.JComboBox#paramString()
1039
         */
1040
        protected String paramString() {
1041
                return super.paramString() +
1042
                  "onlyOneColorOnText" + onlyOneColorOnText +
1043
                  "beepEnabled" + beepEnabled +
1044
                  "hidePopupIfThereAreNoItems" + hidePopupIfThereAreNoItems +
1045
                  "toForceSelectAnItem" + toForceSelectAnItem +
1046
                  "completeArrowKeySelection" + completeArrowKeySelection +
1047
                  "displayAllItemsWithArrowButton" + displayAllItemsWithArrowButton +
1048
                  "itemsOrder" + model.getItemsOrder() +
1049
                  "showAllItemsInListBox" + model.isShowAllItemsInListBox() +
1050
                  "localeRules" + model.getLocaleRules() +
1051
                  "caseSensitive" + model.isCaseSensitive();
1052
        }
1053

    
1054
        /*
1055
         * (non-Javadoc)
1056
         * @see javax.swing.JComboBox#updateUI()
1057
         */
1058
        public void updateUI() {
1059
                super.updateUI();
1060
                
1061
                // Force to hide the popup
1062
                updatedUI = true;
1063

    
1064
                for (int i = 0; i < getComponentCount(); i++) {
1065
                        if (getComponent(i) instanceof JButton) {
1066
                                ((JButton)getComponent(i)).addMouseListener(getArrowMouseListener());
1067
                                return;
1068
                        }
1069
                }
1070
        }
1071
        
1072
        /*
1073
         * (non-Javadoc)
1074
         * @see javax.swing.JComboBox#showPopup()
1075
         */
1076
        public void showPopup() {
1077
                if (this.isShowing() && (!blockPopupHided))
1078
                        setPopupVisible(true);
1079
        }
1080

    
1081
        /**
1082
         * <p>Sets if the popup of this component will always remain hided, or can be shown when is invoked.</p>
1083
         * 
1084
         * @param b <code>true</code> if will remain blocked; <code>false</code> if can be shown 
1085
         */
1086
        public void setBlockPopupHided(boolean b) {
1087
                blockPopupHided = b;
1088
        }
1089
        
1090

    
1091
        /**
1092
         * <p>Determines if the popup of this component will always remain hided.</p>
1093
         * 
1094
         * @param b <code>true</code> if will remain blocked; <code>false</code> if can be shown 
1095
         */
1096
        public boolean isBlockPopupHided() {
1097
                return blockPopupHided;
1098
        }
1099
        ///// END REIMPLEMENTATION OF METHODS OF 'JComboBox' /////    
1100
        
1101
        ////// METHODS FOR THE BEHAVIOR FLAGS  //////
1102
        /**
1103
         * <p>Returns the 'only_One_Color_On_Text' configuration value of this component. Configuration values are:
1104
         *  <ul>
1105
         *   <li><i>true</i>: always uses black colour on text.</li>
1106
         *   <li><i>false</i>: by default uses black colour on text, but if text written by user doesn't match with any item according the <code>ILookUp</code> agent, text will be on red colour.</li>
1107
         *  </ul>
1108
         * </p>
1109
         * 
1110
         * @return 'only_One_Color_On_Text' configuration
1111
         */
1112
        public boolean isOnlyOneColorOnText() {
1113
                return onlyOneColorOnText;
1114
        }
1115
        
1116
        /**
1117
         * <p>Sets the 'only_One_Color_On_Text' configuration value for this component. Configuration values are:
1118
         *  <ul>
1119
         *   <li><i>true</i>: always uses black colour on text.</li>
1120
         *   <li><i>false</i>: by default uses black colour on text, but if text written by user doesn't match with any item according the <code>ILookUp</code> agent, text will be on red colour.</li>
1121
         *  </ul>
1122
         * </p>
1123
         * 
1124
         * @param b value for 'only_One_Color_On_Text' configuration flag
1125
         */
1126
        public void setOnlyOneColorOnText(boolean b) {
1127
                onlyOneColorOnText = b;
1128
        }
1129

    
1130
        /**
1131
         * <p>Returns the 'beep_Enabled' configuration value of this component. Configuration values are:
1132
         *  <ul>
1133
         *   <li><i>true</i>: a beep-sound is listened when no item matches with the text written according the <code>ILookUp</code> agent.</li>
1134
         *   <li><i>false</i>: no sound is listened.</li>
1135
         *  </ul>
1136
         * </p>
1137
         * 
1138
         * @return 'beep_Enabled' configuration
1139
         */
1140
        public boolean isBeepEnabled() {
1141
                return beepEnabled;
1142
        }
1143
        
1144
        /**
1145
         * <p>Sets the 'beep_Enabled' configuration value for this component. Configuration values are:
1146
         *  <ul>
1147
         *   <li><i>true</i>: a beep-sound is listened when no item matches with the text written according the <code>ILookUp</code> agent.</li>
1148
         *   <li><i>false</i>: no sound is listened.</li>
1149
         *  </ul>
1150
         * </p>
1151
         * 
1152
         * @param b value for 'beep_Enabled' configuration flag
1153
         */
1154
        public void setBeepEnabled(boolean b) {
1155
                beepEnabled = b;
1156
        }        
1157

    
1158
        /**
1159
         * <p>Returns the 'hidePopupIfThereAreNoItems' configuration value of this component. Configuration values are:
1160
         *  <ul>
1161
         *   <li><i>true</i>: hides the popup if there are no items when you write.</li>
1162
         *   <li><i>false</i>: default behaviour (if there are no items when you write, popup remains visible) .</li>
1163
         *  <ul>
1164
         * </p>
1165
         * 
1166
         * @return 'hidePopupIfThereAreNoItems' configuration
1167
         */
1168
        public boolean isHidePopupIfThereAreNoItems() {
1169
                return hidePopupIfThereAreNoItems;
1170
        }
1171
        
1172
        /**
1173
         * <p>Sets the 'hidePopupIfThereAreNoItems' configuration value for this component. Configuration values are:
1174
         *  <ul>
1175
         *   <li><i>true</i>: hides the popup if there are no items when you write.</li>
1176
         *   <li><i>false</i>: default behaviour (if there are no items when you write, popup remains visible) .</li>
1177
         *  <ul>
1178
         * </p>
1179
         * 
1180
         * @param b value for 'hidePopupIfThereAreNoItems' configuration flag
1181
         */
1182
        public void setHidePopupIfThereAreNoItems(boolean b) {
1183
                hidePopupIfThereAreNoItems = b;
1184
        }
1185

    
1186
        /**
1187
         * <p>Returns the 'toForceSelectAnItem' configuration value of this component. Configuration values are:
1188
         *  <ul>
1189
         *   <li><i>true</i>: selects the previous selected item or the first of the list when user presses the Enter key or when the component loses the focus .</li>
1190
         *   <li><i>false</i>: default behaviour .</li>
1191
         *  </ul>
1192
         * </p>
1193
         * 
1194
         * @return 'toForceSelectAnItem' configuration
1195
         */
1196
        public boolean isToForceSelectAnItem() {
1197
                return toForceSelectAnItem;
1198
        }
1199
        
1200
        /**
1201
         * <p>Sets the 'toForceSelectAnItem' configuration value for this component. Configuration values are:
1202
         *  <ul>
1203
         *   <li><i>true</i>: selects the previous selected item or the first of the list when user presses the Enter key or when the component loses the focus .</li>
1204
         *   <li><i>false</i>: default behaviour .</li>
1205
         *  </ul>
1206
         * </p>
1207
         * 
1208
         * @param value for 'toForceSelectAnItem' configuration flag
1209
         */
1210
        public void setToForceSelectAnItem(boolean b) {
1211
                toForceSelectAnItem = b;
1212
        }
1213

    
1214
        /**
1215
         * <p>Returns the 'completeArrowKeySelection' configuration value of this component. Configuration values are:
1216
         *  <ul>
1217
         *   <li><i>true</i>: writes in the editor the value of the element selected by the arrow keys (up or down).</li>
1218
         *   <li><i>false</i>: holds the previous text written .</li>
1219
         *  </ul>
1220
         * </p>
1221
         * 
1222
         * @return 'completeArrowKeySelection' configuration
1223
         */
1224
        public boolean isCompleteArrowKeySelection() {
1225
                return completeArrowKeySelection;
1226
        }
1227

    
1228
        /**
1229
         * <p>Sets the 'completeArrowKeySelection' configuration value for this component. Configuration values are:
1230
         *  <ul>
1231
         *   <li><i>true</i>: writes in the editor the value of the element selected by the arrow keys (up or down).</li>
1232
         *   <li><i>false</i>: holds the previous text written .</li>
1233
         *  </ul>
1234
         * </p>
1235
         * 
1236
         * @param b value for 'completeArrowKeySelection' configuration flag
1237
         */
1238
        public void setCompleteArrowKeySelection(boolean b) {
1239
                completeArrowKeySelection = b;
1240
        }
1241

    
1242
        /**
1243
         * <p>Returns the 'displayAllItemsWithArrowButton' configuration value of this component. Configuration values are:
1244
         *  <ul>
1245
         *   <li><i>true</i>: displays all this component's dataModel items if its <i>popup</i> it's hided, and this component's dataModel
1246
         *    listed only the matches <i>(flag: <code>DefaultComboBoxConfigurableLookUpModel.showAllItemsInListBox == false</code>)</i>.</li>
1247
         *   <li><i>false</i>: normal behaviour according the other <i>flags</i>.</li>
1248
         *  </ul>
1249
         * </p>
1250
         * 
1251
         * @return 'displayAllItemsWithArrowButton' configuration
1252
         */
1253
        public boolean isDisplayAllItemsWithArrowButton() {
1254
                return displayAllItemsWithArrowButton;
1255
        }
1256
        
1257
        /**
1258
         * <p>Sets the 'toForceSelectAnItem' configuration value for this component. Configuration values are:
1259
         *  <ul>
1260
         *   <li><i>true</i>: displays all this component's dataModel items if its <i>popup</i> it's hided, and this component's dataModel
1261
         *    listed only the matches <i>(flag: <code>DefaultComboBoxConfigurableLookUpModel.showAllItemsInListBox == false</code>)</i>.</li>
1262
         *   <li><i>false</i>: normal behaviour according the other <i>flags</i>.</li>
1263
         *  </ul>
1264
         * </p>
1265
         * 
1266
         * @param value for 'displayAllItemsWithArrowButton' configuration flag
1267
         */
1268
        public void setDisplayAllItemsWithArrowButton(boolean b) {
1269
                displayAllItemsWithArrowButton = b;
1270
        }
1271

    
1272
        ////// END METHODS FOR THE BEHAVIOR FLAGS  //////
1273

    
1274

    
1275
        /**
1276
         * <p>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.</p>
1277
         * 
1278
         * <p>This class is also optimized for items look up process.</p>
1279
         * 
1280
         * @author Pablo Piqueras Bartolom? (p_queras@hotmail.com)
1281
         */
1282
        public class PlainDocumentTextFormatter extends PlainDocument {
1283
                private static final long serialVersionUID = -1858441733547527816L;
1284
                private JComboBoxConfigurableLookUp comboBoxReference;
1285
                private String textWritten;
1286
                private boolean updatedModel;
1287
                private String textOfReplacement;
1288
                private boolean textInRedColor;
1289
                private int old_caretPosition;
1290
                private String completeArrowKeySelectionValue;
1291

    
1292
                /**
1293
                 * <p>Default Constructor.</p>
1294
                 */
1295
                public PlainDocumentTextFormatter() {
1296
                        super();
1297
                        this.initialize();
1298
                }
1299
                
1300
                /**
1301
                 * <p>This method makes some initialize operations.</p> 
1302
                 */
1303
                protected void initialize() {
1304
                        textWritten = "";
1305
                        textOfReplacement = "";
1306
                        textInRedColor = false;
1307
                        completeArrowKeySelectionValue = null;
1308
                }
1309

    
1310
                /**
1311
                 * <p>Sets a reference of this component.</p>
1312
                 * 
1313
                 * @param comboBox A reference to the class that contains this.
1314
                 */
1315
                protected void setJComboBoxReference(JComboBoxConfigurableLookUp comboBox) {
1316
                        comboBoxReference = comboBox;
1317
                }
1318

    
1319
                /*
1320
                 *  (non-Javadoc)
1321
                 * @see javax.swing.text.Document#insertString(int, java.lang.String, javax.swing.text.AttributeSet)
1322
                 */
1323
                public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
1324
                        if (updatedModel) {
1325
                                model.setTextWritten(textWritten);
1326
                                super.insertString(offs, textWritten, a);
1327
                                
1328
                                return;
1329
                        }
1330

    
1331
                        hidePopup();
1332
                        
1333
                        boolean caretToEnd = true;
1334
                        
1335
                        if (textWritten.length() > 0) {
1336
                                if (offs < textWritten.length()) {
1337
                                        String old_textWritten = textWritten;
1338
                                        
1339
                                        // End of the text
1340
                                        textWritten = textWritten.substring(offs, textWritten.length());
1341
                                        
1342
                                        // Beginning of the text
1343
                                        if (offs > 0) {
1344
                                                // Reset (without text written)
1345
                                                textWritten = old_textWritten.substring(0, offs) + str + textWritten;
1346
                                        }
1347
                                        else {
1348
                                                
1349
                                                if (offs == 0) {
1350
                                                        caretToEnd = false;
1351
                                                }
1352
                                                
1353
                                                textWritten = str + textWritten;
1354
                                        }
1355
                                }
1356
                                else {
1357
                                        textWritten = textWritten.substring(0, offs) + str;
1358
                                }
1359
                        }
1360
                        else {
1361
                                textWritten =  str;
1362
                        }
1363
                                
1364
                        if (completeArrowKeySelectionValue == null) {
1365
                                model.setTextWritten(textWritten);
1366
                        }
1367
                        else {
1368
                                model.setTextWritten(completeArrowKeySelectionValue);
1369
                        }
1370
                        
1371
                        super.insertString(offs, str, a);
1372

    
1373
                        // Update the color of the text
1374
                        updateTextColorAndRingBeep();
1375
                
1376
                        if (model.getSize() > 0) {
1377
                                if (isShowing()) {
1378
                                        showPopup();
1379
                                }
1380
                        }
1381
                        else {
1382
                                if ((textWritten.compareTo("") != 0) && (!hidePopupIfThereAreNoItems)) {
1383
                                        showPopup();        
1384
                                }
1385
                        }
1386
                        
1387
                        if (caretToEnd) {
1388
                                // Update the caret position -> at the same place it was or at the end
1389
                                updateCaretPosition(textWritten.length());
1390
                        }
1391
                        else {
1392
                                // Update the caret position -> at the same place it was or at the end
1393
                                updateCaretPosition(str.length());
1394
                        }
1395
                }
1396
                
1397
                /*
1398
                 *  (non-Javadoc)
1399
                 * @see javax.swing.text.AbstractDocument#replace(int, int, java.lang.String, javax.swing.text.AttributeSet)
1400
                 */
1401
                public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
1402
                        String old_textWritten;
1403

    
1404
                        if (arrowKeyPressed) {
1405
                                if (!model.isShowAllItemsInListBox()) {
1406
                                        if (completeArrowKeySelection) {
1407
                                                String currentText = ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).getText();
1408
                                                
1409
                                                old_textWritten = textWritten;
1410
                                                old_caretPosition = ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).getCaretPosition() + text.length();
1411
                                                                
1412
                                                textWritten = "";
1413

    
1414
                                                super.remove(0, old_textWritten.length());
1415
                
1416
                                                if ((completeArrowKeySelectionValue == null) || (!currentText.equals(old_textWritten))) 
1417
                                                        completeArrowKeySelectionValue = old_textWritten;
1418

    
1419
                                                insertString(0, text, null);
1420
                                        }
1421
                                        else {
1422
                                                insertString(0, "", null);
1423
                                        }
1424
                                }
1425

    
1426
                                previousSelected = text;
1427
                                arrowKeyPressed = false;
1428

    
1429
                                return;
1430
                        }
1431

    
1432
                        completeArrowKeySelectionValue = null;
1433
                        
1434
                        // Avoid two replaces for the same operation
1435
                        if ((text.compareTo("") == 0) && (length == textWritten.length()))
1436
                                return;
1437
                        
1438
                        // Only remove if there is text to be replaced (text selected)
1439
                        if (length > 0) {
1440

    
1441
                                textOfReplacement = text;
1442
                                remove(offset, length);
1443
                        }
1444
                        else {
1445
                                if ((offset > 0) && (offset != textWritten.length())) {
1446
                                        // Must replace the dataModel for update the data in the popup correctly
1447
                                                
1448
                                        // There is a bug that when text has been removed, the elements in the popup aren seen.
1449
                                        // The solution to this bug is add them as a new dataModel
1450
                                        hidePopup();
1451

    
1452
                                        updatedModel = true;
1453

    
1454
                                        old_textWritten = textWritten;
1455
                                        old_caretPosition = ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).getCaretPosition() + text.length();
1456
                                        
1457
                                        textWritten = "";
1458
                                        model.setTextWritten(textWritten);
1459

    
1460
                                        super.remove(0, old_textWritten.length());
1461
                                
1462
                                        // Stores the configuration of the flags                                
1463
                                        int itemsOrderFlag = model.getItemsOrder();
1464
                                        boolean showAllItemsInListBox = model.isShowAllItemsInListBox();
1465
                                        String languageRules = model.getLocaleRules();
1466
                                        boolean caseSensitive = model.isCaseSensitive();
1467
                                        ILookUp lookUpAgent = model.getLookUpAgent();
1468
                                        
1469
                                        // Must replace the dataModel for update the data in the popup correctly
1470
                                        comboBoxReference.setModel(new DefaultComboBoxConfigurableLookUpModel(model.getData()));
1471
                                        
1472
                                        // Restores the configuration of the flags
1473
                                        model.setItemsOrder(itemsOrderFlag);
1474
                                        model.setShowAllItemsInListBox(showAllItemsInListBox);
1475
                                        model.setLocaleRules(languageRules);
1476
                                        model.setCaseSensitive(caseSensitive);
1477
                                        model.setLookUpAgent(lookUpAgent);
1478
                                        
1479
                                        // Reset (without text written)
1480
                                        insertString(0, textWritten, null);
1481
                                        
1482
                                        // Insert the new text
1483
                                        textWritten = old_textWritten.substring(0, offset) + text + old_textWritten.substring(offset, old_textWritten.length());
1484
                                        
1485
                                        insertString(0, textWritten, null);
1486

    
1487
                                        updatedModel = false;
1488

    
1489
                                        // Update the color of the text
1490
                                        updateTextColorAndRingBeep();
1491
                                        
1492
                                        // Update the caret position -> at the same place it was or at the end
1493
                                        updateCaretPosition(old_caretPosition);
1494
                                        
1495
                                        // Only show the popup if there are items to show
1496
                                        if (model.getSize() > 0) {
1497
                                                 showPopup();
1498
                                        }
1499
                                        else {
1500
                                                if ((textWritten.compareTo("") != 0) && (!hidePopupIfThereAreNoItems)) {
1501
                                                        showPopup();        
1502
                                                }
1503
                                        }
1504
                                }
1505
                                else {
1506
                                        // Default replacement
1507
                                        super.replace(offset, length, text, attrs);
1508
                                }
1509
                        }
1510
                }
1511
                        
1512
                /*
1513
                 *  (non-Javadoc)
1514
                 * @see javax.swing.text.Document#remove(int, int)
1515
                 */
1516
                public void remove(int offs, int len) throws BadLocationException {
1517
                        String old_textWritten;
1518
                                
1519
                        // There is a bug that when text has been removed, the elements in the popup aren seen.
1520
                        // The solution to this bug is add them as a new dataModel
1521
                        hidePopup();
1522

    
1523
                        updatedModel = true;
1524

    
1525
                        old_textWritten = textWritten;
1526
                        
1527
                        old_caretPosition = Math.min(((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).getCaretPosition(), offs);
1528
                        
1529
                        textWritten = "";
1530
                        model.setTextWritten(textWritten);
1531

    
1532
                        super.remove(0, old_textWritten.length());
1533
                        
1534
                        int itemsOrderFlag = model.getItemsOrder();
1535
                        boolean showAllItemsInListBox = model.isShowAllItemsInListBox();
1536
                        String languageRules = model.getLocaleRules();
1537
                        boolean caseSensitive = model.isCaseSensitive();
1538
                        ILookUp lookUpAgent = model.getLookUpAgent();
1539
                
1540
                        // Must replace the dataModel for update the data in the popup correctly
1541
                        comboBoxReference.setModel(new DefaultComboBoxConfigurableLookUpModel(model.getData()));
1542
                        
1543
                        // Restores the configuration of the flags
1544
                        model.setItemsOrder(itemsOrderFlag);
1545
                        model.setShowAllItemsInListBox(showAllItemsInListBox);
1546
                        model.setLocaleRules(languageRules);
1547
                        model.setCaseSensitive(caseSensitive);
1548
                        model.setLookUpAgent(lookUpAgent);
1549

    
1550
                        // Reset (without text written)
1551
                        insertString(0, textWritten, null);
1552
                        
1553
                        // Insert the new text
1554
                        textWritten = old_textWritten.substring(0, offs) + textOfReplacement + old_textWritten.substring(offs + len, old_textWritten.length());
1555

    
1556
                        insertString(0, textWritten, null);
1557
                        
1558
                        updatedModel = false;
1559
                        
1560
                        // Update the color of the text
1561
                        updateTextColorAndRingBeep();
1562
                        
1563
                        // Only show the popup if there are items to show
1564
                        if (model.getSize() > 0) {
1565
                                 showPopup();
1566
                        }
1567
                        else {
1568
                                if ((textWritten.compareTo("") != 0) && (!hidePopupIfThereAreNoItems)) {
1569
                                        showPopup();        
1570
                                }
1571
                        }
1572
        
1573
//                        if (old_caretPosition == 0) {
1574
//                                // Set the caret position to the end of the text
1575
//                                updateCaretPosition(textWritten.length());
1576
//                        }
1577
//                        else {
1578
                                // Update the caret position -> at the same place it was or at the end
1579
                                updateCaretPosition(old_caretPosition + textOfReplacement.length());
1580
//                        }
1581
                        
1582
                        textOfReplacement = "";
1583
                }
1584

    
1585
                /**
1586
                 * <p>Updates the color of the text in the {@link ComboBoxEditor} of this component, and
1587
                 *  rings a beep if there is no item.</p>
1588
                 * 
1589
                 * <ul>
1590
                 *  <li><i>Text in <u>red color</u></i>: if no item matches with the text written according the <code>ILookUp</code> agent.</li>
1591
                 *  <li><i>Text in <u>black color</u></i>: if there is at least one item matches with the text written according the <code>ILookUp</code> agent.</li>
1592
                 * </ul>
1593
                 */
1594
                public void updateTextColorAndRingBeep() {
1595
                        if (! comboBoxReference.isOnlyOneColorOnText()) {
1596
                                if (model.isShowAllItemsInListBox()) {
1597
                                        // Set text into red color if no items matches with the text written, or in black color if it was in red
1598
                                        //   color and now there is almost one element that starts with the characteres written by the user
1599
                                        if (textWritten.compareTo("") != 0) {
1600
                                                if (model.getSelectedItem() == null) {
1601
                                                        comboBoxReference.getEditor().getEditorComponent().setForeground(Color.RED);
1602
                                                        textInRedColor = true;
1603
                                                                 
1604
                                                                 // Rings a beep if allowed
1605
                                                if (beepEnabled)
1606
                                                        comboBoxReference.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
1607
                                                }
1608
                                                else {
1609
                                                        comboBoxReference.getEditor().getEditorComponent().setForeground(Color.BLACK);
1610
                                                        textInRedColor = false;
1611
                                                }
1612
                                        }
1613
                                        else {
1614
                                                if (textInRedColor) {
1615
                                                        comboBoxReference.getEditor().getEditorComponent().setForeground(Color.BLACK);
1616
                                                        textInRedColor = false;
1617
                                                }
1618
                                        }
1619
                                }
1620
                                else {
1621
                                        // Set text into red color if no items matches with the text written, or in black color if it was in red
1622
                                        //   color and now there is almost one element that starts with the characteres written by the user
1623
                                        if (textWritten.compareTo("") != 0) {
1624
                                                if (model.getSize() == 0) {
1625
                                                        comboBoxReference.getEditor().getEditorComponent().setForeground(Color.RED);
1626
                                                        textInRedColor = true;
1627
                                                                 
1628
                                                                 // Rings a beep if allowed
1629
                                                if (beepEnabled)
1630
                                                        comboBoxReference.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
1631
                                                }
1632
                                                else {
1633
                                                        comboBoxReference.getEditor().getEditorComponent().setForeground(Color.BLACK);
1634
                                                        textInRedColor = false;
1635
                                                }
1636
                                        }
1637
                                        else {
1638
                                                if (textInRedColor) {
1639
                                                        comboBoxReference.getEditor().getEditorComponent().setForeground(Color.BLACK);
1640
                                                        textInRedColor = false;
1641
                                                }
1642
                                        }
1643
                                }
1644
                        }
1645
                        else {
1646
                                // Rings a beep if no there is no item, and if it's allowed
1647
                                if ((textWritten.compareTo("") != 0) && (model.getSize() == 0)) {
1648
                                        if (beepEnabled)
1649
                                                comboBoxReference.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
1650
                                }
1651
                        }
1652
                }
1653
                
1654
                /**
1655
                 * <p>Updates the position of the caret in the {@link ComboBoxEditor} of this component.</p>
1656
                 * 
1657
                 * @param position the new position of the caret.
1658
                 */
1659
                public void updateCaretPosition(int position) {
1660
                        // If user has selected an item of the popup (using the mouse) -> set the caret position to the end of the text
1661
                        if (popupItemSelected) {
1662
                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(textWritten.length());
1663
                                popupItemSelected = false;
1664
                                return;
1665
                        }
1666
                        
1667
                        if (position > textWritten.length())
1668
                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(textWritten.length());
1669
                        else {
1670
                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(position);
1671
                        }
1672
                }
1673

    
1674
                /**
1675
                 * <p>Updates the color of the text in this document.</p>
1676
                 * 
1677
                 * <p>Sets text to red color if there is no item in the visible list that the <i>look up</i> agent
1678
                 *  returned with that text and the items of the dataModel, and, being enabled the second color in
1679
                 *  the configuration the the <code>JcomboBoxConfigurableLookUp</code> agent. Otherwise, the foreground color
1680
                 *  of the text will be black.</p>
1681
                 * 
1682
                 * <p>This method disables the <i>beep</i> during the process of updating the color of the text, and
1683
                 *  restores it after.</p>
1684
                 */
1685
                public void updateOnlyTextColor() {
1686
                        boolean isBeepEnabled = isBeepEnabled();
1687
                        setBeepEnabled(false);
1688
                        
1689
                        updateTextColorAndRingBeep();
1690
                                
1691
                        setBeepEnabled(isBeepEnabled);
1692
                }
1693
        }
1694
}