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 @ 41179

History | View | Annotate | Download (54.3 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? 
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
                                public void mousePressed(MouseEvent e) {
429
                                        // User selects an item of the popup using the mouse
430
                                        popupItemSelected = true;
431
                                        System.out.println("Pulsado");
432
                                }
433
                        });
434
                                
435
                        if (aC instanceof BasicComboPopup) {
436
                                ((BasicComboPopup)aC).addPopupMenuListener(new PopupMenuListener() {
437
                                        public void popupMenuCanceled(PopupMenuEvent e) {
438
                                                if (arrowButtonClicked) {
439
                                                        arrowButtonClicked = false;
440
                                                }
441
                                        }
442

    
443
                                        public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
444
                                                if (arrowButtonClicked) {
445
                                                        arrowButtonClicked = false;
446
                                                }
447
                                        }
448

    
449
                                        public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
450
                                                if (arrowButtonClicked) {
451
                                                        arrowButtonClicked = false;
452
                                                }
453
                                        }
454
                                });
455
                        }
456
                }
457
        }
458

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

    
578
                                                // Sets the caret position of the text in the document to the end:
579
                                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(document.getLength());
580

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

    
699
                                final DefaultComboBoxConfigurableLookUpModel c_model = (DefaultComboBoxConfigurableLookUpModel)comboBoxReference.getModel();
700

    
701
                                if (toForceSelectAnItem) {
702
                                        if (c_model.isShowAllItemsInListBox()) {
703
                                                // Select now the first item or the previous selected
704
                                                if (c_model.getSelectedItem() == null) {
705
                                                        if (c_model.getData().size() > 0) {
706
                                                                if (previousSelected == null)
707
                                                                        previousSelected = c_model.getDataAccordingItemsOrder().elementAt(0);
708
                                                                else {
709
                                                                        ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
710
                                                                }
711
                                                        }
712
                                                        else {
713
                                                                previousSelected = null;
714
                                                        }
715
                                                }
716
                                                else {                                                                
717
                                                        previousSelected = c_model.getSelectedItem();                                                                        
718
                                                        comboBoxReference.setSelectedItem(previousSelected);
719
                                                }
720

    
721
                                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
722
                                        }
723
                                        else {
724
                                                // Select now the first item or the previous selected
725
                                                switch (model.getData().size()) {
726
                                                        case 0:
727
                                                                if (previousSelected == null) {
728
                                                                        if (c_model.getData().size() > 0) {
729
                                                                                previousSelected = c_model.getDataAccordingItemsOrder().elementAt(0);
730

    
731
                                                                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
732
                                                                        }
733
                                                                        else {
734
                                                                                previousSelected = null;
735
                                                                        }
736
                                                                }
737
                                                                break;
738
                                                        default:
739
                                                                if (previousSelected == null) {
740
                                                                        previousSelected = comboBoxReference.getItemAt(0); // Select the first
741
                                                                        comboBoxReference.setSelectedIndex(0);
742
                                                                }
743
                                                                else
744
                                                                        ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setText(previousSelected.toString());
745
                                                }
746
                                        }
747
                                }
748

    
749
                                comboBoxReference.hidePopup();
750

    
751
                                // Workaround for Bug 5100422 - Hide Popup on focus loss
752
                                if (hidePopupOnFocusLoss)
753
                                        comboBoxReference.setPopupVisible(false);
754
                        }                        
755
                };
756
        }
757
        
758
        ///// END NEW METHODS /////
759
        
760
        ///// REIMPLEMENTATION OF METHODS OF 'JComboBox' /////
761
        
762
        /**
763
         * <p>Sets the editor used to paint and edit the selected item in the 
764
     * <code>JComboBox</code> field.  The editor is used only if the
765
     * receiving <code>JComboBox</code> is editable. If not editable,
766
     * the combo box uses the renderer to paint the selected item.</p>
767
     * 
768
     * <p>The editor must be a <code>JTextComponent</code>, and its document a <code>PlainDocument</code> object.</p>
769
     *  
770
     * @param anEditor  the <code>ComboBoxEditor</code> that
771
     *                        displays the selected item
772
     * @see #setRenderer
773
     * @beaninfo
774
     *     bound: true
775
     *    expert: true
776
     *  description: The editor that combo box uses to edit the current value
777
         */
