001: package com.silvermindsoftware.hitch.swing;
002:
003: import javax.swing.*;
004: import java.util.Arrays;
005: import java.util.List;
006:
007: /**
008: * Copyright 2007 Brandon Goodin
009: *
010: * Licensed under the Apache License, Version 2.0 (the "License");
011: * you may not use this file except in compliance with the License.
012: * You may obtain a copy of the License at
013: *
014: * http://www.apache.org/licenses/LICENSE-2.0
015: *
016: * Unless required by applicable law or agreed to in writing, software
017: * distributed under the License is distributed on an "AS IS" BASIS,
018: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
019: * See the License for the specific language governing permissions and
020: * limitations under the License.
021: */
022:
023: /**
024: * This is a pretty much a direct copy of the SpinnerListModel from JDK 1.5 sources.
025: * It was copied out in order to expose methods that needed to be publicly available
026: * in order to allow for completion to work properly with a list of complex objects
027: * that present their human readable value from a toString(). The findNextMatch
028: * method was exposed as public.
029: */
030: public class EnhancedSpinnerListModel extends SpinnerListModel {
031:
032: private List list;
033: private int index;
034:
035: /**
036: * Constructs a <code>SpinnerModel</code> whose sequence of
037: * values is defined by the specified <code>List</code>.
038: * The initial value (<i>current element</i>)
039: * of the model will be <code>values.get(0)</code>.
040: * If <code>values</code> is <code>null</code> or has zero
041: * size, an <code>IllegalArugmentException</code> is thrown.
042: *
043: * @param values the sequence this model represents
044: * @throws IllegalArugmentException if <code>values</code> is
045: * <code>null</code> or zero size
046: */
047: @SuppressWarnings({"JavadocReference"})
048: public EnhancedSpinnerListModel(List<?> values) {
049: if (values == null || values.size() == 0) {
050: throw new IllegalArgumentException(
051: "SpinnerListModel(List) expects non-null non-empty List");
052: }
053: this .list = values;
054: this .index = 0;
055: }
056:
057: /**
058: * Constructs a <code>SpinnerModel</code> whose sequence of values
059: * is defined by the specified array. The initial value of the model
060: * will be <code>values[0]</code>. If <code>values</code> is
061: * <code>null</code> or has zero length, an
062: * <code>IllegalArugmentException</code> is thrown.
063: *
064: * @param values the sequence this model represents
065: * @throws IllegalArugmentException if <code>values</code> is
066: * <code>null</code> or zero length
067: */
068: @SuppressWarnings({"JavadocReference"})
069: public EnhancedSpinnerListModel(Object[] values) {
070: if (values == null || values.length == 0) {
071: throw new IllegalArgumentException(
072: "SpinnerListModel(Object[]) expects non-null non-empty Object[]");
073: }
074: this .list = Arrays.asList(values);
075: this .index = 0;
076: }
077:
078: /**
079: * Constructs an effectively empty <code>SpinnerListModel</code>.
080: * The model's list will contain a single
081: * <code>"empty"</code> string element.
082: */
083: public EnhancedSpinnerListModel() {
084: this (new Object[] { "empty" });
085: }
086:
087: /**
088: * Returns the <code>List</code> that defines the sequence for this model.
089: *
090: * @return the value of the <code>list</code> property
091: * @see #setList
092: */
093: public List<?> getList() {
094: return list;
095: }
096:
097: /**
098: * Changes the list that defines this sequence and resets the index
099: * of the models <code>value</code> to zero. Note that <code>list</code>
100: * is not copied, the model just stores a reference to it.
101: * <p/>
102: * This method fires a <code>ChangeEvent</code> if <code>list</code> is
103: * not equal to the current list.
104: *
105: * @param list the sequence that this model represents
106: * @throws IllegalArgumentException if <code>list</code> is
107: * <code>null</code> or zero length
108: * @see #getList
109: */
110: public void setList(List<?> list) {
111: if ((list == null) || (list.size() == 0)) {
112: throw new IllegalArgumentException("invalid list");
113: }
114: if (!list.equals(this .list)) {
115: this .list = list;
116: index = 0;
117: fireStateChanged();
118: }
119: }
120:
121: /**
122: * Returns the current element of the sequence.
123: *
124: * @return the <code>value</code> property
125: * @see javax.swing.SpinnerModel#getValue
126: * @see #setValue
127: */
128: public Object getValue() {
129: return list.get(index);
130: }
131:
132: /**
133: * Changes the current element of the sequence and notifies
134: * <code>ChangeListeners</code>. If the specified
135: * value is not equal to an element of the underlying sequence
136: * then an <code>IllegalArgumentException</code> is thrown.
137: * In the following example the <code>setValue</code> call
138: * would cause an exception to be thrown:
139: * <pre>
140: * String[] values = {"one", "two", "free", "four"};
141: * SpinnerModel model = new SpinnerListModel(values);
142: * model.setValue("TWO");
143: * </pre>
144: *
145: * @param elt the sequence element that will be model's current value
146: * @throws IllegalArgumentException if the specified value isn't allowed
147: * @see javax.swing.SpinnerModel#setValue
148: * @see #getValue
149: */
150: public void setValue(Object elt) {
151: int index = list.indexOf(elt);
152: if (index == -1) {
153: throw new IllegalArgumentException(
154: "invalid sequence element");
155: } else if (index != this .index) {
156: this .index = index;
157: fireStateChanged();
158: }
159: }
160:
161: /**
162: * Returns the next legal value of the underlying sequence or
163: * <code>null</code> if value is already the last element.
164: *
165: * @return the next legal value of the underlying sequence or
166: * <code>null</code> if value is already the last element
167: * @see javax.swing.SpinnerModel#getNextValue
168: * @see #getPreviousValue
169: */
170: public Object getNextValue() {
171: return (index >= (list.size() - 1)) ? null : list
172: .get(index + 1);
173: }
174:
175: /**
176: * Returns the previous element of the underlying sequence or
177: * <code>null</code> if value is already the first element.
178: *
179: * @return the previous element of the underlying sequence or
180: * <code>null</code> if value is already the first element
181: * @see javax.swing.SpinnerModel#getPreviousValue
182: * @see #getNextValue
183: */
184: public Object getPreviousValue() {
185: return (index <= 0) ? null : list.get(index - 1);
186: }
187:
188: /**
189: * Returns the next object that starts with <code>substring</code>.
190: *
191: * @param substring the string to be matched
192: * @return the match
193: */
194: public Object findNextMatch(String substring) {
195: int max = list.size();
196:
197: if (max == 0) {
198: return null;
199: }
200: int counter = index;
201:
202: do {
203: Object value = list.get(counter);
204: String string = value.toString();
205:
206: if (string != null && string.startsWith(substring)) {
207: return value;
208: }
209: counter = (counter + 1) % max;
210: } while (counter != index);
211: return null;
212: }
213:
214: }
|