60 |
import javax.swing.event.PopupMenuListener; |
import javax.swing.event.PopupMenuListener; |
61 |
import javax.swing.plaf.ComboBoxUI; |
import javax.swing.plaf.ComboBoxUI; |
62 |
|
|
|
|
|
63 |
/** |
/** |
64 |
* JComboBox. JComboBox is a container, that keeps track of elements added to |
* JComboBox. JComboBox is a container, that keeps track of elements added to |
65 |
* it by the user. JComboBox allows user to select any item in its list and |
* it by the user. JComboBox allows user to select any item in its list and |
68 |
* |
* |
69 |
* @author Andrew Selkirk |
* @author Andrew Selkirk |
70 |
* @author Olga Rodimina |
* @author Olga Rodimina |
71 |
|
* @author Robert Schuster |
72 |
*/ |
*/ |
73 |
public class JComboBox extends JComponent implements ItemSelectable, |
public class JComboBox extends JComponent implements ItemSelectable, |
74 |
ListDataListener, |
ListDataListener, |
75 |
ActionListener, |
ActionListener, |
76 |
Accessible |
Accessible |
77 |
{ |
{ |
78 |
|
|
79 |
private static final long serialVersionUID = 5654585963292734470L; |
private static final long serialVersionUID = 5654585963292734470L; |
80 |
|
|
81 |
/** |
/** |
144 |
protected ListCellRenderer renderer; |
protected ListCellRenderer renderer; |
145 |
|
|
146 |
/** |
/** |
147 |
* editor that is responsible for editting an object in a combo box list |
* Editor that is responsible for editing an object in a combo box list. |
148 |
*/ |
*/ |
149 |
protected ComboBoxEditor editor; |
protected ComboBoxEditor editor; |
150 |
|
|
192 |
private Object prototypeDisplayValue; |
private Object prototypeDisplayValue; |
193 |
|
|
194 |
/** |
/** |
195 |
* Constructs JComboBox object with specified data model for it. The first |
* Constructs JComboBox object with specified data model for it. |
196 |
* item in the specified data model is selected by default. |
* <p>Note that the JComboBox will not change the value that |
197 |
|
* is preselected by your ComboBoxModel implementation.</p> |
198 |
* |
* |
199 |
* @param model Data model that will be used by this JComboBox to keep track |
* @param model Data model that will be used by this JComboBox to keep track |
200 |
* of its list of items. |
* of its list of items. |
207 |
setModel(model); |
setModel(model); |
208 |
setActionCommand("comboBoxChanged"); |
setActionCommand("comboBoxChanged"); |
209 |
|
|
|
// by default set selected item to the first element in the combo box |
|
|
if (getItemCount() != 0) |
|
|
setSelectedItem(getItemAt(0)); |
|
|
|
|
210 |
lightWeightPopupEnabled = true; |
lightWeightPopupEnabled = true; |
211 |
isEditable = false; |
isEditable = false; |
212 |
|
|
320 |
*/ |
*/ |
321 |
public void setModel(ComboBoxModel newDataModel) |
public void setModel(ComboBoxModel newDataModel) |
322 |
{ |
{ |
|
if (this.dataModel == newDataModel) |
|
|
return; |
|
323 |
|
|
324 |
if (this.dataModel != null) |
// dataModel is null if it this method is called from inside the constructors. |
325 |
// remove all listeners currently registered with the model. |
if(dataModel != null) { |
326 |
dataModel.removeListDataListener(this); |
// Prevents unneccessary updates. |
327 |
|
if (dataModel == newDataModel) |
328 |
ComboBoxModel oldDataModel = this.dataModel; |
return; |
329 |
this.dataModel = newDataModel; |
|
330 |
|
// Removes itself (as DataListener) from the to-be-replaced model. |
331 |
if (this.dataModel != null) |
dataModel.removeListDataListener(this); |
332 |
// register all listeners with the new data model |
} |
333 |
dataModel.addListDataListener(this); |
|
334 |
|
/* Adds itself as a DataListener to the new model. |
335 |
|
* It is intentioned that this operation will fail with a NullPointerException if the |
336 |
|
* caller delivered a null argument. |
337 |
|
*/ |
338 |
|
newDataModel.addListDataListener(this); |
339 |
|
|
340 |
|
// Stores old data model for event notification. |
341 |
|
ComboBoxModel oldDataModel = dataModel; |
342 |
|
dataModel = newDataModel; |
343 |
|
|
344 |
firePropertyChange(MODEL_CHANGED_PROPERTY, oldDataModel, this.dataModel); |
// Notifies the listeners of the model change. |
345 |
|
firePropertyChange(MODEL_CHANGED_PROPERTY, oldDataModel, dataModel); |
346 |
} |
} |
347 |
|
|
348 |
/** |
/** |
357 |
|
|
358 |
/** |
/** |
359 |
* This method sets JComboBox's popup to be either lightweight or |
* This method sets JComboBox's popup to be either lightweight or |
360 |
* heavyweight. If 'enabled' is true then lightweight popup is used and |
* heavyweight. If 'enabled' is true then lightweight popup is used and |
361 |
* heavyweight otherwise. By default lightweight popup is used to display |
* heavyweight otherwise. By default lightweight popup is used to display |
362 |
* this JComboBox's elements. |
* this JComboBox's elements. |
363 |
* |
* |
364 |
* @param enabled indicates if lightweight popup or heavyweight popup should |
* @param enabled indicates if lightweight popup or heavyweight popup should |
366 |
*/ |
*/ |
367 |
public void setLightWeightPopupEnabled(boolean enabled) |
public void setLightWeightPopupEnabled(boolean enabled) |
368 |
{ |
{ |
369 |
this.lightWeightPopupEnabled = enabled; |
lightWeightPopupEnabled = enabled; |
370 |
} |
} |
371 |
|
|
372 |
/** |
/** |
394 |
*/ |
*/ |
395 |
public void setEditable(boolean editable) |
public void setEditable(boolean editable) |
396 |
{ |
{ |
397 |
if (this.isEditable != editable) |
if (isEditable != editable) |
398 |
{ |
{ |
399 |
this.isEditable = editable; |
isEditable = editable; |
400 |
firePropertyChange(EDITABLE_CHANGED_PROPERTY, ! isEditable, isEditable); |
firePropertyChange(EDITABLE_CHANGED_PROPERTY, ! isEditable, isEditable); |
401 |
} |
} |
402 |
} |
} |
413 |
{ |
{ |
414 |
if (maximumRowCount != rowCount) |
if (maximumRowCount != rowCount) |
415 |
{ |
{ |
416 |
int oldMaximumRowCount = this.maximumRowCount; |
int oldMaximumRowCount = maximumRowCount; |
417 |
this.maximumRowCount = rowCount; |
maximumRowCount = rowCount; |
418 |
firePropertyChange(MAXIMUM_ROW_COUNT_CHANGED_PROPERTY, |
firePropertyChange(MAXIMUM_ROW_COUNT_CHANGED_PROPERTY, |
419 |
oldMaximumRowCount, this.maximumRowCount); |
oldMaximumRowCount, maximumRowCount); |
420 |
} |
} |
421 |
} |
} |
422 |
|
|
443 |
*/ |
*/ |
444 |
public void setRenderer(ListCellRenderer aRenderer) |
public void setRenderer(ListCellRenderer aRenderer) |
445 |
{ |
{ |
446 |
if (this.renderer != aRenderer) |
if (renderer != aRenderer) |
447 |
{ |
{ |
448 |
ListCellRenderer oldRenderer = this.renderer; |
ListCellRenderer oldRenderer = renderer; |
449 |
this.renderer = aRenderer; |
renderer = aRenderer; |
450 |
firePropertyChange(RENDERER_CHANGED_PROPERTY, oldRenderer, |
firePropertyChange(RENDERER_CHANGED_PROPERTY, oldRenderer, |
451 |
this.renderer); |
renderer); |
452 |
} |
} |
453 |
} |
} |
454 |
|
|
487 |
} |
} |
488 |
|
|
489 |
/** |
/** |
490 |
* Returns editor component that is responsible for displaying/editting |
* Returns editor component that is responsible for displaying/editing |
491 |
* selected item in the combo box. |
* selected item in the combo box. |
492 |
* |
* |
493 |
* @return ComboBoxEditor |
* @return ComboBoxEditor |
509 |
|
|
510 |
/** |
/** |
511 |
* Returns currently selected item in the combo box. |
* Returns currently selected item in the combo box. |
512 |
|
* The result may be <code>null</code> to indicate that nothing is |
513 |
|
* currently selected. |
514 |
* |
* |
515 |
* @return element that is currently selected in this combo box. |
* @return element that is currently selected in this combo box. |
516 |
*/ |
*/ |
517 |
public Object getSelectedItem() |
public Object getSelectedItem() |
518 |
{ |
{ |
519 |
Object item = dataModel.getSelectedItem(); |
return dataModel.getSelectedItem(); |
|
|
|
|
if (item == null && getItemCount() != 0) |
|
|
item = getItemAt(0); |
|
|
|
|
|
return item; |
|
520 |
} |
} |
521 |
|
|
522 |
/** |
/** |
523 |
* Forces JComboBox to select component located in the given index in the |
* Forces JComboBox to select component located in the given index in the |
524 |
* combo box. |
* combo box. |
525 |
|
* <p>If the index is below -1 or exceeds the upper bound an |
526 |
|
* <code>IllegalArgumentException</code> is thrown.<p/> |
527 |
|
* <p>If the index is -1 then no item gets selected.</p> |
528 |
* |
* |
529 |
* @param index index specifying location of the component that should be |
* @param index index specifying location of the component that should be |
530 |
* selected. |
* selected. |
531 |
*/ |
*/ |
532 |
public void setSelectedIndex(int index) |
public void setSelectedIndex(int index) |
533 |
{ |
{ |
534 |
// FIXME: if index == -1 then nothing should be selected |
if(index < -1 || index >= dataModel.getSize()) { |
535 |
setSelectedItem(dataModel.getElementAt(index)); |
// Fails because index is out of bounds. |
536 |
|
throw new IllegalArgumentException("illegal index: " + index); |
537 |
|
} else { |
538 |
|
/* Selects the item at the given index or clears the selection if the |
539 |
|
* index value is -1. |
540 |
|
*/ |
541 |
|
setSelectedItem((index == -1) ? null : dataModel.getElementAt(index)); |
542 |
|
} |
543 |
} |
} |
544 |
|
|
545 |
/** |
/** |
546 |
* Returns index of the item that is currently selected in the combo box. |
* Returns index of the item that is currently selected in the combo box. |
547 |
* If no item is currently selected, then -1 is returned. |
* If no item is currently selected, then -1 is returned. |
548 |
|
* |
549 |
|
* <p>Note: For performance reasons you should minimize invocation of this |
550 |
|
* method. If the data model is not an instance of |
551 |
|
* <code>DefaultComboBoxModel</code> the complexity is O(n) where |
552 |
|
* n is the number of elements in the combo box.</p> |
553 |
* |
* |
554 |
* @return int index specifying location of the currently selected item in |
* @return int Index specifying location of the currently selected item in |
555 |
* the combo box or -1 if nothing is selected in the combo box. |
* the combo box or -1 if nothing is selected in the combo box. |
556 |
*/ |
*/ |
557 |
public int getSelectedIndex() |
public int getSelectedIndex() |
558 |
{ |
{ |
559 |
Object selectedItem = getSelectedItem(); |
Object selectedItem = getSelectedItem(); |
560 |
if (selectedItem != null && (dataModel instanceof DefaultComboBoxModel)) |
|
561 |
return ((DefaultComboBoxModel) dataModel).getIndexOf(selectedItem); |
if (selectedItem != null) { |
562 |
|
|
563 |
|
if(dataModel instanceof DefaultComboBoxModel) { |
564 |
|
// Uses special method of DefaultComboBoxModel to retrieve the index. |
565 |
|
return ((DefaultComboBoxModel) dataModel).getIndexOf(selectedItem); |
566 |
|
} else { |
567 |
|
// Iterates over all items to retrieve the index. |
568 |
|
int size = dataModel.getSize(); |
569 |
|
|
570 |
|
for(int i=0; i < size; i++) { |
571 |
|
Object o = dataModel.getElementAt(i); |
572 |
|
|
573 |
|
// XXX: Is special handling of ComparableS neccessary? |
574 |
|
if((selectedItem != null) ? selectedItem.equals(o) : o == null) { |
575 |
|
return i; |
576 |
|
} |
577 |
|
} |
578 |
|
} |
579 |
|
} |
580 |
|
|
581 |
|
// returns that no item is currently selected |
582 |
return -1; |
return -1; |
583 |
} |
} |
584 |
|
|
587 |
return prototypeDisplayValue; |
return prototypeDisplayValue; |
588 |
} |
} |
589 |
|
|
590 |
public void setPrototypeDisplayValue(Object prototypeDisplayValue) |
public void setPrototypeDisplayValue(Object newPrototypeDisplayValue) |
591 |
{ |
{ |
592 |
this.prototypeDisplayValue = prototypeDisplayValue; |
prototypeDisplayValue = newPrototypeDisplayValue; |
593 |
} |
} |
594 |
|
|
595 |
/** |
/** |
596 |
* This method adds given element to this JComboBox. |
* This method adds given element to this JComboBox. |
597 |
|
* <p>A <code>RuntimeException</code> is thrown if the data model is not |
598 |
|
* an instance of {@link MutableComboBoxModel}.</p> |
599 |
* |
* |
600 |
* @param element element to add |
* @param element element to add |
601 |
*/ |
*/ |
602 |
public void addItem(Object element) |
public void addItem(Object element) |
603 |
{ |
{ |
604 |
((MutableComboBoxModel) dataModel).addElement(element); |
if(dataModel instanceof MutableComboBoxModel) { |
605 |
|
((MutableComboBoxModel) dataModel).addElement(element); |
606 |
|
} else { |
607 |
|
throw new RuntimeException("Unable to add the item because the data model it is not an instance of MutableComboBoxModel."); |
608 |
|
} |
609 |
} |
} |
610 |
|
|
611 |
/** |
/** |
612 |
* Inserts given element at the specified index to this JComboBox |
* Inserts given element at the specified index to this JComboBox. |
613 |
|
* <p>A <code>RuntimeException</code> is thrown if the data model is not |
614 |
|
* an instance of {@link MutableComboBoxModel}.</p> |
615 |
* |
* |
616 |
* @param element element to insert |
* @param element element to insert |
617 |
* @param index position where to insert the element |
* @param index position where to insert the element |
618 |
*/ |
*/ |
619 |
public void insertItemAt(Object element, int index) |
public void insertItemAt(Object element, int index) |
620 |
{ |
{ |
621 |
((MutableComboBoxModel) dataModel).insertElementAt(element, index); |
if(dataModel instanceof MutableComboBoxModel) { |
622 |
|
((MutableComboBoxModel) dataModel).insertElementAt(element, index); |
623 |
|
} else { |
624 |
|
throw new RuntimeException("Unable to insert the item because the data model it is not an instance of MutableComboBoxModel."); |
625 |
|
} |
626 |
} |
} |
627 |
|
|
628 |
/** |
/** |
629 |
* This method removes given element from this JComboBox. |
* This method removes given element from this JComboBox. |
630 |
|
* <p>A <code>RuntimeException</code> is thrown if the data model is not |
631 |
|
* an instance of {@link MutableComboBoxModel}.</p> |
632 |
* |
* |
633 |
* @param element element to remove |
* @param element element to remove |
634 |
*/ |
*/ |
635 |
public void removeItem(Object element) |
public void removeItem(Object element) |
636 |
{ |
{ |
637 |
((MutableComboBoxModel) dataModel).removeElement(element); |
if(dataModel instanceof MutableComboBoxModel) { |
638 |
|
((MutableComboBoxModel) dataModel).removeElement(element); |
639 |
|
} else { |
640 |
|
throw new RuntimeException("Unable to remove the item because the data model it is not an instance of MutableComboBoxModel."); |
641 |
|
} |
642 |
} |
} |
643 |
|
|
644 |
/** |
/** |
645 |
* This method remove element location in the specified index in the |
* This method remove element location in the specified index in the |
646 |
* JComboBox. |
* JComboBox. |
647 |
|
* <p>A <code>RuntimeException</code> is thrown if the data model is not |
648 |
|
* an instance of {@link MutableComboBoxModel}.</p> |
649 |
* |
* |
650 |
* @param index index specifying position of the element to remove |
* @param index index specifying position of the element to remove |
651 |
*/ |
*/ |
652 |
public void removeItemAt(int index) |
public void removeItemAt(int index) |
653 |
{ |
{ |
654 |
((MutableComboBoxModel) dataModel).removeElementAt(index); |
if(dataModel instanceof MutableComboBoxModel) { |
655 |
|
((MutableComboBoxModel) dataModel).removeElementAt(index); |
656 |
|
} else { |
657 |
|
throw new RuntimeException("Unable to remove the item because the data model it is not an instance of MutableComboBoxModel."); |
658 |
|
} |
659 |
} |
} |
660 |
|
|
661 |
/** |
/** |
662 |
* This method removes all elements from this JComboBox. |
* This method removes all elements from this JComboBox. |
663 |
|
* <p>A <code>RuntimeException</code> is thrown if the data model is not |
664 |
|
* an instance of {@link MutableComboBoxModel}.</p> |
665 |
|
* |
666 |
*/ |
*/ |
667 |
public void removeAllItems() |
public void removeAllItems() |
668 |
{ |
{ |
669 |
if (dataModel instanceof DefaultComboBoxModel) |
if (dataModel instanceof DefaultComboBoxModel) { |
670 |
((DefaultComboBoxModel) dataModel).removeAllElements(); |
// Uses special method if we have a DefaultComboBoxModel. |
671 |
|
((DefaultComboBoxModel) dataModel).removeAllElements(); |
672 |
|
} else if(dataModel instanceof MutableComboBoxModel){ |
673 |
|
// Iterates over all items and removes each. |
674 |
|
MutableComboBoxModel mcbm = (MutableComboBoxModel) dataModel; |
675 |
|
|
676 |
|
/* We intentionally remove the items backwards to support |
677 |
|
* models which shift their content to the beginning (e.g. |
678 |
|
* linked lists) |
679 |
|
*/ |
680 |
|
for(int i=mcbm.getSize()-1; i >= 0; i--) { |
681 |
|
mcbm.removeElementAt(i); |
682 |
|
} |
683 |
|
|
684 |
|
} else { |
685 |
|
throw new RuntimeException("Unable to remove the items because the data model it is not an instance of MutableComboBoxModel."); |
686 |
|
} |
687 |
|
|
688 |
} |
} |
689 |
|
|
690 |
/** |
/** |
882 |
*/ |
*/ |
883 |
public Object[] getSelectedObjects() |
public Object[] getSelectedObjects() |
884 |
{ |
{ |
885 |
Object selectedObject = getSelectedItem(); |
return new Object[] { getSelectedItem() }; |
|
return new Object[] { selectedObject }; |
|
886 |
} |
} |
887 |
|
|
888 |
/** |
/** |
1031 |
*/ |
*/ |
1032 |
public int getItemCount() |
public int getItemCount() |
1033 |
{ |
{ |
1034 |
return ((DefaultComboBoxModel) dataModel).getSize(); |
return dataModel.getSize(); |
1035 |
} |
} |
1036 |
|
|
1037 |
/** |
/** |
1043 |
*/ |
*/ |
1044 |
public Object getItemAt(int index) |
public Object getItemAt(int index) |
1045 |
{ |
{ |
1046 |
return ((MutableComboBoxModel) dataModel).getElementAt(index); |
return dataModel.getElementAt(index); |
1047 |
} |
} |
1048 |
|
|
1049 |
/** |
/** |