KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > db > util > DataComboBoxSupport


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.db.util;
21
22 import java.awt.Color JavaDoc;
23 import java.awt.Component JavaDoc;
24 import java.awt.Dimension JavaDoc;
25 import java.awt.event.ActionEvent JavaDoc;
26 import java.awt.event.ActionListener JavaDoc;
27 import java.awt.event.InputEvent JavaDoc;
28 import java.awt.event.KeyAdapter JavaDoc;
29 import java.awt.event.KeyEvent JavaDoc;
30 import javax.swing.AbstractListModel JavaDoc;
31 import javax.swing.ComboBoxModel JavaDoc;
32 import javax.swing.DefaultListCellRenderer JavaDoc;
33 import javax.swing.JComboBox JavaDoc;
34 import javax.swing.JLabel JavaDoc;
35 import javax.swing.JList JavaDoc;
36 import javax.swing.JSeparator JavaDoc;
37 import javax.swing.SwingUtilities JavaDoc;
38 import javax.swing.event.ListDataEvent JavaDoc;
39 import javax.swing.event.ListDataListener JavaDoc;
40 import javax.swing.event.PopupMenuEvent JavaDoc;
41 import javax.swing.event.PopupMenuListener JavaDoc;
42
43 /**
44  * This is an utility class for filling combo boxes with some data (usually
45  * some items). The combo box has a separator item and a "Add item" item allowing
46  * the user to invoke the adding of new items to the combo box. The client of
47  * this class should provide a {@link DataComboBoxModel} and call
48  * the {@link #connect} method.
49  *
50  * @author Andrei Badea
51  */