778
        public void setEditor(ComboBoxEditor anEditor) {
779
                if (anEditor == null) {
780
                        super.setEditor(anEditor);
781
                        return;
782
                }
783
                
784
                JTextComponent jTextComponentOfEditor = (JTextComponent) anEditor.getEditorComponent();
785

    
786
                // Adds the new ''PlainDocumentTextFormatter'', adding the listeners of the new editor's document
787
                PlainDocument old_document = ((PlainDocument)jTextComponentOfEditor.getDocument());
788
                
789
                DocumentListener[] documentListeners = old_document.getDocumentListeners();
790
                UndoableEditListener[] undoableEditListeners = old_document.getUndoableEditListeners();
791
                
792
                // Defines a key listener for the editor of this component
793
                defineEditorKeyListener(this);
794
                jTextComponentOfEditor.addKeyListener(editorKeyListener);
795
                
796
                // Defines a focus listener for the editor of this component
797
                defineEditorFocusListener(this);
798
                jTextComponentOfEditor.addFocusListener(editorFocusListener);
799
                
800
                document = new PlainDocumentTextFormatter();
801
                                
802
                // Set reference to the container component
803
                document.setJComboBoxReference(this);
804
                        
805
                // Removes all previous 'document' and 'undoableEdit' listeners
806
                DocumentListener[] removableDocumentListeners = document.getDocumentListeners();
807
                for (DocumentListener dL : removableDocumentListeners)
808
                        document.removeDocumentListener(dL);
809

    
810
                UndoableEditListener[] removableUndoableEditListeners = document.getUndoableEditListeners();
811
                for (UndoableEditListener dUEL : removableUndoableEditListeners)
812
                        document.removeUndoableEditListener(dUEL);
813

    
814
                for (DocumentListener rdL : documentListeners)
815
                        document.addDocumentListener(rdL);
816
                
817
                // The undo-redo listeners fail
818
                for (UndoableEditListener uEL : undoableEditListeners) 
819
                        document.addUndoableEditListener(uEL);
820
                
821
                if (undoableEditListeners.length > 0) {
822
                        if (jTextComponentOfEditor instanceof IEditableText) {
823
                                ((IEditableText)jTextComponentOfEditor).addUndoRedoEditListener(new UndoRedoEditListener() {
824
                                        /*
825
                                         * (non-Javadoc)
826
                                         * @see org.gvsig.gui.beans.editabletextcomponent.event.UndoRedoEditListener#operationExecuted(org.gvsig.gui.beans.editabletextcomponent.event.UndoRedoEditEvent)
827
                                         */
828
                                        public void operationExecuted(UndoRedoEditEvent e) {
829
                                                model.setTextWritten(e.getNewText());
830
                                                document.updateOnlyTextColor();
831
                                        }
832
                                });
833
                        }
834
                }
835

    
836
                jTextComponentOfEditor.setDocument(document);
837
                
838
                super.setEditor(anEditor);
839
        }
840

    
841
        public void setModel(ComboBoxModel aModel) {
842
                // If model isn't DefaultComboBoxConfigurableLookUpModel, sets as model a new DefaultComboBoxConfigurableLookUpModel, with the data
843
                //  of ''aModel'':
844
                if (! (aModel instanceof DefaultComboBoxConfigurableLookUpModel) ) {
845
                        Vector<Object> data = new Vector<Object>(aModel.getSize());
846
                        
847
                        for (int i = 0; i < aModel.getSize(); i++) {
848
                                data.add(aModel.getElementAt(i));
849
                        }
850
                        
851
                        aModel = new DefaultComboBoxConfigurableLookUpModel(data);
852
                }
853
                
854
                super.setModel(aModel);
855
                
856
                model = (DefaultComboBoxConfigurableLookUpModel)super.getModel();
857
        }
858
        
859
        public void setSelectedIndex(int anIndex) {
860
                if (anIndex < -1 || anIndex >= model.getSize())
861
                        // Fails because index is out of bounds.
862
                        throw new IllegalArgumentException("setSelectedIndex: " + anIndex + " out of bounds");
863
                else
864
                        // Selects the item at the given index or clears the selection if the
865
                        // index value is -1.
866
                        setSelectedItem((anIndex == -1) ? null : model.getElementAt(anIndex));
867
        }
868
        
869
        public void setSelectedItem(Object anObject) {                
870
                if ((selectedItemReminder == null) || (!selectedItemReminder.equals(anObject))) {
871
                        if (arrowKeyPressed) {
872
                                
873
                                selectingItem = true;
874
                                model.setSelectedItem(anObject);
875
                                selectingItem = false;
876
                                
877
                                if (model.getSize() > 0)
878
                                        previousSelected = anObject;
879
                        }
880
                        else {
881
                                selectingItem = true;
882
                                model.setSelectedItem(anObject);
883
                                selectingItem = false;
884
                                
885
                                editor.setItem(anObject);
886
                                
887
                                if (model.getSize() > 0)
888
                                        previousSelected = anObject;
889
                        }
890
                        
891
                        if (selectedItemReminder != model.getSelectedItem()) {
892
                                // In case a users implementation of ComboBoxModel
893
                                // doesn't fire a ListDataEvent when the selection
894
                                // changes.
895
                                selectedItemChanged();
896
                        }
897
                }                        
898
                fireActionEvent();
899
                document.updateOnlyTextColor();
900
        }
901

    
902
        public void setEditable(boolean b) {
903
                throw new UnsupportedOperationException();
904
        }
905
        
