KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > swingwtx > swing > JComboBox


1 /*
2    SwingWT
3    Copyright(c)2003-2004, R. Rawson-Tetley
4
5    For more information on distributing and using this program, please
6    see the accompanying "COPYING" file.
7
8    Contact me by electronic mail: bobintetley@users.sourceforge.net
9
10    $Log: JComboBox.java,v $
11    Revision 1.36 2004/05/06 00:28:22 laurentmartelli
12     - setSelectedIndex() calls model.setSelectedItem()
13     - handleComboKeyStrokes() does not raise NullPointerException if litems==null
14
15    Revision 1.35 2004/05/05 17:19:39 bobintetley
16    Fix to make JComboBox update the selected item on it's model as the user
17    chooses another item. Removed debug code from Everything demo
18
19    Revision 1.34 2004/05/05 16:46:53 bobintetley
20    JTree rendering fix for collapse/expansion
21
22    Revision 1.33 2004/05/05 16:11:34 bobintetley
23    (Laurent Martelli) JComboBox performance patch
24
25    Revision 1.32 2004/05/05 12:43:21 bobintetley
26    Patches/new files from Laurent Martell
27
28    Revision 1.31 2004/04/30 23:18:26 dannaab
29    List selection support, misc bug fixes
30
31    Revision 1.30 2004/04/28 08:38:11 bobintetley
32    Hierarchy fixes, code cleanup for base classes, additional javadocs and use of flag to identify JComponent descendants with peers
33
34    Revision 1.29 2004/04/19 10:49:37 bobintetley
35    Fix to cell editing with DefaultEditor/JComboBox and fix so JTable/JTree
36    cell renderers are used after editor updates
37
38    Revision 1.28 2004/04/16 14:38:47 bobintetley
39    Table and Tree cell editor support
40
41    Revision 1.27 2004/04/16 10:19:06 dannaab
42    Misc bug fixes, InputMap implementation, preliminary undo support
43
44    Revision 1.26 2004/03/30 10:42:46 bobintetley
45    Many minor bug fixes, event improvements by Dan Naab. Full swing.Icon support
46
47    Revision 1.25 2004/02/20 13:57:01 bobintetley
48    JLookupPopup - A high speed alternative to JComboBox
49
50    Revision 1.24 2004/02/13 15:09:23 bobintetley
51    JComboBox/Abstract button non-peer selection and JTable threading fixed
52
53    Revision 1.23 2004/02/03 09:21:21 bobintetley
54    Fixed threading bug in invokeIn, and JComboBox hotkeys
55
56    Revision 1.22 2004/01/26 09:10:09 bobintetley
57    JComboBox event fixes, fix to Java2D garbage collection and ComboBox demo
58
59    Revision 1.21 2004/01/23 08:04:56 bobintetley
60    JComboBox fixes and better Action implementation
61
62    Revision 1.20 2004/01/16 10:07:28 bobintetley
63    ItemEvent/Listener support for combo
64
65    Revision 1.19 2004/01/08 12:56:30 bobintetley
66    Experiment with hotkeys - unworkable in current SWT
67
68    Revision 1.18 2004/01/04 12:02:41 bobintetley
69    Fix to broken popupMenu events, default values and null data handling
70
71    Revision 1.17 2003/12/17 09:03:14 bobintetley
72    Closely matches Swing behaviour + JScrollPane support for Panels
73
74    Revision 1.16 2003/12/16 17:46:17 bobintetley
75    Additional thread safety methods
76
77    Revision 1.15 2003/12/16 15:47:45 bobintetley
78    Thread safety added to common methods
79
80    Revision 1.14 2003/12/16 13:14:33 bobintetley
81    Use of SwingWTUtils.isSWTControlAvailable instead of null test
82
83    Revision 1.13 2003/12/16 11:01:02 bobintetley
84    Additional Swing compatibility
85
86    Revision 1.12 2003/12/15 18:29:57 bobintetley
87    Changed setParent() method to setSwingWTParent() to avoid conflicts with applications
88
89    Revision 1.11 2003/12/15 17:37:18 bobintetley
90    ComboBox model interfaces and support
91
92    Revision 1.10 2003/12/15 15:53:55 bobintetley
93    maximumRowCount()
94
95    Revision 1.9 2003/12/14 09:13:38 bobintetley
96    Added CVS log to source headers
97
98 */