52 public final class DataComboBoxSupport {
53
54     private final DataComboBoxModel dataModel;
55     private final boolean allowAdding;
56
57     private Object JavaDoc previousItem = null;
58     private Object JavaDoc previousNonSpecialItem = null;
59     private int previousIndex = -1;
60
61     private boolean performingNewItemAction = false;
62
63     /**
64      * Serves as the separator item.
65      */

66     private static final class Separator extends JSeparator JavaDoc {
67
68         Separator() {
69             setForeground(Color.BLACK);
70         }
71
72         public Dimension JavaDoc getPreferredSize() {
73             Dimension JavaDoc size = super.getPreferredSize();
74             return new Dimension JavaDoc(size.width, 1);
75         }
76     }
77
78     /** Not private because used in tests. */
79     static final Separator JavaDoc SEPARATOR_ITEM = new Separator JavaDoc();
80
81     /**
82      * Serves as the new item. Not private because used in tests.
83      */

84     final Object JavaDoc NEW_ITEM = new Object JavaDoc() {
85         public String JavaDoc toString() {
86             return dataModel.getNewItemDisplayName();
87         }
88     };
89
90     /** Not private because used in tests. */
91     DataComboBoxSupport(JComboBox JavaDoc comboBox, DataComboBoxModel dataModel, boolean allowAdding) {
92         this.dataModel = dataModel;
93         this.allowAdding = allowAdding;
94
95         comboBox.setEditable(false);
96
97         comboBox.setModel(new ItemComboBoxModel());
98
99         comboBox.setRenderer(new ItemListCellRenderer());
100         comboBox.addKeyListener(new ItemKeyListener());
101         comboBox.addActionListener(new ItemActionListener());
102         comboBox.addPopupMenuListener(new ItemPopupMenuListener());
103     }
104
105     /**
106      * Connects a combo box with the specified combo box model.
107      */

108     public static void connect(JComboBox JavaDoc comboBox, DataComboBoxModel dataModel) {
109         connect(comboBox, dataModel, true);
110     }
111
112     /**
113      * Connects a combo box with the specified combo box model.
114      */

115     public static void connect(JComboBox JavaDoc comboBox, DataComboBoxModel dataModel, boolean allowAdding) {
116         new DataComboBoxSupport(comboBox, dataModel, allowAdding);
117     }
118
119     private boolean isSpecialItem(Object JavaDoc item) {
120         return item == SEPARATOR_ITEM || item == NEW_ITEM;
121     }
122
123     private void setPreviousNonSpecialItem(JComboBox JavaDoc comboBox) {
124         if (comboBox.getSelectedItem() == NEW_ITEM) {
125             // no new item added
126
comboBox.setSelectedItem(previousNonSpecialItem);
127         }
128     }
129
130     private class ItemComboBoxModel extends AbstractListModel JavaDoc implements ComboBoxModel JavaDoc, ListDataListener JavaDoc {
131
132         // XXX intervalAdded() and intervalRemoved() are not implemented,
133
// but it is enough for the connection and drivers combo boxes
134

135         public ItemComboBoxModel() {
136             getDelegate().addListDataListener(this);
137         }
138
139         public Object JavaDoc getElementAt(int index) {
140             if (allowAdding) {
141                 if (getSize() == 1) {
142                     // there is just NEW_ITEM
143
if (index == 0) {
144                         return NEW_ITEM;
145                     } else {
146                         throw new IllegalStateException JavaDoc("Index out of bounds: " + index); // NOI18N
147
}
148                 }
149
150                 // there are the delegate items, SEPARATOR_ITEM, NEW_ITEM
151
if (index >= 0 && index < getDelegate().getSize()) {
152                     return getDelegate().getElementAt(index);
153                 } else if (index == getSize() - 2) {
154                     return SEPARATOR_ITEM;
155                 } else if (index == getSize() - 1) {
156                     return NEW_ITEM;
157                 } else {
158                     throw new IllegalStateException JavaDoc("Index out of bounds: " + index); // NOI18N
159
}
160             } else {
161                 // there are no other items than those of the delegate
162
return getDelegate().getElementAt(index);
163             }
164         }
165
166         public int getSize() {
167             // 1 = NEW_ITEM
168
// 2 = SEPARATOR, NEW_ITEM
169
if (allowAdding) {
170                 return getDelegate().getSize() == 0 ? 1 : getDelegate().getSize() + 2;
171             } else {
172                 return getDelegate().getSize();
173             }
174         }
175
176         public void setSelectedItem(Object JavaDoc anItem) {
177             previousItem = getDelegate().getSelectedItem();
178             previousIndex = getItemIndex(previousItem);
179
180             if (!isSpecialItem(previousItem)) {
181                 previousNonSpecialItem = previousItem;
182             }
183
184             getDelegate().setSelectedItem(anItem);
185         }
186
187         public Object JavaDoc getSelectedItem() {
188             return getDelegate().getSelectedItem();
189         }
190
191         public Object JavaDoc getPreviousItem() {
192             return previousItem;
193         }
194
195         private ComboBoxModel JavaDoc getDelegate() {
196             return dataModel.getListModel();
197         }
198
199         private int getItemIndex(Object JavaDoc item) {
200             if (item == null) {
201                 return -1;
202             }
203             for (int i = 0; i < getSize(); i++ ) {
204                 if (getElementAt(i).equals(item)) {
205                     return i;
206                 }
207             }
208             return -1;
209         }
210
211         public void intervalRemoved(ListDataEvent JavaDoc e) {
212             throw new UnsupportedOperationException JavaDoc("This is currently not supported.");
213         }
214
215         public void intervalAdded(ListDataEvent JavaDoc e) {
216             throw new UnsupportedOperationException JavaDoc("This is currently not supported.");
217         }
218
219         public void contentsChanged(ListDataEvent JavaDoc e) {
220             fireContentsChanged(this, 0, getSize());
221         }
222     }
223
224     private class ItemListCellRenderer extends DefaultListCellRenderer JavaDoc {
225
226         public Component JavaDoc getListCellRendererComponent(JList JavaDoc list, Object JavaDoc value, int index, boolean isSelected, boolean cellHasFocus) {
227
228             Component JavaDoc component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
229             JLabel JavaDoc label = (JLabel JavaDoc)component;
230
231             if (value != null && !isSpecialItem(value)) {
232                 String JavaDoc displayName = dataModel.getItemDisplayName(value);
233                 label.setText(dataModel.getItemDisplayName(value));
234                 label.setToolTipText(dataModel.getItemTooltipText(value));
235             } else if (value == SEPARATOR_ITEM) {
236                 return SEPARATOR_ITEM;
237             } else if (value != null) {
238                 label.setText(value.toString());
239                 label.setToolTipText(null);
240             }
241
242             return label;
243         }
244     }
245
246     private final class ItemKeyListener extends KeyAdapter JavaDoc {
247
248         public void keyPressed(KeyEvent JavaDoc e) {
249             JComboBox JavaDoc comboBox = (JComboBox JavaDoc)e.getSource();
250
251             int keyCode = e.getKeyCode();
252             if (KeyEvent.VK_ENTER == keyCode) {
253                 Object JavaDoc selectedItem = comboBox.getSelectedItem();
254                 if (selectedItem == NEW_ITEM) {
255                     performingNewItemAction = true;
256                     try {
257                         comboBox.setPopupVisible(false);
258                         e.consume();
259                         dataModel.newItemActionPerformed();
260                     } finally {
261                         performingNewItemAction = false;
262                     }
263
264                     setPreviousNonSpecialItem(comboBox);
265                 }
266             }
267         }
268     }
269
270     private final class ItemActionListener implements ActionListener JavaDoc {
271
272         public void actionPerformed(ActionEvent JavaDoc e) {
273             final JComboBox JavaDoc comboBox = (JComboBox JavaDoc)e.getSource();
274
275             Object JavaDoc selectedItem = comboBox.getSelectedItem();
276             if (selectedItem == SEPARATOR_ITEM) {
277                 int newIndex = -1;
278                 if (previousIndex != -1) {
279                     // skipping the separator when moving up/down with the arrow keys
280
int selectedIndex = comboBox.getSelectedIndex();
281                     if (selectedIndex > previousIndex) {
282                         // moving down
283
newIndex = selectedIndex + 1;
284                     } else {
285                         // moving up
286
newIndex= selectedIndex - 1;
287                     }
288                 }
289                 comboBox.setSelectedIndex(newIndex);
290             } else if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) {
291                 // handling mouse click, see KeyEvent.getKeyModifiersText(e.getModifiers())
292
if (selectedItem == NEW_ITEM) {
293                     performingNewItemAction = true;
294                     try {
295                         comboBox.setPopupVisible(false);
296                         dataModel.newItemActionPerformed();
297                     } finally {
298                         performingNewItemAction = false;
299                     }
300
301                     setPreviousNonSpecialItem(comboBox);
302                     // we (or maybe the client) have just selected an item inside an actionPerformed event,
303
// which will not send another actionPerformed event for the new item.
304
// We need to make sure all listeners get an event for the new item,
305
// thus...
306
final Object JavaDoc newSelectedItem = comboBox.getSelectedItem();
307                     SwingUtilities.invokeLater(new Runnable JavaDoc() {
308                         public void run() {
309                             comboBox.setSelectedItem(newSelectedItem);
310                         }
311                     });
312                 }
313             }
314         }
315     }
316
317     private final class ItemPopupMenuListener implements PopupMenuListener JavaDoc {
318
319         public void popupMenuWillBecomeVisible(PopupMenuEvent JavaDoc e) {
320         }
321
322         public void popupMenuWillBecomeInvisible(PopupMenuEvent JavaDoc e) {
323             if (!performingNewItemAction) {
324                 setPreviousNonSpecialItem((JComboBox JavaDoc)e.getSource());
325             }
326         }
327
328         public void popupMenuCanceled(PopupMenuEvent JavaDoc e) {
329             // without the check the previous non-special item would be displayed
330
// while calling DataComboBoxModel.newItemActionPerformed()
331
// instead of NEW_ITEM, but this is unwanted. Same for
332
// popupMenuWillBecomeImvisible().
333
if (!performingNewItemAction) {
334                 setPreviousNonSpecialItem((JComboBox JavaDoc)e.getSource());
335             }
336         }
337     }
338 }
339
Popular Tags