906
        public void removeAllItems() {
907
                if ( !(model instanceof MutableComboBoxModel) )
908
                        throw new RuntimeException("Cannot use this method with a non-Mutable data dataModel.");
909

    
910
                //if ( model instanceof DefaultComboBoxConfigurableLookUpModel ) {
911
                model.setTextWritten("");
912
                ((DefaultComboBoxConfigurableLookUpModel)model).removeAllElements();
913

    
914
                selectedItemReminder = null;
915

    
916
                if (isEditable()) {
917
                        editor.setItem(null);
918
                }
919
                
920
                document.updateTextColorAndRingBeep();
921
                updateUI();
922
        }
923
        
924
        public void addItem(Object anObject) {
925
                super.addItem(anObject);
926

    
927
                if ((toForceSelectAnItem) && (getSelectedIndex() == -1))
928
                        setSelectedIndex(0);
929
                
930
                document.updateTextColorAndRingBeep();
931
        }
932

    
933
        /*
934
         * (non-Javadoc)
935
         * @see javax.swing.JComboBox#removeItem(java.lang.Object)
936
         */
937
        public void removeItem(Object anObject) {
938
                super.removeItem(anObject);
939
                
940
                document.updateTextColorAndRingBeep();
941
        }
942

    
943
        /*
944
         * (non-Javadoc)
945
         * @see javax.swing.JComboBox#removeItemAt(int)
946
         */
947
        public void removeItemAt(int anIndex) {
948
                super.removeItemAt(anIndex);
949
                
950
                document.updateTextColorAndRingBeep();
951
        }
952

    
953
        /*
954
         * (non-Javadoc)
955
         * @see javax.swing.JComponent#setUI(javax.swing.plaf.ComponentUI)
956
         */
957
        protected void setUI(ComponentUI newUI) {
958
                super.setUI(newUI);
959
                ComponentUI oldUI = newUI;
960
                
961
                // Remove the default key selection manager
962
                super.setKeySelectionManager(null);
963
                
964
        firePropertyChange("UI", oldUI, newUI);
965
        revalidate();
966
        repaint();
967
        }
968

    
969
        /*
970
         * <p>Unsupported operation.</p>
971
         * 
972
         * (non-Javadoc)
973
         * @see javax.swing.JComboBox#selectWithKeyChar(char)
974
         */
975
        public boolean selectWithKeyChar(char keyChar) {
976
                throw new UnsupportedOperationException();
977
        }
978

    
979
        /*
980
         * <p>Unsupported operation.</p>
981
         * 
982
         * (non-Javadoc)
983
         * @see javax.swing.JComboBox#processKeyEvent(java.awt.event.KeyEvent)
984
         */
985
        public void processKeyEvent(KeyEvent e) {
986
                throw new UnsupportedOperationException();
987
        }
988

    
989
        /*
990
         * <p>Unsupported operation.</p>
991
         * 
992
         * (non-Javadoc)
993
         * @see javax.swing.JComboBox#createDefaultKeySelectionManager()
994
         */
995
        protected KeySelectionManager createDefaultKeySelectionManager() {
996
                throw new UnsupportedOperationException();
997
        }
998

    
999
        /*
1000
         * (non-Javadoc)
1001
         * @see javax.swing.JComboBox#paramString()
1002
         */
1003
        protected String paramString() {
1004
                return super.paramString() +
1005
                  "onlyOneColorOnText" + onlyOneColorOnText +
1006
                  "beepEnabled" + beepEnabled +
1007
                  "hidePopupIfThereAreNoItems" + hidePopupIfThereAreNoItems +
1008
                  "toForceSelectAnItem" + toForceSelectAnItem +
1009
                  "completeArrowKeySelection" + completeArrowKeySelection +
1010
                  "displayAllItemsWithArrowButton" + displayAllItemsWithArrowButton +
1011
                  "itemsOrder" + model.getItemsOrder() +
1012
                  "showAllItemsInListBox" + model.isShowAllItemsInListBox() +
1013
                  "localeRules" + model.getLocaleRules() +
1014
                  "caseSensitive" + model.isCaseSensitive();
1015
        }
1016

    
1017
        /*
1018
         * (non-Javadoc)
1019
         * @see javax.swing.JComboBox#updateUI()
1020
         */
1021
        public void updateUI() {
1022
                super.updateUI();
1023
                
1024
                // Force to hide the popup
1025
                updatedUI = true;
1026

    
1027
                for (int i = 0; i < getComponentCount(); i++) {
1028
                        if (getComponent(i) instanceof JButton) {
1029
                                ((JButton)getComponent(i)).addMouseListener(getArrowMouseListener());
1030
                                return;
1031
                        }
1032
                }
1033
        }
1034
        
1035
        /*
1036
         * (non-Javadoc)
1037
         * @see javax.swing.JComboBox#showPopup()
1038
         */
1039
        public void showPopup() {
1040
                if (this.isShowing() && (!blockPopupHided))
1041
                        setPopupVisible(true);
1042
        }
1043

    
1044
        /**
1045
         * <p>Sets if the popup of this component will always remain hided, or can be shown when is invoked.</p>
1046
         * 
1047
         * @param b <code>true</code> if will remain blocked; <code>false</code> if can be shown 
1048
         */
1049
        public void setBlockPopupHided(boolean b) {
1050
                blockPopupHided = b;
1051
        }
