42
42
import java.util.Calendar;
43
43
import java.util.Date;
45
import javax.swing.event.ChangeEvent;
48
* Implements a SpinnerModel for dates, rotating a calendar field such as
49
* month, year, day, week, hour, minute.
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
52
* @version 0.1 (first implementation)
54
55
public class SpinnerDateModel extends AbstractSpinnerModel
55
56
implements Serializable
58
/** The current date. */
57
59
private Calendar date;
62
* A constraint on the start or earliest permitted date (<code>null</code>
58
65
private Comparable start;
68
* A constraint on the end or latest permitted date (<code>null</code> for no
59
71
private Comparable end;
74
* The calendar field used to calculate the previous or next date.
60
76
private int calendarField;
63
79
* For compatability with Sun's JDK
64
* FIXME: Which fields should be serialized?
66
81
private static final long serialVersionUID = -4802518107105940612L;
69
* Constructs a SpinnerDateModel using the current date,
70
* no start or end limit, and Calendar.DAY_OF_MONTH as the calendar field.
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
72
88
public SpinnerDateModel()
78
* Constructs a SpinnerDateModel which spins a given calendar field,
79
* using a given date and start and end date limits.
80
* @param value - the initial Date value
81
* @param start - start limit, as a Date object, or <code>null</code>
83
* @param end - end limit, or <code>null</code> for no upper limit.
84
* @param calendarField - the <code>Calendar</code> field to spin,
85
* (Calendar.ZONE_OFFSET and Calendar.DST_OFFSET are invalid)
94
* Constructs a <code>SpinnerDateModel</code> with the specified value, lower
95
* and upper bounds, and which spins the specified calendar field.
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
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)
87
110
public SpinnerDateModel(Date value, Comparable start, Comparable end,
88
111
int calendarField)
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.");
90
119
date = Calendar.getInstance();
91
120
date.setTime(value);
92
121
this.start = start;
115
* Returns the starting limit of the SpinnerModel.
116
* @return a Date object, or <code>null</code> if there is no limit.
150
* Returns the lower limit on the date/time value, or <code>null</code> if
151
* there is no minimum date/time.
153
* @return The lower limit.
155
* @see #setStart(Comparable)
118
157
public Comparable getStart()
124
* Returns the end limit of the SpinnerModel.
125
* @return a Date object, or <code>null</code> if there is no limit.
163
* Returns the upper limit on the date/time value, or <code>null</code> if
164
* there is no maximum date/time.
166
* @return The upper limit.
168
* @see #setEnd(Comparable)
127
170
public Comparable getEnd()
143
187
* Returns the next date in the sequence, or <code>null</code> if the
144
* next date is equal to or past the end limit.
145
* @return a Date object, or <code>null</code>.
188
* next date is past the upper limit (if one is specified). The current date
191
* @return The next date, or <code>null</code> if the current value is
192
* the latest date represented by the model.
147
196
public Object getNextValue()
152
201
Date nextDate = nextCal.getTime();
154
203
if (end.compareTo(nextDate) < 0)
160
209
* Returns the previous date in the sequence, or <code>null</code> if the
161
* next date is equal to or past the end limit.
162
* @return a Date object, or <code>null</code>.
210
* previous date is prior to the lower limit (if one is specified). The
211
* current date is not changed.
213
* @return The previous date, or <code>null</code> if the current value is
214
* the earliest date represented by the model.
164
218
public Object getPreviousValue()
167
221
prevCal.setTime(date.getTime());
168
222
prevCal.roll(calendarField, false);
169
223
Date prevDate = prevCal.getTime();
171
if (end.compareTo(prevDate) > 0)
225
if (start.compareTo(prevDate) > 0)
177
* Sets the date field to change. It must be a valid Calendar field,
178
* excluding Calendar.ZONE_OFFSET and Calendar.DST_OFFSET.
179
* @param calendarField - the calendar field to set.
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}.
235
* @param calendarField the calendar field to set.
237
* @throws IllegalArgumentException if <code>calendarField</code> is not
181
240
public void setCalendarField(int calendarField)
188
247
if (this.calendarField != calendarField)
190
this.calendarField = calendarField;
249
this.calendarField = calendarField;
196
* Sets the starting date limit for the sequence.
198
* @param start - a Date object of the limit date,
199
* or <code>null</code> for no limit.
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}.
263
* @param start the new lower limit for the date/time value
264
* (<code>null</code> permitted).
201
266
public void setStart(Comparable start)
203
268
if (this.start != start)
211
* Sets the end date limit for the sequence.
213
* @param end - a Date object of the limit date,
214
* or <code>null</code> for no limit.
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}.
284
* @param end the new upper limit for the date/time value (<code>null</code>
216
287
public void setEnd(Comparable end)
218
289
if (this.end != end)
226
* Sets the current date in the sequence.
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.
228
* @param value - a Date object.
300
* @param value the new date (<code>null</code> not permitted, must be an
301
* instance of <code>Date</code>).
303
* @throws IllegalArgumentException if <code>value</code> is not an instance
304
* of <code>Date</code>.
230
306
public void setValue(Object value)
232
308
if (! (value instanceof Date) || value == null)
233
309
throw new IllegalArgumentException("Value not a date.");
234
date.setTime((Date) value);
311
if (!date.getTime().equals(value))
313
date.setTime((Date) value);