Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libUI / src / org / gvsig / gui / beans / swing / jComboBoxItemsSeeker / services / JComboBoxSearchURLOfServices.java @ 11620

History | View | Annotate | Download (17 KB)

1 11620 ppiqueras
package org.gvsig.gui.beans.swing.jComboBoxItemsSeeker.services;
2
3
import java.awt.event.FocusAdapter;
4
import java.awt.event.FocusEvent;
5
import java.awt.event.FocusListener;
6
import java.awt.event.KeyAdapter;
7
import java.awt.event.KeyEvent;
8
import java.awt.event.KeyListener;
9
import java.awt.event.MouseAdapter;
10
import java.awt.event.MouseEvent;
11
import java.util.Vector;
12
13
import javax.accessibility.Accessible;
14
import javax.swing.ComboBoxEditor;
15
import javax.swing.ComboBoxModel;
16
import javax.swing.JComboBox;
17
import javax.swing.JList;
18
import javax.swing.event.PopupMenuListener;
19
import javax.swing.plaf.basic.BasicComboBoxUI;
20
import javax.swing.plaf.basic.ComboPopup;
21
import javax.swing.text.AttributeSet;
22
import javax.swing.text.BadLocationException;
23
import javax.swing.text.JTextComponent;
24
import javax.swing.text.PlainDocument;
25
26
import org.gvsig.gui.beans.swing.jComboBoxItemsSeeker.models.DefaultComboBoxModelOrderedSearch;
27
28
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
29
 *
30
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
31
 *
32
 * This program is free software; you can redistribute it and/or
33
 * modify it under the terms of the GNU General Public License
34
 * as published by the Free Software Foundation; either version 2
35
 * of the License, or (at your option) any later version.
36
 *
37
 * This program is distributed in the hope that it will be useful,
38
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
39
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
40
 * GNU General Public License for more details.
41
 *
42
 * You should have received a copy of the GNU General Public License
43
 * along with this program; if not, write to the Free Software
44
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
45
 *
46
 * For more information, contact:
47
 *
48
 *  Generalitat Valenciana
49
 *   Conselleria d'Infraestructures i Transport
50
 *   Av. Blasco Ib??ez, 50
51
 *   46010 VALENCIA
52
 *   SPAIN
53
 *
54
 *      +34 963862235
55
 *   gvsig@gva.es
56
 *      www.gvsig.gva.es
57
 *
58
 *    or
59
 *
60
 *   IVER T.I. S.A
61
 *   Salamanca 50
62
 *   46005 Valencia
63
 *   Spain
64
 *
65
 *   +34 963163400
66
 *   dac@iver.es
67
 */
68
69
/**
70
 * This class will have the necessary behavior for the combo box with URL of services:<br>
71
 *
72
 * <ul>
73
 * <li>All items will be sorted</li>
74
 * <li>Allows repeated items</li>
75
 * <li>Finds all items that their first characters are the written by the user</li>
76
 * <li>If no item has its first characters as the written by the user -> don't show the popup</li>
77
 * <li>Similar behaviour as the Mozilla Firefox URL combo box</li>
78
 * </ul>
79
 *
80
 * @author Pablo Piqueras Bartolom? (p_queras@hotmail.com)
81
 */