1052
        
1053

    
1054
        /**
1055
         * <p>Determines if the popup of this component will always remain hided.</p>
1056
         * 
1057
         * @param b <code>true</code> if will remain blocked; <code>false</code> if can be shown 
1058
         */
1059
        public boolean isBlockPopupHided() {
1060
                return blockPopupHided;
1061
        }
1062
        ///// END REIMPLEMENTATION OF METHODS OF 'JComboBox' /////    
1063
        
1064
        ////// METHODS FOR THE BEHAVIOR FLAGS  //////
1065
        /**
1066
         * <p>Returns the 'only_One_Color_On_Text' configuration value of this component. Configuration values are:
1067
         *  <ul>
1068
         *   <li><i>true</i>: always uses black colour on text.</li>
1069
         *   <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>
1070
         *  </ul>
1071
         * </p>
1072
         * 
1073
         * @return 'only_One_Color_On_Text' configuration
1074
         */
1075
        public boolean isOnlyOneColorOnText() {
1076
                return onlyOneColorOnText;
1077
        }
1078
        
1079
        /**
1080
         * <p>Sets the 'only_One_Color_On_Text' configuration value for this component. Configuration values are:
1081
         *  <ul>
1082
         *   <li><i>true</i>: always uses black colour on text.</li>
1083
         *   <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>
1084
         *  </ul>
1085
         * </p>
1086
         * 
1087
         * @param b value for 'only_One_Color_On_Text' configuration flag
1088
         */
1089
        public void setOnlyOneColorOnText(boolean b) {
1090
                onlyOneColorOnText = b;
1091
        }
1092

    
1093
        /**
1094
         * <p>Returns the 'beep_Enabled' configuration value of this component. Configuration values are:
1095
         *  <ul>
1096
         *   <li><i>true</i>: a beep-sound is listened when no item matches with the text written according the <code>ILookUp</code> agent.</li>
1097
         *   <li><i>false</i>: no sound is listened.</li>
1098
         *  </ul>
1099
         * </p>
1100
         * 
1101
         * @return 'beep_Enabled' configuration
1102
         */
1103
        public boolean isBeepEnabled() {
1104
                return beepEnabled;
1105
        }
1106
        
1107
        /**
1108
         * <p>Sets the 'beep_Enabled' configuration value for this component. Configuration values are:
1109
         *  <ul>
1110
         *   <li><i>true</i>: a beep-sound is listened when no item matches with the text written according the <code>ILookUp</code> agent.</li>
1111
         *   <li><i>false</i>: no sound is listened.</li>
1112
         *  </ul>
1113
         * </p>
1114
         * 
1115
         * @param b value for 'beep_Enabled' configuration flag
1116
         */
1117
        public void setBeepEnabled(boolean b) {
1118
                beepEnabled = b;
1119
        }        
1120

    
1121
        /**
1122
         * <p>Returns the 'hidePopupIfThereAreNoItems' configuration value of this component. Configuration values are:
1123
         *  <ul>
1124
         *   <li><i>true</i>: hides the popup if there are no items when you write.</li>
1125
         *   <li><i>false</i>: default behaviour (if there are no items when you write, popup remains visible) .</li>
1126
         *  <ul>
1127
         * </p>
1128
         * 
1129
         * @return 'hidePopupIfThereAreNoItems' configuration
1130
         */
1131
        public boolean isHidePopupIfThereAreNoItems() {
1132
                return hidePopupIfThereAreNoItems;
1133
        }
1134
        
1135
        /**
1136
         * <p>Sets the 'hidePopupIfThereAreNoItems' configuration value for this component. Configuration values are:
1137
         *  <ul>
1138
         *   <li><i>true</i>: hides the popup if there are no items when you write.</li>
1139
         *   <li><i>false</i>: default behaviour (if there are no items when you write, popup remains visible) .</li>
1140
         *  <ul>
1141
         * </p>
1142
         * 
1143
         * @param b value for 'hidePopupIfThereAreNoItems' configuration flag
1144
         */
1145
        public void setHidePopupIfThereAreNoItems(boolean b) {
1146
                hidePopupIfThereAreNoItems = b;
1147
        }
1148

    
1149
        /**
1150
         * <p>Returns the 'toForceSelectAnItem' configuration value of this component. Configuration values are:
1151
         *  <ul>
1152
         *   <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>
1153
         *   <li><i>false</i>: default behaviour .</li>
1154
         *  </ul>
1155
         * </p>
1156
         * 
1157
         * @return 'toForceSelectAnItem' configuration
1158
         */
1159
        public boolean isToForceSelectAnItem() {
1160
                return toForceSelectAnItem;
1161
        }
1162
        
1163
        /**
1164
         * <p>Sets the 'toForceSelectAnItem' configuration value for this component. Configuration values are:
1165
         *  <ul>
1166
         *   <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>
1167
         *   <li><i>false</i>: default behaviour .</li>
1168
         *  </ul>
1169
         * </p>
1170
         * 
1171
         * @param value for 'toForceSelectAnItem' configuration flag
1172
         */
