001 /* DefaultComboBoxModel.java --
002 Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038 package javax.swing;
039
040 import java.io.Serializable;
041 import java.util.Arrays;
042 import java.util.Vector;
043
044 import javax.swing.event.ListDataEvent;
045
046
047 /**
048 * A model that stores a list of elements and a selected item (which may be
049 * <code>null</code>). Changes to the model are signalled to listeners using
050 * {@link ListDataEvent}. This model is designed for use by the
051 * {@link JComboBox} component.
052 *
053 * @author Andrew Selkirk
054 * @author Olga Rodimina
055 * @author Robert Schuster
056 */
057 public class DefaultComboBoxModel extends AbstractListModel
058 implements MutableComboBoxModel, Serializable
059 {
060 private static final long serialVersionUID = 6698657703676921904L;
061
062 /**
063 * Storage for the elements in the model's list.
064 */
065 private Vector list;
066
067 /**
068 * The selected item (<code>null</code> indicates no selection).
069 */
070 private Object selectedItem = null;
071
072 /**
073 * Creates a new model, initially empty.
074 */
075 public DefaultComboBoxModel()
076 {
077 list = new Vector();
078 }
079
080 /**
081 * Creates a new model and initializes its item list to the values in the
082 * given array. The selected item is set to the first item in the array, or
083 * <code>null</code> if the array length is zero.
084 *
085 * @param items an array containing items for the model (<code>null</code>
086 * not permitted).
087 *
088 * @throws NullPointerException if <code>items</code> is <code>null</code>.
089 */
090 public DefaultComboBoxModel(Object[] items)
091 {
092 list = new Vector(Arrays.asList(items));
093 if (list.size() > 0)
094 selectedItem = list.get(0);
095 }
096
097 /**
098 * Creates a new model and initializes its item list to the values in the
099 * given vector. The selected item is set to the first item in the vector,
100 * or <code>null</code> if the vector length is zero.
101 *
102 * @param vector a vector containing items for the model (<code>null</code>
103 * not permitted).
104 *
105 * @throws NullPointerException if <code>vector</code> is <code>null</code>.
106 */
107 public DefaultComboBoxModel(Vector<?> vector)
108 {
109 this.list = vector;
110 if (getSize() > 0)
111 selectedItem = vector.get(0);
112 }
113
114 /**
115 * Adds an element to the model's item list and sends a {@link ListDataEvent}
116 * to all registered listeners. If the new element is the first item added
117 * to the list, and the selected item is <code>null</code>, the new element
118 * is set as the selected item.
119 *
120 * @param object item to add to the model's item list.
121 */
122 public void addElement(Object object)
123 {
124 list.addElement(object);
125 int index = list.size() - 1;
126 fireIntervalAdded(this, index, index);
127 if (list.size() == 1 && selectedItem == null)
128 setSelectedItem(object);
129 }
130
131 /**
132 * Removes the element at the specified index from the model's item list
133 * and sends a {@link ListDataEvent} to all registered listeners. If the
134 * element removed was the selected item, then the preceding element becomes
135 * the new selected item (or the next element, if there is no preceding
136 * element).
137 *
138 * @param index the index of the item to remove.
139 *
140 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
141 * bounds.
142 */
143 public void removeElementAt(int index)
144 {
145 int selected = getIndexOf(selectedItem);
146 if (selected == index) // choose a new selected item
147 {
148 if (selected > 0)
149 setSelectedItem(getElementAt(selected - 1));
150 else
151 setSelectedItem(getElementAt(selected + 1));
152 }
153 list.removeElementAt(index);
154 fireIntervalRemoved(this, index, index);
155 }
156
157 /**
158 * Adds an element at the specified index in the model's item list
159 * and sends a {@link ListDataEvent} to all registered listeners.
160 *
161 * @param object element to insert
162 * @param index index specifing position in the list where given element
163 * should be inserted.
164 *
165 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of
166 * bounds.
167 *
168 * @see #addElement(Object)
169 */
170 public void insertElementAt(Object object, int index)
171 {
172 list.insertElementAt(object, index);
173 fireIntervalAdded(this, index, index);
174 }
175
176 /**
177 * Removes an element from the model's item list and sends a
178 * {@link ListDataEvent} to all registered listeners. If the item to be
179 * removed is the current selected item, a new selected item will be set.
180 * If the element is not found in the model's item list, this method does
181 * nothing.
182 *
183 * @param object the element to remove.
184 */
185 public void removeElement(Object object)
186 {
187 int index = getIndexOf(object);
188 if (index != -1)
189 removeElementAt(index);
190 }
191
192 /**
193 * Removes all the items from the model's item list, resets and selected item
194 * to <code>null</code>, and sends a {@link ListDataEvent} to all registered
195 * listeners.
196 */
197 public void removeAllElements()
198 {
199 selectedItem = null;
200 int size = getSize();
201 if (size > 0)
202 {
203 list.clear();
204 fireIntervalRemoved(this, 0, size - 1);
205 }
206 }
207
208 /**
209 * Returns the number of items in the model's item list.
210 *
211 * @return The number of items in the model's item list.
212 */
213 public int getSize()
214 {
215 return list.size();
216 }
217
218 /**
219 * Sets the selected item for the model and sends a {@link ListDataEvent} to
220 * all registered listeners. The start and end index of the event is set to
221 * -1 to indicate the model's selection has changed, and not its contents.
222 *
223 * @param object the new selected item (<code>null</code> permitted).
224 */
225 public void setSelectedItem(Object object)
226 {
227 // No item is selected and object is null, so no change required.
228 if (selectedItem == null && object == null)
229 return;
230
231 // object is already selected so no change required.
232 if (selectedItem != null && selectedItem.equals(object))
233 return;
234
235 // Simply return if object is not in the list.
236 if (object != null && getIndexOf(object) == -1)
237 return;
238
239 // Here we know that object is either an item in the list or null.
240
241 // Handle the three change cases: selectedItem is null, object is
242 // non-null; selectedItem is non-null, object is null;
243 // selectedItem is non-null, object is non-null and they're not
244 // equal.
245 selectedItem = object;
246 fireContentsChanged(this, -1, -1);
247 }
248
249 /**
250 * Returns the selected item.
251 *
252 * @return The selected item (possibly <code>null</code>).
253 */
254 public Object getSelectedItem()
255 {
256 return selectedItem;
257 }
258
259 /**
260 * Returns the element at the specified index in the model's item list.
261 *
262 * @param index the element index.
263 *
264 * @return The element at the specified index in the model's item list, or
265 * <code>null</code> if the <code>index</code> is outside the bounds
266 * of the list.
267 */
268 public Object getElementAt(int index)
269 {
270 if (index < 0 || index >= list.size())
271 return null;
272 return list.elementAt(index);
273 }
274
275 /**
276 * Returns the index of the specified element in the model's item list.
277 *
278 * @param object the element.
279 *
280 * @return The index of the specified element in the model's item list.
281 */
282 public int getIndexOf(Object object)
283 {
284 return list.indexOf(object);
285 }
286 }