82
public class JComboBoxSearchURLOfServices extends JComboBox implements java.io.Serializable {
83
        private static final long serialVersionUID = -6928118339485676552L;
84
85
        // EDITOR DOCUMENT REFERENCE
86
        /**
87
         * A reference to the document of this component
88
         */
89
        private PlainDocumentTextFormatter document;
90
        // END EDITOR DOCUMENT REFERENCE
91
92
        // NEW ATTRIBUTES
93
        /**
94
         * A reference to the model of this component (according to the MVC <i>(Model-View-Controller)</i> pattern)
95
         */
96
        private DefaultComboBoxModelOrderedSearch model;
97
98
        /**
99
         * Has or not to hide the popup on focus loss
100
         */
101
        private boolean hidePopupOnFocusLoss;
102
103
        /**
104
         * Has an item of the popup been selected or not by the user
105
         */
106
        private boolean popupItemSelected;
107
        // END NEW ATTRIBUTES
108
109
        // LISTENERS
110
        /**
111
         * Listener for the editor key
112
         */
113
        private KeyListener editorKeyListener;
114
115
        /**
116
         * Listener for the editor focus
117
         */
118
        private FocusListener editorFocusListener;
119
120
        /**
121
         * Listener for the popup menu
122
         */
123
        private PopupMenuListener popupMenuListener;
124
        // END LISTENERS
125
126
        /**
127
         * Default constructor without parameters
128
         */
129
        public JComboBoxSearchURLOfServices() {
130
                super();
131
                initialize();
132
        }
133
134
        /**
135
         * Default constructor with a {@link ComboBoxModel} as parameter
136
         *
137
         * @param aModel javax.swing.ComboBoxModel
138
         */
139
        public JComboBoxSearchURLOfServices(ComboBoxModel aModel) {
140
                super(aModel);
141
                initialize();
142
        }
143
144
        /**
145
         * Default constructor with an array of objects as parameter
146
         *
147
         * @param items An array of objects. All them must implement a <i>'String toStrin()'</i> method
148
         */
149
        public JComboBoxSearchURLOfServices(Object[] items) {
150
                super(items);
151
                initialize();
152
        }
153
154
        /**
155
         * Default constructor with a Vector of objects as parameter
156
         *
157
         * @param items A {@link Vector} of objects. All them must implement a <i>'String toStrin()'</i> method
158
         */
159
        public JComboBoxSearchURLOfServices(Vector items) {
160
                super(items);
161
                initialize();
162
        }
163
164
        /**
165
         * This method sets the start values of inner attributes and creates the necessary inner objects
166
         */
167
        private void initialize() {
168
                // By default user hasn't selected an item of the popup
169
                popupItemSelected = false;
170
171
                // Creates the model for this component and gets it reference
172
                model = new DefaultComboBoxModelOrderedSearch();
173
                super.setModel(model);
174
175
        // Allows user to edit on the combobox
176
                super.setEditable(true);
177
178
                // Other configuration tasks
179
                this.configure();
180
181
                // If there are items -> select the first
182
                if (model.getSize() > 0)
183
                        model.setSelectedItem(model.getElementAt(0));
184
        }
185
186
        /**
187
         * Configures the component and some of its elements
188
         */
189
        private void configure() {
190
        // Defines a key listener for the editor of this component
191
        this.defineEditorKeyListener(this);
192
193
        // Defines a focus listener for the editor of this component
194
        this.defineEditorFocusListener(this);
195
196
                // Configures the document of the editor of this component
197
                this.configureDocument();
198
199
                // Configures the editor (ComboBoxEditor) of this component
200
                this.configureEditor(this.getEditor());
201
202
                // Configures the popup of this component
203
                this.configurePopUp(this);
204
        }
205
206
        /**
207
         * Configures the editor ( {@link ComboBoxEditor} ) of this component
208
         *
209
         * @param newEditor The new editor to configure
210
         */
211
        private void configureEditor(ComboBoxEditor newEditor) {
212
        if (newEditor != null) {
213
                   JTextComponent jTextComponentOfEditor = (JTextComponent) newEditor.getEditorComponent();
214
215
                // Adds the new document (tries to remove it if it existed before)
216
                jTextComponentOfEditor.setDocument(this.document);
217
218
                // Adds the new Key Listener (tries to remove it if it existed before)
219
                   jTextComponentOfEditor.removeKeyListener(this.editorKeyListener);
220
                jTextComponentOfEditor.addKeyListener(this.editorKeyListener);
221
222
                // Adds the new Focus Listener (tries to remove it if it existed before)
223
                jTextComponentOfEditor.removeFocusListener(this.editorFocusListener);
224
                jTextComponentOfEditor.addFocusListener(this.editorFocusListener);
225
        }
226
        }
227
228
        /**
229
         * Configures the document of the editor of this component
230
         */
231
        private void configureDocument() {
232
                // Creates the document of the editor of this component
233
        document = new PlainDocumentTextFormatter();
234
235
        // Set reference to the container component
236
        document.setJComboBoxReference(this);
237
        }
238
239
        /**
240
         * Configures the popup of this component
241
         *
242
         * @param combo_Box A reference of this component
243
         */
244
        private void configurePopUp(JComboBoxSearchURLOfServices combo_Box) {
245
                final JComboBoxSearchURLOfServices comboBoxReference = combo_Box;
246
                this.addPopupMenuListener(this.popupMenuListener);
247
248
        BasicComboBoxUI comboBoxUi = (BasicComboBoxUI)comboBoxReference.getUI();
249
        Accessible a = comboBoxUi.getAccessibleChild(comboBoxReference, 0);
250
        if (a instanceof ComboPopup) {
251
            JList jlist = ((ComboPopup)a).getList();
252
253
            jlist.addMouseListener(new MouseAdapter() {
254
                                /*
255
                                 *  (non-Javadoc)
256
                                 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
257
                                 */
258
                                public void mousePressed(MouseEvent e) {
259
                                        // User selects an item of the popup using the mouse
260
                                        popupItemSelected = true;
261
                                }
262
            });
263
        }
264
        }
265
266
        /**
267
         * Defines a key listener for the editor of this component
268
         * This method is another important difference from the JComboBox; and could work badly with some keymaps
269
         *
270
         * @param combo_Box A reference of this component
271
         */
272
        private void defineEditorKeyListener(JComboBoxSearchURLOfServices combo_Box) {
273
                final JComboBoxSearchURLOfServices comboBoxReference = combo_Box;
274
275
                editorKeyListener = new KeyAdapter() {
276
                        /*
277
                         * (non-Javadoc)
278
                         * @see java.awt.event.KeyAdapter#keyPressed(java.awt.event.KeyEvent)
279
                         */
280
                        public void keyPressed(KeyEvent ke)  // Executed on the Start view state or Search view state
281
                        {
282
                                // According the key pressed, do some actions or others
283
                                switch (ke.getKeyCode())
284
                                {
285
                                        case KeyEvent.VK_ENTER :
286
                                                // Don't allow execute the default instructions because they have a bug (first time we remove some characteres, no item will be displayed in the popup)
287
                                                ke.consume();
288
289
                                                // Hide the popup
290
                                                hidePopup();
291
292
                                                // Sets the caret position of the text in the document to the end:
293
                                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(document.getLength());
294
                                                break;
295
296
                                        case KeyEvent.VK_UP: case KeyEvent.VK_DOWN:
297
                                                // User selects an item of the popup using the mouse
298
                                                popupItemSelected = true;
299
                                                break;
300
                                }
301
                        }
302
                };
303
        }
304
305
        /**
306
         * Defines a focus listener for the editor of this component
307
         *
308
         * @param combo_Box A reference of this component
309
         */
310
        private void defineEditorFocusListener(JComboBoxSearchURLOfServices combo_Box) {
311
                final JComboBoxSearchURLOfServices comboBoxReference = combo_Box;
312
313
                // Bug 5100422 on Java 1.5: Editable JComboBox won't hide popup when tabbing out
314
                hidePopupOnFocusLoss=System.getProperty("java.version").startsWith("1.5");
315
316
                // Highlight whole text when gaining focus
317
                editorFocusListener = new FocusAdapter() {
318
319
                        /*
320
                         *  (non-Javadoc)
321
                         * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
322
                         */
323
                        public void focusLost(FocusEvent e) {
324
                                // Workaround for Bug 5100422 - Hide Popup on focus loss
325
                                if (hidePopupOnFocusLoss)
326
                                        comboBoxReference.setPopupVisible(false);
327
                        }
328
                };
329
        }
330
331
        /**
332
         * 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
333
         * This class is also optimized for items seek
334
         *
335
         * @author Pablo Piqueras Bartolom? (p_queras@hotmail.com)
336
         */
337
        private class PlainDocumentTextFormatter extends PlainDocument {
338
                private static final long serialVersionUID = 4158213349939840209L;
339
                private JComboBoxSearchURLOfServices comboBoxReference;
340
                private String textWritten;
341
                private boolean updatedModel;
342
                private String textOfReplacement;
343
                private int old_caretPosition;
344
345
                /**
346
                 * Default Constructor
347
                 */
348
                public PlainDocumentTextFormatter() {
349
                        super();
350
                        this.initialize();
351
                }
352
353
                /**
354
                 * This method makes some initialize operations
355
                 */
356
                private void initialize() {
357
                        textWritten = "";
358
                        textOfReplacement = "";
359
                }
360
361
                /**
362
                 * Sets a reference of this component
363
                 *
364
                 * @param combo_Box A reference to the class that contains this.
365
                 */
366
                private void setJComboBoxReference(JComboBoxSearchURLOfServices combo_Box) {
367
                        comboBoxReference = combo_Box;
368
                }
369
370
                /*
371
                 *  (non-Javadoc)
372
                 * @see javax.swing.text.Document#insertString(int, java.lang.String, javax.swing.text.AttributeSet)
373
                 */
374
            public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
375
                    if (updatedModel) {
376
                            model.setTextWritten(textWritten);
377
                            super.insertString(offs, textWritten, a);
378
379
                            return;
380
                    }
381
382
                    hidePopup();
383
384
                    if (textWritten.length() > 0) {
385
                            if (offs < textWritten.length()) {
386
                                    String old_textWritten = textWritten;
387
388
                                    // End of the text
389
                                    textWritten = textWritten.substring(offs, textWritten.length());
390
391
                                    // Beginning of the text
392
                                    if (offs > 0) {
393
                                        // Reset (without text written)
394
                                            textWritten = old_textWritten.substring(0, offs) + str + textWritten;
395
                                    }
396
                                    else {
397
                                            textWritten = str + textWritten;
398
                                    }
399
                            }
400
                            else {
401
                                    textWritten = textWritten.substring(0, offs) + str;
402
                            }
403
                    }
404
                    else {
405
                            textWritten =  str;
406
                    }
407
408
                    model.setTextWritten(textWritten);
409
410
                    super.insertString(offs, str, a);
411
412
                    // Only show the popup if there are items to show
413
                    if (model.getSize() > 0) {
414
                            showPopup();
415
                    }
416
417
                    // Update the caret position -> at the same place it was or at the end
418
                    updateCaretPosition(textWritten.length());
419
            }
420
421
            /*
422
             *  (non-Javadoc)
423
             * @see javax.swing.text.AbstractDocument#replace(int, int, java.lang.String, javax.swing.text.AttributeSet)
424
             */
425
            public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
426
                    // Avoid two replaces for the same operation
427
                    if ((text.compareTo("") == 0) && (length == textWritten.length()))
428
                            return;
429
430
                    // Only remove if there is text to be replaced (text selected)
431
                    if (length > 0) {
432
                            textOfReplacement = text;
433
                            remove(offset, length);
434
                    }
435
                    else {
436
                            if ((offset > 0) && (offset != textWritten.length())) {
437
                                    // Must replace the model for update the data in the popup correctly
438
                                    String old_textWritten;
439
440
                                // There is a bug that when text has been removed, the elements in the popup aren seen.
441
                                // The solution to this bug is add them as a new model
442
                                hidePopup();
443
444
                                updatedModel = true;
445
446
                                old_textWritten = textWritten;
447
                                old_caretPosition = ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).getCaretPosition() + text.length();
448
449
                                textWritten = "";
450
                                model.setTextWritten(textWritten);
451
452
                                super.remove(0, old_textWritten.length());
453
454
                                // Must replace the model for update the data in the popup correctly
455
                                model = new DefaultComboBoxModelOrderedSearch(model.getData());
456
                                comboBoxReference.setModel(model);
457
458
                                // Reset (without text written)
459
                                insertString(0, textWritten, null);
460
461
                                // Insert the new text
462
                                textWritten = old_textWritten.substring(0, offset) + text + old_textWritten.substring(offset, old_textWritten.length());
463
464
                                insertString(0, textWritten, null);
465
466
                                updatedModel = false;
467
468
                                // Update the caret position -> at the same place it was or at the end
469
                                updateCaretPosition(old_caretPosition);
470
471
                                // Only show the popup if there are items to show
472
                                if (model.getSize() > 0) {
473
                                        showPopup();
474
                                }
475
                            }
476
                            else {
477
                                    // Default replacement
478
                                    super.replace(offset, length, text, attrs);
479
                            }
480
                    }
