1
/* ========================================================================
2
* JCommon : a free general purpose class library for the Java(tm) platform
3
* ========================================================================
5
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
7
* Project Info: http://www.jfree.org/jcommon/index.html
9
* This library is free software; you can redistribute it and/or modify it
10
* under the terms of the GNU Lesser General Public License as published by
11
* the Free Software Foundation; either version 2.1 of the License, or
12
* (at your option) any later version.
14
* This library is distributed in the hope that it will be useful, but
15
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17
* License for more details.
19
* You should have received a copy of the GNU Lesser General Public
20
* License along with this library; if not, write to the Free Software
21
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
24
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
25
* in the United States and other countries.]
28
* KeyedComboBoxModel.java
30
* (C) Copyright 2004, by Thomas Morgner and Contributors.
32
* Original Author: Thomas Morgner;
33
* Contributor(s): David Gilbert (for Object Refinery Limited);
35
* $Id: KeyedComboBoxModel.java,v 1.5 2005/10/18 13:18:34 mungady Exp $
39
* 07-Jun-2004 : Added JCommon header (DG);
44
import java.util.ArrayList;
45
import javax.swing.ComboBoxModel;
46
import javax.swing.event.ListDataEvent;
47
import javax.swing.event.ListDataListener;
50
* The KeyedComboBox model allows to define an internal key (the data element) for every
53
* This class is usefull in all cases, where the public text differs from the internal
54
* view on the data. A separation between presentation data and processing data is a
55
* prequesite for localizing combobox entries. This model does not allow selected
56
* elements, which are not in the list of valid elements.
58
* @author Thomas Morgner
60
public class KeyedComboBoxModel implements ComboBoxModel {
63
* The internal data carrier to map keys to values and vice versa.
65
private static class ComboBoxItemPair {
68
/** The value for the key. */
72
* Creates a new item pair for the given key and value. The value
73
* can be changed later, if needed.
76
* @param value the value
78
public ComboBoxItemPair(final Object key, final Object value) {
87
public Object getKey() {
93
* @return the value for this key.
95
public Object getValue() {
100
* Redefines the value stored for that key.
101
* @param value the new value.
103
public void setValue(final Object value) {
108
/** The index of the selected item. */
109
private int selectedItem;
110
/** The data (contains ComboBoxItemPairs). */
111
private ArrayList data;
112
/** The listeners. */
113
private ArrayList listdatalistener;
114
/** The cached listeners as array. */
115
private transient ListDataListener[] tempListeners;
118
* Creates a new keyed combobox model.
120
public KeyedComboBoxModel() {
121
data = new ArrayList();
122
listdatalistener = new ArrayList();
126
* Creates a new keyed combobox model for the given keys and values.
127
* Keys and values must have the same number of items.
129
* @param keys the keys
130
* @param values the values
132
public KeyedComboBoxModel(final Object[] keys, final Object[] values) {
134
setData(keys, values);
138
* Replaces the data in this combobox model. The number of keys must be equals to the
141
* @param keys the keys
142
* @param values the values
144
public void setData(final Object[] keys, final Object[] values) {
145
if (values.length != keys.length) {
146
throw new IllegalArgumentException("Values and text must have the same length.");
150
data.ensureCapacity(keys.length);
152
for (int i = 0; i < values.length; i++) {
153
add(keys[i], values[i]);
157
final ListDataEvent evt = new ListDataEvent
158
(this, ListDataEvent.CONTENTS_CHANGED, 0, data.size() - 1);
159
fireListDataEvent(evt);
163
* Notifies all registered list data listener of the given event.
165
* @param evt the event.
167
protected synchronized void fireListDataEvent(final ListDataEvent evt) {
168
if (tempListeners == null) {
169
tempListeners = (ListDataListener[]) listdatalistener.toArray
170
(new ListDataListener[listdatalistener.size()]);
172
for (int i = 0; i < tempListeners.length; i++) {
173
final ListDataListener l = tempListeners[i];
174
l.contentsChanged(evt);
179
* Returns the selected item.
181
* @return The selected item or <code>null</code> if there is no selection
183
public Object getSelectedItem() {
184
if (selectedItem >= data.size()) {
188
if (selectedItem < 0) {
192
final ComboBoxItemPair item = (ComboBoxItemPair) data.get(selectedItem);
193
return item.getValue();
197
* Defines the selected key. If the object is not in the list of values, no item
200
* @param anItem the new selected item.
202
public void setSelectedKey(final Object anItem) {
203
if (anItem == null) {
207
final int newSelectedItem = findDataElementIndex(anItem);
208
selectedItem = newSelectedItem;
210
fireListDataEvent(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, -1, -1));
214
* Set the selected item. The implementation of this method should notify all
215
* registered <code>ListDataListener</code>s that the contents have changed.
217
* @param anItem the list object to select or <code>null</code> to clear the selection
219
public void setSelectedItem(final Object anItem) {
220
if (anItem == null) {
224
final int newSelectedItem = findElementIndex(anItem);
225
selectedItem = newSelectedItem;
227
fireListDataEvent(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, -1, -1));
231
* Adds a listener to the list that's notified each time a change to the data model
234
* @param l the <code>ListDataListener</code> to be added
236
public synchronized void addListDataListener(final ListDataListener l) {
237
listdatalistener.add(l);
238
tempListeners = null;
242
* Returns the value at the specified index.
244
* @param index the requested index
245
* @return the value at <code>index</code>
247
public Object getElementAt(final int index) {
248
if (index >= data.size()) {
252
final ComboBoxItemPair datacon = (ComboBoxItemPair) data.get(index);
253
if (datacon == null) {
256
return datacon.getValue();
260
* Returns the key from the given index.
262
* @param index the index of the key.
263
* @return the the key at the specified index.
265
public Object getKeyAt(final int index) {
266
if (index >= data.size()) {
274
final ComboBoxItemPair datacon = (ComboBoxItemPair) data.get(index);
275
if (datacon == null) {
278
return datacon.getKey();
282
* Returns the selected data element or null if none is set.
284
* @return the selected data element.
286
public Object getSelectedKey() {
287
return getKeyAt(selectedItem);
291
* Returns the length of the list.
293
* @return the length of the list
295
public int getSize() {
300
* Removes a listener from the list that's notified each time a change to the data model
303
* @param l the <code>ListDataListener</code> to be removed
305
public void removeListDataListener(final ListDataListener l) {
306
listdatalistener.remove(l);
307
tempListeners = null;
311
* Searches an element by its data value. This method is called by the setSelectedItem
312
* method and returns the first occurence of the element.
314
* @param anItem the item
315
* @return the index of the item or -1 if not found.
317
private int findDataElementIndex(final Object anItem) {
318
if (anItem == null) {
319
throw new NullPointerException("Item to find must not be null");
322
for (int i = 0; i < data.size(); i++) {
323
final ComboBoxItemPair datacon = (ComboBoxItemPair) data.get(i);
324
if (anItem.equals(datacon.getKey())) {
332
* Tries to find the index of element with the given key. The key must not be null.
334
* @param key the key for the element to be searched.
335
* @return the index of the key, or -1 if not found.
337
public int findElementIndex(final Object key) {
339
throw new NullPointerException("Item to find must not be null");
342
for (int i = 0; i < data.size(); i++) {
343
final ComboBoxItemPair datacon = (ComboBoxItemPair) data.get(i);
344
if (key.equals(datacon.getValue())) {
352
* Removes an entry from the model.
356
public void removeDataElement(final Object key) {
357
final int idx = findDataElementIndex(key);
363
final ListDataEvent evt = new ListDataEvent
364
(this, ListDataEvent.INTERVAL_REMOVED, idx, idx);
365
fireListDataEvent(evt);
369
* Adds a new entry to the model.
372
* @param cbitem the display value.
374
public void add(final Object key, final Object cbitem) {
375
final ComboBoxItemPair con = new ComboBoxItemPair(key, cbitem);
377
final ListDataEvent evt = new ListDataEvent
378
(this, ListDataEvent.INTERVAL_ADDED, data.size() - 2, data.size() - 2);
379
fireListDataEvent(evt);
383
* Removes all entries from the model.
385
public void clear() {
386
final int size = getSize();
388
final ListDataEvent evt = new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, 0, size - 1);
389
fireListDataEvent(evt);