1173
        public void setToForceSelectAnItem(boolean b) {
1174
                toForceSelectAnItem = b;
1175
        }
1176

    
1177
        /**
1178
         * <p>Returns the 'completeArrowKeySelection' configuration value of this component. Configuration values are:
1179
         *  <ul>
1180
         *   <li><i>true</i>: writes in the editor the value of the element selected by the arrow keys (up or down).</li>
1181
         *   <li><i>false</i>: holds the previous text written .</li>
1182
         *  </ul>
1183
         * </p>
1184
         * 
1185
         * @return 'completeArrowKeySelection' configuration
1186
         */
1187
        public boolean isCompleteArrowKeySelection() {
1188
                return completeArrowKeySelection;
1189
        }
1190

    
1191
        /**
1192
         * <p>Sets the 'completeArrowKeySelection' configuration value for this component. Configuration values are:
1193
         *  <ul>
1194
         *   <li><i>true</i>: writes in the editor the value of the element selected by the arrow keys (up or down).</li>
1195
         *   <li><i>false</i>: holds the previous text written .</li>
1196
         *  </ul>
1197
         * </p>
1198
         * 
1199
         * @param b value for 'completeArrowKeySelection' configuration flag
1200
         */
1201
        public void setCompleteArrowKeySelection(boolean b) {
1202
                completeArrowKeySelection = b;
1203
        }
1204

    
1205
        /**
1206
         * <p>Returns the 'displayAllItemsWithArrowButton' configuration value of this component. Configuration values are:
1207
         *  <ul>
1208
         *   <li><i>true</i>: displays all this component's dataModel items if its <i>popup</i> it's hided, and this component's dataModel
1209
         *    listed only the matches <i>(flag: <code>DefaultComboBoxConfigurableLookUpModel.showAllItemsInListBox == false</code>)</i>.</li>
1210
         *   <li><i>false</i>: normal behaviour according the other <i>flags</i>.</li>
1211
         *  </ul>
1212
         * </p>
1213
         * 
1214
         * @return 'displayAllItemsWithArrowButton' configuration
1215
         */
1216
        public boolean isDisplayAllItemsWithArrowButton() {
1217
                return displayAllItemsWithArrowButton;
1218
        }
1219
        
1220
        /**
1221
         * <p>Sets the 'toForceSelectAnItem' configuration value for this component. Configuration values are:
1222
         *  <ul>
1223
         *   <li><i>true</i>: displays all this component's dataModel items if its <i>popup</i> it's hided, and this component's dataModel
1224
         *    listed only the matches <i>(flag: <code>DefaultComboBoxConfigurableLookUpModel.showAllItemsInListBox == false</code>)</i>.</li>
1225
         *   <li><i>false</i>: normal behaviour according the other <i>flags</i>.</li>
1226
         *  </ul>
1227
         * </p>
1228
         * 
1229
         * @param value for 'displayAllItemsWithArrowButton' configuration flag
1230
         */
1231
        public void setDisplayAllItemsWithArrowButton(boolean b) {
1232
                displayAllItemsWithArrowButton = b;
1233
        }
1234

    
1235
        ////// END METHODS FOR THE BEHAVIOR FLAGS  //////
1236

    
1237

    
1238
        /**
1239
         * <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>
1240
         * 
1241
         * <p>This class is also optimized for items look up process.</p>
1242
         * 
1243
         * @author Pablo Piqueras Bartolom? (p_queras@hotmail.com)
1244
         */