481
            }
482
483
                /*
484
                 *  (non-Javadoc)
485
                 * @see javax.swing.text.Document#remove(int, int)
486
                 */
487
                public void remove(int offs, int len) throws BadLocationException {
488
                        String old_textWritten;
489
490
                    // There is a bug that when text has been removed, the elements in the popup aren seen.
491
                    // The solution to this bug is add them as a new model
492
                    hidePopup();
493
494
                    updatedModel = true;
495
496
                    old_textWritten = textWritten;
497
                    old_caretPosition = Math.min(((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).getCaretPosition(), offs);
498
499
                    textWritten = "";
500
                    model.setTextWritten(textWritten);
501
502
                    super.remove(0, old_textWritten.length());
503
504
                    // Must replace the model for update the data in the popup correctly
505
                    model = new DefaultComboBoxModelOrderedSearch(model.getData());
506
                    comboBoxReference.setModel(model);
507
508
                    // Reset (without text written)
509
                    insertString(0, textWritten, null);
510
511
                    // Insert the new text
512
                    textWritten = old_textWritten.substring(0, offs) + textOfReplacement + old_textWritten.substring(offs + len, old_textWritten.length());
513
                    textOfReplacement = "";
514
515
                    insertString(0, textWritten, null);
516
517
                    updatedModel = false;
518
519
                    // Only show the popup if there are items to show
520
                    if (model.getSize() > 0) {
521
                            showPopup();
522
                    }
523
524
                    // Update the caret position -> at the same place it was or at the end
525
                    updateCaretPosition(old_caretPosition);
526
                }
527
528
                /**
529
                 * Updates the position of the caret in the {@link ComboBoxEditor} of this component.
530
                 *
531
                 * @param position The new position of the caret.
532
                 */
533
                private void updateCaretPosition(int position) {
534
                        // If user has selected an item of the popup (using the mouse) -> set the caret position to the end of the text
535
                        if (popupItemSelected) {
536
                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(textWritten.length());
537
                                popupItemSelected = false;
538
                                return;
539
                        }
540
541
                        if (position > textWritten.length())
542
                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(textWritten.length());
543
                        else
544
                                ((JTextComponent) comboBoxReference.getEditor().getEditorComponent()).setCaretPosition(position);
545
                }
546
        }
547
}