99
100
101 package swingwtx.swing;
102
103 import swingwtx.swing.event.*;
104 import swingwt.awt.event.*;
105
106 import org.eclipse.swt.events.*;
107 import org.eclipse.swt.widgets.*;
108 import org.eclipse.swt.*;
109
110 import java.util.*;
111
112 public class JComboBox extends swingwtx.swing.JComponent {
113
114     protected Combo ppeer = null;
115     protected String JavaDoc pText = "";
116     protected Vector litems = null;
117     protected int pSelectedIndex = -1;
118     protected int pMaxRows = 8;
119     protected Vector popupListeners = new Vector();
120     protected Vector itemListeners = new Vector();
121     protected Vector changeListeners = new Vector();
122     protected ComboBoxModel model = null;
123
124     /** Used for thread safe property accessor calls */
125     private Object JavaDoc retValue = null;
126
127     /** Used to determine if the combo can be entered into */
128     protected boolean isEditable = false;
129
130     public JComboBox() { litems = new Vector(); }
131
132     public JComboBox(Object JavaDoc[] items) {
133         litems = new Vector();
134         for (int i = 0; i < items.length; i++) {
135             litems.add(items[i]);
136         }
137         if (!isEditable && litems.size() > 0)
138             pSelectedIndex = 0;
139     }
140
141     public JComboBox(Vector items) {
142         litems = items;
143         if (!isEditable && litems != null && litems.size() > 0)
144             pSelectedIndex = 0;
145     }
146
147     public JComboBox(ComboBoxModel model) {
148         this.model = model;
149         copyModel();
150         if (!isEditable && litems != null && litems.size() > 0)
151             pSelectedIndex = 0;
152     }
153
154     protected final static int CANCELED = 0;
155     protected final static int INVISIBLE = 1;
156     protected final static int VISIBLE = 2;
157     
158     public void addChangeListener(ChangeListener l) {
159         changeListeners.add(l);
160     }
161     
162     public void removeChangeListener(ChangeListener l) {
163         changeListeners.remove(l);
164     }
165     
166     public void addPopupMenuListener(PopupMenuListener l) {
167         popupListeners.add(l);
168     }
169
170     public void removePopupMenuListener(PopupMenuListener l) {
171         popupListeners.remove(l);
172     }
173
174     public void addItemListener(ItemListener l) {
175         itemListeners.add(l);
176     }
177
178     public void removeItemListener(ItemListener l) {
179         itemListeners.remove(l);
180     }
181
182     public void processPopupMenuEvent(int id) {
183         Iterator i = popupListeners.iterator();
184         PopupMenuEvent e = new PopupMenuEvent(this);
185         while (i.hasNext()) {
186             PopupMenuListener l = (PopupMenuListener) i.next();
187             switch(id) {
188                 case CANCELED: l.popupMenuCanceled(e); break;
189                 case INVISIBLE: l.popupMenuWillBecomeInvisible(e); break;
190                 case VISIBLE: l.popupMenuWillBecomeVisible(e); break;
191             }
192         }
193     }
194
195     public void processItemEvent(ItemEvent e) {
196         
197     // The model needs to be informed of the new selection
198
if (model != null)
199         model.setSelectedItem(e.getItem());
200             
201         for (int i = 0; i < itemListeners.size(); i++) {
202             ItemListener l = (ItemListener) itemListeners.get(i);
203             l.itemStateChanged(e);
204         }
205     }
206
207     public void processChangeEvent(ChangeEvent e) {
208         for (int i = 0; i < changeListeners.size(); i++) {
209             ChangeListener l = (ChangeListener) changeListeners.get(i);
210             l.stateChanged(e);
211         }
212     }
213     
214
215     /** Handles copying of Combo box models so they can be
216      * handled by SWT
217      */

218     protected void copyModel() {
219         if (model == null) return;
220         litems = new Vector(model.getSize());
221         for (int i = 0; i < model.getSize(); i++) {
222             litems.add(model.getElementAt(i));
223         }
224     }
225
226     public Object JavaDoc getSelectedItem() {
227         retValue = null;
228         SwingUtilities.invokeSync(new Runnable JavaDoc() { public void run() {
229             if (isEditable) {
230                 if (!SwingWTUtils.isSWTControlAvailable(ppeer))
231                     retValue = pText;
232                 else
233                     retValue = ppeer.getText();
234             }
235             else {
236                 if ((!SwingWTUtils.isSWTControlAvailable(ppeer)) && pSelectedIndex > -1)
237                     retValue = litems.get(pSelectedIndex);
238                 else if (SwingWTUtils.isSWTControlAvailable(ppeer))
239                     if (ppeer.getSelectionIndex() != -1)
240                         retValue = litems.get(ppeer.getSelectionIndex());
241             }
242         }});
243         return retValue;
244     }
245
246     public void setSelectedItem(final Object JavaDoc text) {
247         SwingUtilities.invokeSync(new Runnable JavaDoc() {
248             public void run() {
249                 if (isEditable) {
250                     if (!SwingWTUtils.isSWTControlAvailable(ppeer))
251                         pText = text.toString();
252                     else
253                         ppeer.setText(text.toString());
254                 }
255                 else {
256                     // If we are dealing with a String, use a string comparison
257
if (litems != null) {
258                         if (text instanceof String JavaDoc) {
259                             Object JavaDoc[] itm = litems.toArray();
260                             for (int i = 0; i < itm.length; i++)
261                                  if (itm[i].toString().equals(text.toString())) {
262                                     setSelectedIndex(i);
263                                     break;
264                                 }
265                         }
266                         else {
267                             // Object comparison
268
int index = litems.indexOf(text);
269                             if (index != -1) setSelectedIndex(index);
270                         }
271             }
272                 }
273             }
274         });
275     }
276
277     public ComboBoxModel getModel() { return model; }
278     public void setModel(ComboBoxModel model) {
279         this.model = model;
280         copyModel();
281         if (SwingWTUtils.isSWTControlAvailable(ppeer)) {
282         String JavaDoc[] items = new String JavaDoc[litems.size()];
283         for (int i=0; i < litems.size(); i++) {
284         Object JavaDoc o = litems.get(i);
285         items[i] = o == null ? "" : o.toString();
286         }
287         ppeer.setItems(items);
288         }
289     }
290
291     public void addItem(final Object JavaDoc item) {
292         if (litems == null)
293             litems = new Vector();
294         litems.add(item);
295
296         SwingUtilities.invokeSync(new Runnable JavaDoc() {
297             public void run() {
298                 if (SwingWTUtils.isSWTControlAvailable(ppeer))
299                     ppeer.add(item.toString());
300             }
301         });
302
303     }
304
305     public void insertItemAt(final Object JavaDoc item, final int index) {
306         if (litems == null)
307             litems = new Vector();
308         litems.add(index, item);
309         SwingUtilities.invokeSync(new Runnable JavaDoc() {
310             public void run() {
311                 if (SwingWTUtils.isSWTControlAvailable(ppeer))
312                     ppeer.add(item.toString(), index);
313             }
314         });
315     }
316
317     public int getSelectedIndex() {
318         retValue = null;
319         SwingUtilities.invokeSync(new Runnable JavaDoc() {
320             public void run() {
321                 if (!SwingWTUtils.isSWTControlAvailable(ppeer))
322                     retValue = new Integer JavaDoc(pSelectedIndex);
323                 else
324                     retValue = new Integer JavaDoc(ppeer.getSelectionIndex());
325             }
326         });
327         return ((Integer JavaDoc) retValue).intValue();
328     }
329
330     public Object JavaDoc getItemAt(int index) {
331         if (index == -1)
332             return null;
333         return litems.get(index);
334     }
335     
336     public swingwt.awt.Component getComponent(int n) {
337         return this;
338     }
339
340     public int getItemCount() {
341         return litems.size();
342     }
343
344     public void setSelectedIndex(final int index) {
345         final JComboBox me = this;
346         if (model!=null) {
347             if (index!=-1)
348                 model.setSelectedItem(model.getElementAt(index));
349             else
350                 model.setSelectedItem(null);
351         }
352         SwingUtilities.invokeSync(new Runnable JavaDoc() {
353             public void run() {
354                 if (!SwingWTUtils.isSWTControlAvailable(ppeer))
355                     pSelectedIndex = index;
356                 else {
357                     ppeer.select(index);
358                     processActionEvent(0);
359                     ItemEvent ie = new ItemEvent(me, 0, getSelectedItem(), ItemEvent.SELECTED);
360                     processItemEvent(ie);
361                 }
362             }
363         });
364     }
365
366     public void removeAllItems() {
367         if (litems != null)
368             litems.removeAllElements();
369         SwingUtilities.invokeSync(new Runnable JavaDoc() {
370             public void run() {
371                 if (SwingWTUtils.isSWTControlAvailable(ppeer))
372                     ppeer.removeAll();
373             }
374         });
375     }
376
377     public void removeItem(final Object JavaDoc item) {
378         litems.remove(item);
379         SwingUtilities.invokeSync(new Runnable JavaDoc() {
380             public void run() {
381                 if (SwingWTUtils.isSWTControlAvailable(ppeer))
382                     ppeer.remove(item.toString());
383             }
384         });
385     }
386
387     public void removeItemAt(final int index) {
388         litems.remove(index);
389         SwingUtilities.invokeSync(new Runnable JavaDoc() {
390             public void run() {
391                 if (SwingWTUtils.isSWTControlAvailable(ppeer))
392                     ppeer.remove(index);
393             }
394         });
395     }
396
397     public void setEditable(boolean b) {
398         isEditable = b;
399     }
400
401     public boolean getEditable() {
402         return isEditable;
403     }
404
405     public int getMaximumRowCount() {
406         return pMaxRows;
407     }
408     public void setMaximumRowCount(int max) {
409         pMaxRows = max;
410     }
411
412     /**
413      * Once a parent component receives an "add" call for a child, this being
414      * the child, this should be called to tell us to instantiate the peer
415      * and load in any cached properties.
416      */

417     public void setSwingWTParent(swingwt.awt.Container parent) throws Exception JavaDoc {
418         descendantHasPeer = true;
419         ppeer = new Combo(parent.getComposite(), SWT.BORDER | SWT.DROP_DOWN );
420         
421         if (litems != null) {
422         String JavaDoc[] items = new String JavaDoc[litems.size()];
423         for (int i=0; i < litems.size(); i++) {
424         Object JavaDoc o = litems.get(i);
425         items[i] = o == null ? "" : o.toString();
426         }
427         ppeer.setItems(items);
428         }
429         
430         if (pSelectedIndex != -1)
431             ppeer.select(pSelectedIndex);
432
433             // Real Swing combos default to the first item if none are selected
434
else if (litems != null && litems.size() > 0) {
435             pSelectedIndex = 0;
436             ppeer.select(0);
437         }
438         // If the combo is editable, default the text supplied if we have some
439
if (isEditable)
440             if (!pText.equals(""))
441                 ppeer.setText(pText);
442
443         peer = ppeer;
444         this.parent = parent;
445
446         registerComboEvents();
447     }
448
449     protected void registerComboEvents() {
450
451         final JComboBox me = this;
452
453         // Popup menu event mapped listener
454
ppeer.addModifyListener(new ModifyListener() {
455             public void modifyText(ModifyEvent e) {
456                 // Only fire when the text is changed
457
if (ppeer.getSelectionIndex() != -1) {
458                     processPopupMenuEvent(INVISIBLE);
459                     processPopupMenuEvent(VISIBLE);
460                     processPopupMenuEvent(CANCELED);
461                 }
462             }
463         });
464
465         // Selection changed
466
ppeer.addSelectionListener(new SelectionAdapter() {
467             public void widgetSelected(SelectionEvent e) {
468                 ItemEvent ie = new ItemEvent(me, 0, getSelectedItem(), ItemEvent.SELECTED);
469                 processItemEvent(ie);
470                 ChangeEvent ce = new ChangeEvent(me);
471                 processChangeEvent(ce);
472                 processActionEvent(0); // Fire an action event when selection changes
473
}
474         });
475
476         // Changing selection on key strokes for non-editable combos
477
handleComboKeyStrokes();
478
479     }
480
481     /**
482      * This routine will add the key handlers necessary for searching
483      * through combos by the key pressed (as Windows does, and as Swing does).
484      *
485      * This code really isn't too pretty, as SWT deactivates the key events if
486      * SWT.READ_ONLY is specified, so I have to handle that too, also you
487      * can't consume KeyEvents under a Combo (must be a bug), so I use a timer
488      * over the event pump to reset values. As I say, it's dirty but it works.
489      *
490      * @author Robin Rawson-Tetley
491      */

492     protected void handleComboKeyStrokes() {
493
494         // If the combo isn't editable, then set up hot keys to search the list
495
// when the user presses a key. I can't BELIEVE I have to frigging code this
496
// and SWT doesn't do this anyway!
497

498         if (isEditable) return;
499
500         ppeer.addKeyListener(new org.eclipse.swt.events.KeyAdapter() {
501             public void keyPressed(org.eclipse.swt.events.KeyEvent e) {
502
503                 // Cancel the keystroke -- maybe one day it will work...
504
e.doit = false;
505
506                 // If ALT or CTRL is pressed, ignore this code.
507
if ( ((e.stateMask & SWT.ALT) > 0) ||
508                      ((e.stateMask & SWT.CTRL) > 0) ) return;
509
510                 // See what's already selected - this way we can cycle
511
// up the list like Swing does.
512
int currentlySelected = getSelectedIndex();
513
514                 // The current character we are dealing with
515
String JavaDoc curChar = "";
516         String JavaDoc selected = "";
517         
518                 if (currentlySelected != -1)
519             selected = getSelectedItem().toString();
520         
521                 if (currentlySelected != -1 && selected.length() > 0)
522                     curChar = selected.substring(0, 1).toLowerCase();
523
524                 boolean foundMatch = false;
525
526                 if (litems!=null) {
527                     for (int i = 0; i < litems.size(); i++) {
528                         String JavaDoc s = litems.get(i).toString();
529                         // This item start with the same letter?
530
if ( s.length() > 0 &&
531                              s.substring(0, 1).toLowerCase().equals(new String JavaDoc(new char[] { e.character }).toLowerCase()) )
532                         {
533
534                             // Was the last keystroke on this letter? If so, the index must be higher
535
if (curChar.equals(new String JavaDoc(new char[] { e.character }).toLowerCase()))
536                                 i = currentlySelected + 1;
537
538                             // If we've run out of letters, don't do anything
539
if (i >= litems.size())
540                                 break;
541
542                             // Now that we've moved the match up, make sure the letters still
543
// match - if they don't, then we've gone too far - don't do
544
// anything
545
if (!litems.get(i).toString().substring(0, 1).toLowerCase().equals(new String JavaDoc(new char[] { e.character }).toLowerCase()))
546                                 break;
547
548                             foundMatch = true;
549
550                             // Because we can't cancel the keystroke, we let it
551
// go and then change the value again afterwards - thanks SWT!
552
final int matchedIndex = i;
553                             SwingUtilities.invokeIn(new Runnable JavaDoc() {
554                                     public void run() {
555                                         setSelectedItem(litems.get(matchedIndex));
556                                     }
557                                 }, 1);
558                             break;
559
560                         }
561                     }
562                 }
563
564                 // We didn't find one, reassert the current value to overwrite
565
// the keystroke.
566
if (!foundMatch) {
567                     final Object JavaDoc selItem = getSelectedItem();
568                     SwingUtilities.invokeIn(new Runnable JavaDoc() {
569                         public void run() {
570                             setSelectedItem(selItem);
571                         }
572                     }, 1);
573                 }
574
575             }
576         });
577
578     }
579
580 }
581
Popular Tags