/* ======================================================================== * JCommon : a free general purpose class library for the Java(tm) platform * ======================================================================== * * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. * * Project Info: http://www.jfree.org/jcommon/index.html * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. * * [Java is a trademark or registered trademark of Sun Microsystems, Inc. * in the United States and other countries.] * * ------------------ * KeyedComboBoxModel.java * ------------------ * (C) Copyright 2004, by Thomas Morgner and Contributors. * * Original Author: Thomas Morgner; * Contributor(s): David Gilbert (for Object Refinery Limited); * * $Id: KeyedComboBoxModel.java,v 1.6 2006/12/03 15:33:33 taqua Exp $ * * Changes * ------- * 07-Jun-2004 : Added JCommon header (DG); * */ package net.pms.util; import java.util.ArrayList; import javax.swing.ComboBoxModel; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; /** * The KeyedComboBox model allows to define an internal key (the data element) * for every entry in the model. *
* This class is usefull in all cases, where the public text differs from the * internal view on the data. A separation between presentation data and * processing data is a prequesite for localizing combobox entries. This model * does not allow selected elements, which are not in the list of valid * elements. * * @author Thomas Morgner * @author mail@tcox.org (Added generics) */ public class KeyedComboBoxModel implements ComboBoxModel { /** * The internal data carrier to map keys to values and vice versa. */ private static class ComboBoxItemPair { /** * The key. */ private Object key; /** * The value for the key. */ private Object value; /** * Creates a new item pair for the given key and value. The value can be * changed later, if needed. * * @param key the key * @param value the value */ public ComboBoxItemPair(final Object key, final Object value) { this.key = key; this.value = value; } /** * Returns the key. * * @return the key. */ public Object getKey() { return key; } /** * Returns the value. * * @return the value for this key. */ public Object getValue() { return value; } /** * Redefines the value stored for that key. * * @param value the new value. */ @SuppressWarnings("unused") public void setValue(final Object value) { this.value = value; } } /** * The index of the selected item. */ private int selectedItemIndex; private Object selectedItemValue; /** * The data (contains ComboBoxItemPairs). */ private ArrayListnull
if there is no selection
*/
public Object getSelectedItem() {
return selectedItemValue;
}
/**
* Defines the selected key. If the object is not in the list of values, no
* item gets selected.
*
* @param anItem the new selected item.
*/
public void setSelectedKey(final Object anItem) {
if (anItem == null) {
selectedItemIndex = -1;
selectedItemValue = null;
} else {
final int newSelectedItem = findDataElementIndex(anItem);
if (newSelectedItem == -1) {
selectedItemIndex = -1;
selectedItemValue = null;
} else {
selectedItemIndex = newSelectedItem;
selectedItemValue = getElementAt(selectedItemIndex);
}
}
fireListDataEvent(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, -1, -1));
}
/**
* Set the selected item. The implementation of this method should notify
* all registered ListDataListener
s that the contents have
* changed.
*
* @param anItem the list object to select or null
to clear the
* selection
*/
public void setSelectedItem(final Object anItem) {
if (anItem == null) {
selectedItemIndex = -1;
selectedItemValue = null;
} else {
final int newSelectedItem = findElementIndex(anItem);
if (newSelectedItem == -1) {
if (isAllowOtherValue()) {
selectedItemIndex = -1;
selectedItemValue = anItem;
} else {
selectedItemIndex = -1;
selectedItemValue = null;
}
} else {
selectedItemIndex = newSelectedItem;
selectedItemValue = getElementAt(selectedItemIndex);
}
}
fireListDataEvent(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, -1, -1));
}
private boolean isAllowOtherValue() {
return allowOtherValue;
}
public void setAllowOtherValue(final boolean allowOtherValue) {
this.allowOtherValue = allowOtherValue;
}
/**
* Adds a listener to the list that's notified each time a change to the data
* model occurs.
*
* @param l the ListDataListener
to be added
*/
public synchronized void addListDataListener(final ListDataListener l) {
listdatalistener.add(l);
tempListeners = null;
}
/**
* Returns the value at the specified index.
*
* @param index the requested index
* @return the value at index
*/
public Object getElementAt(final int index) {
if (index >= data.size()) {
return null;
}
final ComboBoxItemPair datacon = (ComboBoxItemPair) data.get(index);
if (datacon == null) {
return null;
}
return datacon.getValue();
}
/**
* Returns the key from the given index.
*
* @param index the index of the key.
* @return the the key at the specified index.
*/
public Object getKeyAt(final int index) {
if (index >= data.size()) {
return null;
}
if (index < 0) {
return null;
}
final ComboBoxItemPair datacon = (ComboBoxItemPair) data.get(index);
if (datacon == null) {
return null;
}
return datacon.getKey();
}
/**
* Returns the selected data element or null if none is set.
*
* @return the selected data element.
*/
public Object getSelectedKey() {
return getKeyAt(selectedItemIndex);
}
/**
* Returns the length of the list.
*
* @return the length of the list
*/
public int getSize() {
return data.size();
}
/**
* Removes a listener from the list that's notified each time a change to
* the data model occurs.
*
* @param l the ListDataListener
to be removed
*/
public void removeListDataListener(final ListDataListener l) {
listdatalistener.remove(l);
tempListeners = null;
}
/**
* Searches an element by its data value. This method is called by the
* setSelectedItem method and returns the first occurence of the element.
*
* @param anItem the item
* @return the index of the item or -1 if not found.
*/
private int findDataElementIndex(final Object anItem) {
if (anItem == null) {
throw new NullPointerException("Item to find must not be null");
}
for (int i = 0; i < data.size(); i++) {
final ComboBoxItemPair datacon = (ComboBoxItemPair) data.get(i);
if (anItem.equals(datacon.getKey())) {
return i;
}
}
return -1;
}
/**
* Tries to find the index of element with the given key. The key must not
* be null.
*
* @param key the key for the element to be searched.
* @return the index of the key, or -1 if not found.
*/
public int findElementIndex(final Object key) {
if (key == null) {
throw new NullPointerException("Item to find must not be null");
}
for (int i = 0; i < data.size(); i++) {
final ComboBoxItemPair datacon = (ComboBoxItemPair) data.get(i);
if (key.equals(datacon.getValue())) {
return i;
}
}
return -1;
}
/**
* Removes an entry from the model.
*
* @param key the key
*/
public void removeDataElement(final Object key) {
final int idx = findDataElementIndex(key);
if (idx == -1) {
return;
}
data.remove(idx);
final ListDataEvent evt = new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, idx, idx);
fireListDataEvent(evt);
}
/**
* Adds a new entry to the model.
*
* @param key the key
* @param cbitem the display value.
*/
public void add(final Object key, final Object cbitem) {
final ComboBoxItemPair con = new ComboBoxItemPair(key, cbitem);
data.add(con);
final ListDataEvent evt = new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, data.size() - 2, data.size() - 2);
fireListDataEvent(evt);
}
/**
* Removes all entries from the model.
*/
public void clear() {
final int size = getSize();
data.clear();
final ListDataEvent evt = new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, 0, size - 1);
fireListDataEvent(evt);
}
}