Frames | No Frames |
1: /* SpinnerListModel.java -- A spinner model backed by a list or an array. 2: Copyright (C) 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package javax.swing; 39: 40: import java.io.Serializable; 41: import java.util.ArrayList; 42: import java.util.Arrays; 43: import java.util.List; 44: 45: import javax.swing.event.ChangeEvent; 46: 47: /** 48: * An implementation of <code>SpinnerModel</code> which uses the values 49: * contained within a list or an array. The backing list or array is 50: * only stored as a reference within the class. As a result, changes 51: * made elsewhere to the members of the list or array are reflected by 52: * this model. 53: * <p> 54: * 55: * The model itself inherits a list of <code>ChangeListener</code>s from 56: * <code>AbstractSpinnerModel</code>. As this code is unaware of changes 57: * made to the backing list or array, it is the responsibility of the 58: * application using the model to invoke <code>fireStateChanged()</code>, 59: * in order to notify any <code>ChangeListener</code>s, when the list or array 60: * changes. The model handles notification when the reference itself 61: * is changed via <code>setList()</code> or when the current value is 62: * set directly using <code>setValue()</code>. 63: * 64: * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 65: * @see SpinnerModel 66: * @see AbstractSpinnerModel 67: * @see JSpinner 68: * @since 1.4 69: */ 70: 71: public class SpinnerListModel extends AbstractSpinnerModel 72: implements Serializable 73: { 74: /** 75: * For compatability with Sun's JDK 76: */ 77: private static final long serialVersionUID = 3358804052191994516L; 78: 79: /** 80: * The backing list for this model. 81: */ 82: private List list; 83: 84: /** 85: * The current index in the list. 86: */ 87: private transient int index; 88: 89: /** 90: * Constructs a default <code>SpinnerListModel</code>. This 91: * is a model backed by a list containing only the single 92: * <code>String</code> element, "empty". 93: */ 94: public SpinnerListModel() 95: { 96: List defaultList; 97: 98: // Create an empty list. 99: defaultList = new ArrayList(); 100: // Add the string "empty". 101: defaultList.add("empty"); 102: // Set the list. 103: setList(defaultList); 104: } 105: 106: /** 107: * Constructs a <code>SpinnerListModel</code> using the supplied list. 108: * The model maintains a reference to this list, and returns 109: * consecutive elements in response to calls to <code>getNextValue()</code>. 110: * The initial value is that at position 0, so an initial call 111: * to <code>getValue()</code> returns the same as <code>list.get(0)</code>. 112: * 113: * @param list The list to use for this model. 114: * 115: * @throws IllegalArgumentException if the list is null or contains no 116: * elements. 117: * 118: * @see SpinnerListModel#getNextValue() 119: * @see SpinnerListModel#getValue() 120: */ 121: public SpinnerListModel(List<?> list) 122: { 123: // Retain a reference to the valid list. 124: setList(list); 125: } 126: 127: /** 128: * Constructs a <code>SpinnerListModel</code> using the supplied array. 129: * The model stores a reference to the wrapper list returned by 130: * <code>Arrays.asList()</code>. The wrapper list reflects modifications 131: * in the underlying array, so these changes will also be reflected 132: * by the model. The model produces consecutive elements from the array 133: * in response to calls to <code>getNextValue()</code>. The initial 134: * value returned by <code>getValue()</code> is the same as 135: * <code>array[0]</code>. 136: * 137: * @param array The array to use for this model. 138: * 139: * @throws IllegalArgumentException if the array is null or contains 140: * no elements. 141: * 142: * @see Arrays#asList(Object[]) 143: * @see SpinnerListModel#getNextValue() 144: * @see SpinnerListModel#getValue() 145: */ 146: public SpinnerListModel(Object[] array) 147: { 148: // Check for a null or zero-sized array. 149: if (array == null || array.length == 0) 150: { 151: throw new IllegalArgumentException("The supplied array was invalid."); 152: } 153: 154: // Retain a reference to a wrapper around the valid array. 155: // The array, in list form, will be tested again here, but we can't really 156: // avoid this -- a null value to Arrays.asList will throw a 157: // NullPointerException. 158: setList(Arrays.asList(array)); 159: } 160: 161: /** 162: * Returns the backing list for this model. 163: * 164: * @return The backing list. 165: */ 166: public List<?> getList() 167: { 168: return list; 169: } 170: 171: /** 172: * Returns the next value from the list, which is the same as the element 173: * stored at the current index + 1. Null is returned if there are no more 174: * values to be returned (the end of the list has been reached). An 175: * ambiguity can occur here, as null may also be returned as a valid list 176: * element. This operation does not change the current value. 177: * 178: * @return The next value from the list or null. 179: */ 180: public Object getNextValue() 181: { 182: // Check for a next value. 183: if (index < (list.size() - 1)) 184: // Return the element at the next index. 185: return list.get(index + 1); 186: else 187: // Return null as this is the end of the list. 188: return null; 189: } 190: 191: /** 192: * Returns the previous value from the list, which is the same as the element 193: * stored at the current index - 1. Null is returned if there are no more 194: * values to be returned (the start of the list has been reached). An 195: * ambiguity can occur here, as null may also be returned as a valid list 196: * element. This operation does not change the current value. 197: * 198: * @return The previous value from the list or null. 199: */ 200: public Object getPreviousValue() 201: { 202: // Check for a previous value. 203: if (index > 0) 204: // Return the element at the previous position. 205: return list.get(index - 1); 206: else 207: // Return null as this is the start of the list. 208: return null; 209: } 210: 211: /** 212: * Returns the current value of the model. Initially, this will 213: * be the element at position 0. On later invocations, this will 214: * be the last element returned by <code>getNextValue()</code> 215: * or <code>getPreviousValue()</code>. 216: * 217: * @return The current value. 218: * 219: * @see SpinnerListModel#getPreviousValue() 220: * @see SpinnerListModel#getNextValue() 221: */ 222: public Object getValue() 223: { 224: return list.get(index); 225: } 226: 227: /** 228: * Changes the backing list for this model. The model only stores 229: * a reference to the list, so any changes made to the list elsewhere 230: * will be reflected in the values returned by the model. A 231: * <code>ChangeEvent</code> is fired if the list being used actually 232: * changes (i.e. the new list is not referentially equal (!=) to the 233: * old one). 234: * 235: * @param list The new list to use. 236: * 237: * @throws IllegalArgumentException if the list is null or contains 238: * no elements. 239: * 240: * @see ChangeEvent 241: */ 242: public void setList(List<?> list) 243: { 244: // Check for null or zero size list. 245: if (list == null || list.size() == 0) 246: throw new IllegalArgumentException("The supplied list was invalid."); 247: 248: // Check for a change of referenced list. 249: if (this.list != list) 250: { 251: // Store the new list. 252: this.list = list; 253: // Notify listeners of a change. 254: fireStateChanged(); 255: } 256: // We reset the other values in either case. 257: // Set the index to 0. 258: index = 0; 259: } 260: 261: /** 262: * Sets the current value of the model to be the one supplied. 263: * The value must exist within the backing list in order for 264: * the change to take place. Otherwise, an exception is thrown. 265: * The value used is the first occurrence of the value within 266: * the backing list. Listeners are notified of this change. 267: * Following the change, <code>getNextValue()</code> and 268: * <code>getPreviousValue()</code> return the objects following 269: * and prior to the supplied value, respectively. 270: * 271: * @param value The requested new value of the list. 272: * 273: * @throws IllegalArgumentException if the supplied value does 274: * not exist in the backing list. 275: * 276: * @see SpinnerListModel#getPreviousValue() 277: * @see SpinnerListModel#getNextValue() 278: */ 279: public void setValue(Object value) 280: { 281: int valueIndex; 282: 283: // Search for the value in the list. 284: valueIndex = list.indexOf(value); 285: // Check for the value being found. 286: if (valueIndex == -1) 287: throw new IllegalArgumentException("The supplied value does not " 288: + "exist in this list"); 289: // Make the indices match. 290: index = valueIndex; 291: // Notify the listeners. 292: fireStateChanged(); 293: } 294: 295: }