1245
        public class PlainDocumentTextFormatter extends PlainDocument {
1246
                private static final long serialVersionUID = -1858441733547527816L;
1247
                private JComboBoxConfigurableLookUp comboBoxReference;
1248
                private String textWritten;
1249
                private boolean updatedModel;
1250
                private String textOfReplacement;
1251
                private boolean textInRedColor;
1252
                private int old_caretPosition;
1253
                private String completeArrowKeySelectionValue;
1254

    
1255
                /**
1256
                 * <p>Default Constructor.</p>
1257
                 */
1258
                public PlainDocumentTextFormatter() {
1259
                        super();
1260
                        this.initialize();
1261
                }
1262
                
1263
                /**
1264
                 * <p>This method makes some initialize operations.</p> 
1265
                 */
1266
                protected void initialize() {
1267
                        textWritten = "";
1268
                        textOfReplacement = "";
1269
                        textInRedColor = false;
1270
                        completeArrowKeySelectionValue = null;
1271
                }
1272

    
1273
                /**
1274
                 * <p>Sets a reference of this component.</p>
1275
                 * 
1276
                 * @param comboBox A reference to the class that contains this.
1277
                 */
1278
                protected void setJComboBoxReference(JComboBoxConfigurableLookUp comboBox) {
1279
                        comboBoxReference = comboBox;
1280
                }
1281

    
1282
                /*
1283
                 *  (non-Javadoc)
1284
                 * @see javax.swing.text.Document#insertString(int, java.lang.String, javax.swing.text.AttributeSet)
1285
                 */
1286
                public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
1287
                        if (updatedModel) {
1288
                                model.setTextWritten(textWritten);
1289
                                super.insertString(offs, textWritten, a);
1290
                                
1291
                                return;
1292
                        }
1293

    
1294
                        hidePopup();
1295
                        
1296
                        boolean caretToEnd = true;
1297
                        
1298
                        if (textWritten.length() > 0) {
1299
                                if (offs < textWritten.length()) {
1300
                                        String old_textWritten = textWritten;
1301
                                        
1302
                                        // End of the text
1303
                                        textWritten = textWritten.substring(offs, textWritten.length());
1304
                                        
1305
                                        // Beginning of the text
1306
                                        if (offs > 0) {
1307
                                                // Reset (without text written)
1308
                                                textWritten = old_textWritten.substring(0, offs) + str + textWritten;
1309
                                        }
1310
                                        else {
1311
                                                
1312
                                                if (offs == 0) {
1313
                                                        caretToEnd = false;
1314
                                                }
1315
                                                
1316
                                                textWritten = str + textWritten;
1317
                                        }
1318
                                }
1319
                                else {
1320
                                        textWritten = textWritten.substring(0, offs) + str;
1321
                                }
1322
                        }
1323
                        else {
1324
                                textWritten =  str;
1325
                        }
1326
                                
1327
                        if (completeArrowKeySelectionValue == null) {
1328
                                model.setTextWritten(textWritten);
1329
                        }
1330
                        else {
1331
                                model.setTextWritten(completeArrowKeySelectionValue);
1332
                        }
1333
                        
1334
                        super.insertString(offs, str, a);
1335

    
1336
                        // Update the color of the text
1337
                        updateTextColorAndRingBeep();
1338
                
1339
                        if (model.getSize() > 0) {
1340
                                if (isShowing()) {
1341
                                        showPopup();
1342
                                }
1343
                        }
1344
                        else {
1345
                                if ((textWritten.compareTo("") != 0) && (!hidePopupIfThereAreNoItems)) {
1346
                                        showPopup();        
1347
                                }
1348
                        }
1349
                        
1350
                        if (caretToEnd) {
1351
                                // Update the caret position -> at the same place it was or at the end
1352
                                updateCaretPosition(textWritten.length());
1353
                        }
1354
                        else {
1355
                                // Update the caret position -> at the same place it was or at the end
1356
                                updateCaretPosition(str.length());
1357
                        }
1358
                }
1359
                
1360
                /*
1361
                 *  (non-Javadoc)
1362
                 * @see javax.swing.text.AbstractDocument#replace(int, int, java.lang.String, javax.swing.text.AttributeSet)
1363
                 */
1364
                public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
1365
                        String old_textWritten;
1366

    
1367
                        if (arrowKeyPressed) {
1368
                                if (!model.isShowAllItemsInListBox()) {
1369
                                        if (completeArrowKeySelection) {
1370
                                                String currentText = ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).getText();
1371
                                                
1372
                                                old_textWritten = textWritten;
1373
                                                old_caretPosition = ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).getCaretPosition() + text.length();
1374
                                                                
1375
                                                textWritten = "";
1376

    
1377
                                                super.remove(0, old_textWritten.length());
1378
                
1379
                                                if ((completeArrowKeySelectionValue == null) || (!currentText.equals(old_textWritten))) 
1380
                                                        completeArrowKeySelectionValue = old_textWritten;
1381

    
1382
                                                insertString(0, text, null);
1383
                                        }
1384
                                        else {
1385
                                                insertString(0, "", null);
1386
                                        }
1387
                                }
1388

    
1389
                                previousSelected = text;
1390
                                arrowKeyPressed = false;
1391

    
1392
                                return;
1393
                        }
1394

    
1395
                        completeArrowKeySelectionValue = null;
1396
                        
1397
                        // Avoid two replaces for the same operation
1398
                        if ((text.compareTo("") == 0) && (length == textWritten.length()))
1399
                                return;
1400
                        
1401
                        // Only remove if there is text to be replaced (text selected)
1402
                        if (length > 0) {
1403

    
1404
                                textOfReplacement = text;
1405
                                remove(offset, length);
1406
                        }
