001: /*
002: * Copyright 2006 Ethan Nicholas. All rights reserved.
003: * Use is subject to license terms.
004: */
005: package jaxx.runtime.swing;
006:
007: import java.awt.*;
008: import java.awt.event.*;
009: import java.beans.*;
010: import java.util.*;
011: import java.util.List;
012: import javax.swing.*;
013:
014: public class JAXXComboBox extends JComboBox {
015: public class JAXXComboBoxModel extends AbstractListModel implements
016: ComboBoxModel {
017: private List/*<Item>*/items;
018: private Object selectedItem;
019:
020: public JAXXComboBoxModel(List/*<Item>*/items) {
021: this .items = items;
022:
023: PropertyChangeListener listener = new PropertyChangeListener() {
024: public void propertyChange(PropertyChangeEvent e) {
025: if (e.getPropertyName().equals(
026: Item.SELECTED_PROPERTY)) {
027: Item item = (Item) e.getSource();
028: int itemIndex = JAXXComboBoxModel.this .items
029: .indexOf(item);
030: // TODO: fix cut-and-pasting badness
031: int[] oldSelection = new int[] { getSelectedIndex() };
032: int[] newSelection;
033: int index = -1;
034: for (int i = 0; i < oldSelection.length; i++) {
035: if (oldSelection[i] == itemIndex) {
036: index = i;
037: break;
038: }
039: }
040: if (item.isSelected()) {
041: if (index != -1) // it was already selected
042: return;
043: newSelection = new int[oldSelection.length + 1];
044: System.arraycopy(oldSelection, 0,
045: newSelection, 0,
046: oldSelection.length);
047: newSelection[newSelection.length - 1] = itemIndex;
048: } else {
049: if (index == -1) // it already wasn't selected
050: return;
051: newSelection = new int[oldSelection.length - 1];
052: System.arraycopy(oldSelection, 0,
053: newSelection, 0, index);
054: System.arraycopy(oldSelection, index + 1,
055: newSelection, index,
056: oldSelection.length - 1 - index);
057: }
058: setSelectedIndex(newSelection[0]);
059: } else {
060: // TODO: more cut-and-pasting badness
061: for (int i = 0; i < getSize(); i++) {
062: if (getElementAt(i) == ((Item) e
063: .getSource()).getValue()) {
064: fireContentsChanged(
065: JAXXComboBoxModel.this , i, i);
066: if (getSelectedIndex() == i)
067: fireItemStateChanged(new ItemEvent(
068: JAXXComboBox.this ,
069: ItemEvent.ITEM_STATE_CHANGED,
070: getElementAt(i),
071: ItemEvent.DESELECTED));
072: return;
073: }
074: }
075: }
076: }
077: };
078: for (int i = 0; i < items.size(); i++)
079: ((Item) items.get(i))
080: .addPropertyChangeListener(listener);
081: }
082:
083: public Object getElementAt(int i) {
084: return ((Item) items.get(i)).getValue();
085: }
086:
087: public int getSize() {
088: return items.size();
089: }
090:
091: public Object getSelectedItem() {
092: return selectedItem;
093: }
094:
095: public void setSelectedItem(Object selectedItem) {
096: if ((this .selectedItem != null && !this .selectedItem
097: .equals(selectedItem))
098: || this .selectedItem == null
099: && selectedItem != null) {
100: this .selectedItem = selectedItem;
101: fireContentsChanged(this , -1, -1);
102: }
103: }
104: }
105:
106: public JAXXComboBox() {
107: setRenderer(new DefaultListCellRenderer() {
108: public Component getListCellRendererComponent(JList list,
109: Object value, int index, boolean isSelected,
110: boolean cellHasFocus) {
111: ListModel model = list.getModel();
112: if (model instanceof JAXXComboBoxModel) {
113: List/*<Item>*/items = ((JAXXComboBoxModel) model).items;
114: Item item = null;
115: if (index == -1) {
116: for (int i = 0; i < items.size(); i++) {
117: Item testItem = (Item) items.get(i);
118: if (testItem.getValue() == value) {
119: item = testItem;
120: break;
121: }
122: }
123: } else
124: item = (Item) items.get(index);
125:
126: if (item != null) {
127: String label = item.getLabel();
128: if (label != null)
129: value = label;
130: }
131: }
132: return super .getListCellRendererComponent(list, value,
133: index, isSelected, cellHasFocus);
134: }
135: });
136:
137: addItemListener(new ItemListener() {
138: public void itemStateChanged(ItemEvent e) {
139: ListModel model = getModel();
140: if (model instanceof JAXXComboBoxModel) {
141: List/*<Item>*/items = ((JAXXComboBoxModel) model).items;
142: for (int i = items.size() - 1; i >= 0; i--) {
143: boolean selected = getSelectedIndex() == i;
144: Item item = (Item) items.get(i);
145: if (selected != item.isSelected())
146: item.setSelected(selected);
147: }
148: }
149: }
150: });
151: }
152:
153: // this way we can keep it marked protected and still allow code in this file to call it
154: protected void fireItemStateChanged(ItemEvent e) {
155: super .fireItemStateChanged(e);
156: }
157:
158: public void setItems(List/*<Item>*/items) {
159: setModel(new JAXXComboBoxModel(items));
160: List/*<Integer>*/selectedIndexList = new ArrayList/*<Integer>*/();
161: for (int i = 0; i < items.size(); i++)
162: if (((Item) items.get(i)).isSelected())
163: selectedIndexList.add(new Integer(i));
164: int[] selectedIndices = new int[selectedIndexList.size()];
165: for (int i = 0; i < selectedIndexList.size(); i++)
166: selectedIndices[i] = ((Integer) selectedIndexList.get(i))
167: .intValue();
168: if (selectedIndices.length > 0)
169: setSelectedIndex(selectedIndices[0]);
170: }
171: }
|