Frames | No Frames |
1: /* SpinnerDateModel.java -- 2: Copyright (C) 2002, 2004, 2006 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: 39: package javax.swing; 40: 41: import java.io.Serializable; 42: import java.util.Calendar; 43: import java.util.Date; 44: 45: import javax.swing.event.ChangeEvent; 46: 47: /** 48: * A date model used by the {@link JSpinner} component. This implements a 49: * spinner model for dates, rotating a calendar field such as month, year, 50: * day, week, hour, minute. 51: * 52: * @author Sven de Marothy 53: * @since 1.4 54: */ 55: public class SpinnerDateModel extends AbstractSpinnerModel 56: implements Serializable 57: { 58: /** The current date. */ 59: private Calendar date; 60: 61: /** 62: * A constraint on the start or earliest permitted date (<code>null</code> 63: * for no minimum). 64: */ 65: private Comparable start; 66: 67: /** 68: * A constraint on the end or latest permitted date (<code>null</code> for no 69: * maximum). 70: */ 71: private Comparable end; 72: 73: /** 74: * The calendar field used to calculate the previous or next date. 75: */ 76: private int calendarField; 77: 78: /** 79: * For compatability with Sun's JDK 80: */ 81: private static final long serialVersionUID = -4802518107105940612L; 82: 83: /** 84: * Constructs a <code>SpinnerDateModel</code> using the current date, 85: * no start or end limit, and {@link Calendar#DAY_OF_MONTH} as the calendar 86: * field. 87: */ 88: public SpinnerDateModel() 89: { 90: this(new Date(), null, null, Calendar.DAY_OF_MONTH); 91: } 92: 93: /** 94: * Constructs a <code>SpinnerDateModel</code> with the specified value, lower 95: * and upper bounds, and which spins the specified calendar field. 96: * <p> 97: * The <code>start</code> and <code>end</code> limits must have a 98: * <code>compareTo</code> method that supports instances of {@link Date}, but 99: * do not themselves need to be instances of {@link Date} (although typically 100: * they are). 101: * 102: * @param value the initial value/date (<code>null</code> not permitted). 103: * @param start a constraint that specifies the earliest permitted date 104: * value, or <code>null</code> for no lower limit. 105: * @param end a constraint that specifies the latest permitted date value, 106: * or <code>null</code> for no upper limit. 107: * @param calendarField the <code>Calendar</code> field to spin, 108: * (Calendar.ZONE_OFFSET and Calendar.DST_OFFSET are invalid) 109: */ 110: public SpinnerDateModel(Date value, Comparable start, Comparable end, 111: int calendarField) 112: { 113: if (value == null) 114: throw new IllegalArgumentException("Null 'value' argument."); 115: if (start != null && start.compareTo(value) > 0) 116: throw new IllegalArgumentException("Require value on or after start."); 117: if (end != null && end.compareTo(value) < 0) 118: throw new IllegalArgumentException("Require value on or before end."); 119: date = Calendar.getInstance(); 120: date.setTime(value); 121: this.start = start; 122: this.end = end; 123: setCalendarField(calendarField); 124: } 125: 126: /** 127: * Returns the {@link Calendar} field used to calculate the previous and 128: * next dates in the sequence. 129: * 130: * @return The date field code. 131: */ 132: public int getCalendarField() 133: { 134: return calendarField; 135: } 136: 137: /** 138: * Returns the current date/time. 139: * 140: * @return The current date/time (never <code>null</code>). 141: * 142: * @see #getValue() 143: */ 144: public Date getDate() 145: { 146: return date.getTime(); 147: } 148: 149: /** 150: * Returns the lower limit on the date/time value, or <code>null</code> if 151: * there is no minimum date/time. 152: * 153: * @return The lower limit. 154: * 155: * @see #setStart(Comparable) 156: */ 157: public Comparable getStart() 158: { 159: return start; 160: } 161: 162: /** 163: * Returns the upper limit on the date/time value, or <code>null</code> if 164: * there is no maximum date/time. 165: * 166: * @return The upper limit. 167: * 168: * @see #setEnd(Comparable) 169: */ 170: public Comparable getEnd() 171: { 172: return end; 173: } 174: 175: /** 176: * Returns the current date in the sequence (this method returns the same as 177: * {@link #getDate()}). 178: * 179: * @return The current date (never <code>null</code>). 180: */ 181: public Object getValue() 182: { 183: return date.getTime(); 184: } 185: 186: /** 187: * Returns the next date in the sequence, or <code>null</code> if the 188: * next date is past the upper limit (if one is specified). The current date 189: * is not changed. 190: * 191: * @return The next date, or <code>null</code> if the current value is 192: * the latest date represented by the model. 193: * 194: * @see #getEnd() 195: */ 196: public Object getNextValue() 197: { 198: Calendar nextCal = Calendar.getInstance(); 199: nextCal.setTime(date.getTime()); 200: nextCal.roll(calendarField, true); 201: Date nextDate = nextCal.getTime(); 202: if (end != null) 203: if (end.compareTo(nextDate) < 0) 204: return null; 205: return nextDate; 206: } 207: 208: /** 209: * Returns the previous date in the sequence, or <code>null</code> if the 210: * previous date is prior to the lower limit (if one is specified). The 211: * current date is not changed. 212: * 213: * @return The previous date, or <code>null</code> if the current value is 214: * the earliest date represented by the model. 215: * 216: * @see #getStart() 217: */ 218: public Object getPreviousValue() 219: { 220: Calendar prevCal = Calendar.getInstance(); 221: prevCal.setTime(date.getTime()); 222: prevCal.roll(calendarField, false); 223: Date prevDate = prevCal.getTime(); 224: if (start != null) 225: if (start.compareTo(prevDate) > 0) 226: return null; 227: return prevDate; 228: } 229: 230: /** 231: * Sets the date field to change when calculating the next and previous 232: * values. It must be a valid {@link Calendar} field, excluding 233: * {@link Calendar#ZONE_OFFSET} and {@link Calendar#DST_OFFSET}. 234: * 235: * @param calendarField the calendar field to set. 236: * 237: * @throws IllegalArgumentException if <code>calendarField</code> is not 238: * a valid code. 239: */ 240: public void setCalendarField(int calendarField) 241: { 242: if (calendarField < 0 || calendarField >= Calendar.FIELD_COUNT 243: || calendarField == Calendar.ZONE_OFFSET 244: || calendarField == Calendar.DST_OFFSET) 245: throw new IllegalArgumentException("Illegal calendarField"); 246: 247: if (this.calendarField != calendarField) 248: { 249: this.calendarField = calendarField; 250: fireStateChanged(); 251: } 252: } 253: 254: /** 255: * Sets the lower limit for the date/time value and, if the new limit is 256: * different to the old limit, sends a {@link ChangeEvent} to all registered 257: * listeners. A <code>null</code> value is interpreted as "no lower limit". 258: * No check is made to ensure that the current date/time is on or after the 259: * new lower limit - the caller is responsible for ensuring that this 260: * relationship holds. In addition, the caller should ensure that 261: * <code>start</code> is {@link Serializable}. 262: * 263: * @param start the new lower limit for the date/time value 264: * (<code>null</code> permitted). 265: */ 266: public void setStart(Comparable start) 267: { 268: if (this.start != start) 269: { 270: this.start = start; 271: fireStateChanged(); 272: } 273: } 274: 275: /** 276: * Sets the upper limit for the date/time value and, if the new limit is 277: * different to the old limit, sends a {@link ChangeEvent} to all registered 278: * listeners. A <code>null</code> value is interpreted as "no upper limit". 279: * No check is made to ensure that the current date/time is on or before the 280: * new upper limit - the caller is responsible for ensuring that this 281: * relationship holds. In addition, the caller should ensure that 282: * <code>end</code> is {@link Serializable}. 283: * 284: * @param end the new upper limit for the date/time value (<code>null</code> 285: * permitted). 286: */ 287: public void setEnd(Comparable end) 288: { 289: if (this.end != end) 290: { 291: this.end = end; 292: fireStateChanged(); 293: } 294: } 295: 296: /** 297: * Sets the current date and, if the new value is different to the old 298: * value, sends a {@link ChangeEvent} to all registered listeners. 299: * 300: * @param value the new date (<code>null</code> not permitted, must be an 301: * instance of <code>Date</code>). 302: * 303: * @throws IllegalArgumentException if <code>value</code> is not an instance 304: * of <code>Date</code>. 305: */ 306: public void setValue(Object value) 307: { 308: if (! (value instanceof Date) || value == null) 309: throw new IllegalArgumentException("Value not a date."); 310: 311: if (!date.getTime().equals(value)) 312: { 313: date.setTime((Date) value); 314: fireStateChanged(); 315: } 316: } 317: }