1407
                        else {
1408
                                if ((offset > 0) && (offset != textWritten.length())) {
1409
                                        // Must replace the dataModel for update the data in the popup correctly
1410
                                                
1411
                                        // There is a bug that when text has been removed, the elements in the popup aren seen.
1412
                                        // The solution to this bug is add them as a new dataModel
1413
                                        hidePopup();
1414

    
1415
                                        updatedModel = true;
1416

    
1417
                                        old_textWritten = textWritten;
1418
                                        old_caretPosition = ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).getCaretPosition() + text.length();
1419
                                        
1420
                                        textWritten = "";
1421
                                        model.setTextWritten(textWritten);
1422

    
1423
                                        super.remove(0, old_textWritten.length());
1424
                                
1425
                                        // Stores the configuration of the flags                                
1426
                                        int itemsOrderFlag = model.getItemsOrder();
1427
                                        boolean showAllItemsInListBox = model.isShowAllItemsInListBox();
1428
                                        String languageRules = model.getLocaleRules();
1429
                                        boolean caseSensitive = model.isCaseSensitive();
1430
                                        ILookUp lookUpAgent = model.getLookUpAgent();
1431
                                        
1432
                                        // Must replace the dataModel for update the data in the popup correctly
1433
                                        comboBoxReference.setModel(new DefaultComboBoxConfigurableLookUpModel(model.getData()));
1434
                                        
1435
                                        // Restores the configuration of the flags
1436
                                        model.setItemsOrder(itemsOrderFlag);
1437
                                        model.setShowAllItemsInListBox(showAllItemsInListBox);
1438
                                        model.setLocaleRules(languageRules);
1439
                                        model.setCaseSensitive(caseSensitive);
1440
                                        model.setLookUpAgent(lookUpAgent);
1441
                                        
1442
                                        // Reset (without text written)
1443
                                        insertString(0, textWritten, null);
1444
                                        
1445
                                        // Insert the new text
1446
                                        textWritten = old_textWritten.substring(0, offset) + text + old_textWritten.substring(offset, old_textWritten.length());
1447
                                        
1448
                                        insertString(0, textWritten, null);
1449

    
1450
                                        updatedModel = false;
1451

    
1452
                                        // Update the color of the text
1453
                                        updateTextColorAndRingBeep();
1454
                                        
1455
                                        // Update the caret position -> at the same place it was or at the end
1456
                                        updateCaretPosition(old_caretPosition);
1457
                                        
1458
                                        // Only show the popup if there are items to show
1459
                                        if (model.getSize() > 0) {
1460
                                                 showPopup();
1461
                                        }
1462
                                        else {
1463
                                                if ((textWritten.compareTo("") != 0) && (!hidePopupIfThereAreNoItems)) {
1464
                                                        showPopup();        
1465
                                                }
1466
                                        }
1467
                                }
1468
                                else {
1469
                                        // Default replacement
1470
                                        super.replace(offset, length, text, attrs);
1471
                                }
1472
                        }
1473
                }
1474
                        
1475
                /*
1476
                 *  (non-Javadoc)
1477
                 * @see javax.swing.text.Document#remove(int, int)
1478
                 */
