blob: bcaa0c3211da571b2ec22da204f45375d5be77cd [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2004 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package javax.swing;
27
28import java.util.*;
29import java.io.Serializable;
30
31
32/**
33 * A simple implementation of <code>SpinnerModel</code> whose
34 * values are defined by an array or a <code>List</code>.
35 * For example to create a model defined by
36 * an array of the names of the days of the week:
37 * <pre>
38 * String[] days = new DateFormatSymbols().getWeekdays();
39 * SpinnerModel model = new SpinnerListModel(Arrays.asList(days).subList(1, 8));
40 * </pre>
41 * This class only stores a reference to the array or <code>List</code>
42 * so if an element of the underlying sequence changes, it's up
43 * to the application to notify the <code>ChangeListeners</code> by calling
44 * <code>fireStateChanged</code>.
45 * <p>
46 * This model inherits a <code>ChangeListener</code>.
47 * The <code>ChangeListener</code>s are notified whenever the
48 * model's <code>value</code> or <code>list</code> properties changes.
49 *
50 * @see JSpinner
51 * @see SpinnerModel
52 * @see AbstractSpinnerModel
53 * @see SpinnerNumberModel
54 * @see SpinnerDateModel
55 *
56 * @author Hans Muller
57 * @since 1.4
58 */
59public class SpinnerListModel extends AbstractSpinnerModel implements Serializable
60{
61 private List list;
62 private int index;
63
64
65 /**
66 * Constructs a <code>SpinnerModel</code> whose sequence of
67 * values is defined by the specified <code>List</code>.
68 * The initial value (<i>current element</i>)
69 * of the model will be <code>values.get(0)</code>.
70 * If <code>values</code> is <code>null</code> or has zero
71 * size, an <code>IllegalArugmentException</code> is thrown.
72 *
73 * @param values the sequence this model represents
74 * @throws IllegalArugmentException if <code>values</code> is
75 * <code>null</code> or zero size
76 */
77 public SpinnerListModel(List<?> values) {
78 if (values == null || values.size() == 0) {
79 throw new IllegalArgumentException("SpinnerListModel(List) expects non-null non-empty List");
80 }
81 this.list = values;
82 this.index = 0;
83 }
84
85
86 /**
87 * Constructs a <code>SpinnerModel</code> whose sequence of values
88 * is defined by the specified array. The initial value of the model
89 * will be <code>values[0]</code>. If <code>values</code> is
90 * <code>null</code> or has zero length, an
91 * <code>IllegalArugmentException</code> is thrown.
92 *
93 * @param values the sequence this model represents
94 * @throws IllegalArugmentException if <code>values</code> is
95 * <code>null</code> or zero length
96 */
97 public SpinnerListModel(Object[] values) {
98 if (values == null || values.length == 0) {
99 throw new IllegalArgumentException("SpinnerListModel(Object[]) expects non-null non-empty Object[]");
100 }
101 this.list = Arrays.asList(values);
102 this.index = 0;
103 }
104
105
106 /**
107 * Constructs an effectively empty <code>SpinnerListModel</code>.
108 * The model's list will contain a single
109 * <code>"empty"</code> string element.
110 */
111 public SpinnerListModel() {
112 this(new Object[]{"empty"});
113 }
114
115
116 /**
117 * Returns the <code>List</code> that defines the sequence for this model.
118 *
119 * @return the value of the <code>list</code> property
120 * @see #setList
121 */
122 public List<?> getList() {
123 return list;
124 }
125
126
127 /**
128 * Changes the list that defines this sequence and resets the index
129 * of the models <code>value</code> to zero. Note that <code>list</code>
130 * is not copied, the model just stores a reference to it.
131 * <p>
132 * This method fires a <code>ChangeEvent</code> if <code>list</code> is
133 * not equal to the current list.
134 *
135 * @param list the sequence that this model represents
136 * @throws IllegalArgumentException if <code>list</code> is
137 * <code>null</code> or zero length
138 * @see #getList
139 */
140 public void setList(List<?> list) {
141 if ((list == null) || (list.size() == 0)) {
142 throw new IllegalArgumentException("invalid list");
143 }
144 if (!list.equals(this.list)) {
145 this.list = list;
146 index = 0;
147 fireStateChanged();
148 }
149 }
150
151
152 /**
153 * Returns the current element of the sequence.
154 *
155 * @return the <code>value</code> property
156 * @see SpinnerModel#getValue
157 * @see #setValue
158 */
159 public Object getValue() {
160 return list.get(index);
161 }
162
163
164 /**
165 * Changes the current element of the sequence and notifies
166 * <code>ChangeListeners</code>. If the specified
167 * value is not equal to an element of the underlying sequence
168 * then an <code>IllegalArgumentException</code> is thrown.
169 * In the following example the <code>setValue</code> call
170 * would cause an exception to be thrown:
171 * <pre>
172 * String[] values = {"one", "two", "free", "four"};
173 * SpinnerModel model = new SpinnerListModel(values);
174 * model.setValue("TWO");
175 * </pre>
176 *
177 * @param elt the sequence element that will be model's current value
178 * @throws IllegalArgumentException if the specified value isn't allowed
179 * @see SpinnerModel#setValue
180 * @see #getValue
181 */
182 public void setValue(Object elt) {
183 int index = list.indexOf(elt);
184 if (index == -1) {
185 throw new IllegalArgumentException("invalid sequence element");
186 }
187 else if (index != this.index) {
188 this.index = index;
189 fireStateChanged();
190 }
191 }
192
193
194 /**
195 * Returns the next legal value of the underlying sequence or
196 * <code>null</code> if value is already the last element.
197 *
198 * @return the next legal value of the underlying sequence or
199 * <code>null</code> if value is already the last element
200 * @see SpinnerModel#getNextValue
201 * @see #getPreviousValue
202 */
203 public Object getNextValue() {
204 return (index >= (list.size() - 1)) ? null : list.get(index + 1);
205 }
206
207
208 /**
209 * Returns the previous element of the underlying sequence or
210 * <code>null</code> if value is already the first element.
211 *
212 * @return the previous element of the underlying sequence or
213 * <code>null</code> if value is already the first element
214 * @see SpinnerModel#getPreviousValue
215 * @see #getNextValue
216 */
217 public Object getPreviousValue() {
218 return (index <= 0) ? null : list.get(index - 1);
219 }
220
221
222 /**
223 * Returns the next object that starts with <code>substring</code>.
224 *
225 * @param substring the string to be matched
226 * @return the match
227 */
228 Object findNextMatch(String substring) {
229 int max = list.size();
230
231 if (max == 0) {
232 return null;
233 }
234 int counter = index;
235
236 do {
237 Object value = list.get(counter);
238 String string = value.toString();
239
240 if (string != null && string.startsWith(substring)) {
241 return value;
242 }
243 counter = (counter + 1) % max;
244 } while (counter != index);
245 return null;
246 }
247}