1479
                public void remove(int offs, int len) throws BadLocationException {
1480
                        String old_textWritten;
1481
                                
1482
                        // There is a bug that when text has been removed, the elements in the popup aren seen.
1483
                        // The solution to this bug is add them as a new dataModel
1484
                        hidePopup();
1485

    
1486
                        updatedModel = true;
1487

    
1488
                        old_textWritten = textWritten;
1489
                        
1490
                        old_caretPosition = Math.min(((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).getCaretPosition(), offs);
1491
                        
1492
                        textWritten = "";
1493
                        model.setTextWritten(textWritten);
1494

    
1495
                        super.remove(0, old_textWritten.length());
1496
                        
1497
                        int itemsOrderFlag = model.getItemsOrder();
1498
                        boolean showAllItemsInListBox = model.isShowAllItemsInListBox();
1499
                        String languageRules = model.getLocaleRules();
1500
                        boolean caseSensitive = model.isCaseSensitive();
1501
                        ILookUp lookUpAgent = model.getLookUpAgent();
1502
                
1503
                        // Must replace the dataModel for update the data in the popup correctly
1504
                        comboBoxReference.setModel(new DefaultComboBoxConfigurableLookUpModel(model.getData()));
1505
                        
1506
                        // Restores the configuration of the flags
1507
                        model.setItemsOrder(itemsOrderFlag);
1508
                        model.setShowAllItemsInListBox(showAllItemsInListBox);
1509
                        model.setLocaleRules(languageRules);
1510
                        model.setCaseSensitive(caseSensitive);
1511
                        model.setLookUpAgent(lookUpAgent);
1512

    
1513
                        // Reset (without text written)
1514
                        insertString(0, textWritten, null);
1515
                        
1516
                        // Insert the new text
1517
                        textWritten = old_textWritten.substring(0, offs) + textOfReplacement + old_textWritten.substring(offs + len, old_textWritten.length());
1518

    
1519
                        insertString(0, textWritten, null);
1520
                        
1521
                        updatedModel = false;
1522
                        
1523
                        // Update the color of the text
1524
                        updateTextColorAndRingBeep();
1525
                        
1526
                        // Only show the popup if there are items to show
1527
                        if (model.getSize() > 0) {
1528
                                 showPopup();
1529
                        }
1530
                        else {
1531
                                if ((textWritten.compareTo("") != 0) && (!hidePopupIfThereAreNoItems)) {
1532
                                        showPopup();        
1533
                                }
1534
                        }
1535
        
1536
//                        if (old_caretPosition == 0) {
1537
//                                // Set the caret position to the end of the text
1538
//                                updateCaretPosition(textWritten.length());
1539
//                        }
1540
//                        else {
1541
                                // Update the caret position -> at the same place it was or at the end
1542
                                updateCaretPosition(old_caretPosition + textOfReplacement.length());
1543
//                        }
1544
                        
1545
                        textOfReplacement = "";
1546
                }
1547

    
1548
                /**
1549
                 * <p>Updates the color of the text in the {@link ComboBoxEditor} of this component, and
1550
                 *  rings a beep if there is no item.</p>
1551
                 * 
1552
                 * <ul>
1553
                 *  <li><i>Text in <u>red color</u></i>: if no item matches with the text written according the <code>ILookUp</code> agent.</li>
1554
                 *  <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>
1555
                 * </ul>
1556
                 */
1557
                public void updateTextColorAndRingBeep() {
1558
                        if (! comboBoxReference.isOnlyOneColorOnText()) {
1559
                                if (model.isShowAllItemsInListBox()) {
1560
                                        // Set text into red color if no items matches with the text written, or in black color if it was in red
1561
                                        //   color and now there is almost one element that starts with the characteres written by the user
1562
                                        if (textWritten.compareTo("") != 0) {
1563
                                                if (model.getSelectedItem() == null) {
1564
                                                        comboBoxReference.getEditor().getEditorComponent().setForeground(Color.RED);
1565
                                                        textInRedColor = true;
1566
                                                                 
1567
                                                                 // Rings a beep if allowed
1568
                                                if (beepEnabled)
1569
                                                        comboBoxReference.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
1570
                                                }
1571
                                                else {
1572
                                                        comboBoxReference.getEditor().getEditorComponent().setForeground(Color.BLACK);
1573
                                                        textInRedColor = false;
1574
                                                }
1575
                                        }
1576
                                        else {
1577
                                                if (textInRedColor) {
1578
                                                        comboBoxReference.getEditor().getEditorComponent().setForeground(Color.BLACK);
1579
                                                        textInRedColor = false;
1580
                                                }
1581
                                        }
1582
                                }
1583
                                else {
1584
                                        // Set text into red color if no items matches with the text written, or in black color if it was in red
1585
                                        //   color and now there is almost one element that starts with the characteres written by the user
1586
                                        if (textWritten.compareTo("") != 0) {
1587
                                                if (model.getSize() == 0) {
1588
                                                        comboBoxReference.getEditor().getEditorComponent().setForeground(Color.RED);
1589
                                                        textInRedColor = true;
1590
                                                                 
1591
                                                                 // Rings a beep if allowed
1592
                                                if (beepEnabled)
1593
                                                        comboBoxReference.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
1594
                                                }
1595
                                                else {
1596
                                                        comboBoxReference.getEditor().getEditorComponent().setForeground(Color.BLACK);
1597
                                                        textInRedColor = false;
1598
                                                }
1599
                                        }
1600
                                        else {
1601
                                                if (textInRedColor) {
1602
                                                        comboBoxReference.getEditor().getEditorComponent().setForeground(Color.BLACK);
1603
                                                        textInRedColor = false;
1604
                                                }
1605
                                        }
1606
                                }
1607
                        }
1608
                        else {
1609
                                // Rings a beep if no there is no item, and if it's allowed
1610
                                if ((textWritten.compareTo("") != 0) && (model.getSize() == 0)) {
1611
                                        if (beepEnabled)
1612
                                                comboBoxReference.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
1613
                                }
1614
                        }
1615
                }
1616
                
1617
                /**
1618
                 * <p>Updates the position of the caret in the {@link ComboBoxEditor} of this component.</p>
1619
                 * 
1620
                 * @param position the new position of the caret.
1621
                 */
1622
                public void updateCaretPosition(int position) {
1623
                        // If user has selected an item of the popup (using the mouse) -> set the caret position to the end of the text
1624
                        if (popupItemSelected) {
1625
                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(textWritten.length());
1626
                                popupItemSelected = false;
1627
                                return;
1628
                        }
1629
                        
1630
                        if (position > textWritten.length())
1631
                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(textWritten.length());
1632
                        else {
1633
                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(position);
1634
                        }
1635
                }
1636

    
1637
                /**
1638
                 * <p>Updates the color of the text in this document.</p>
1639
                 * 
1640
                 * <p>Sets text to red color if there is no item in the visible list that the <i>look up</i> agent
1641
                 *  returned with that text and the items of the dataModel, and, being enabled the second color in
1642
                 *  the configuration the the <code>JcomboBoxConfigurableLookUp</code> agent. Otherwise, the foreground color
1643
                 *  of the text will be black.</p>
1644
                 * 
1645
                 * <p>This method disables the <i>beep</i> during the process of updating the color of the text, and
1646
                 *  restores it after.</p>
1647
                 */
1648
                public void updateOnlyTextColor() {
1649
                        boolean isBeepEnabled = isBeepEnabled();
1650
                        setBeepEnabled(false);
1651
                        
1652
                        updateTextColorAndRingBeep();
1653
                                
1654
                        setBeepEnabled(isBeepEnabled);
1655
                }
1656
        }
1657
}