META-INF.modules.java.desktop.classes.javax.swing.SpinnerDateModel Maven / Gradle / Ivy
Show all versions of java.desktop Show documentation
/*
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.util.*;
import java.io.Serializable;
/**
* A SpinnerModel
for sequences of Date
s.
* The upper and lower bounds of the sequence are defined by properties called
* start
and end
and the size
* of the increase or decrease computed by the nextValue
* and previousValue
methods is defined by a property
* called calendarField
. The start
* and end
properties can be null
to
* indicate that the sequence has no lower or upper limit.
*
* The value of the calendarField
property must be one of the
* java.util.Calendar
constants that specify a field
* within a Calendar
. The getNextValue
* and getPreviousValue
* methods change the date forward or backwards by this amount.
* For example, if calendarField
is Calendar.DAY_OF_WEEK
,
* then nextValue
produces a Date
that's 24
* hours after the current value
, and previousValue
* produces a Date
that's 24 hours earlier.
*
* The legal values for calendarField
are:
*
* Calendar.ERA
* Calendar.YEAR
* Calendar.MONTH
* Calendar.WEEK_OF_YEAR
* Calendar.WEEK_OF_MONTH
* Calendar.DAY_OF_MONTH
* Calendar.DAY_OF_YEAR
* Calendar.DAY_OF_WEEK
* Calendar.DAY_OF_WEEK_IN_MONTH
* Calendar.AM_PM
* Calendar.HOUR
* Calendar.HOUR_OF_DAY
* Calendar.MINUTE
* Calendar.SECOND
* Calendar.MILLISECOND
*
* However some UIs may set the calendarField before committing the edit
* to spin the field under the cursor. If you only want one field to
* spin you can subclass and ignore the setCalendarField calls.
*
* This model inherits a ChangeListener
. The
* ChangeListeners
are notified whenever the models
* value
, calendarField
,
* start
, or end
properties changes.
*
* @see JSpinner
* @see SpinnerModel
* @see AbstractSpinnerModel
* @see SpinnerListModel
* @see SpinnerNumberModel
* @see Calendar#add
*
* @author Hans Muller
* @since 1.4
*/
@SuppressWarnings("serial") // Superclass is not serializable across versions
public class SpinnerDateModel extends AbstractSpinnerModel implements Serializable
{
private Comparable start, end;
private Calendar value;
private int calendarField;
private boolean calendarFieldOK(int calendarField) {
switch(calendarField) {
case Calendar.ERA:
case Calendar.YEAR:
case Calendar.MONTH:
case Calendar.WEEK_OF_YEAR:
case Calendar.WEEK_OF_MONTH:
case Calendar.DAY_OF_MONTH:
case Calendar.DAY_OF_YEAR:
case Calendar.DAY_OF_WEEK:
case Calendar.DAY_OF_WEEK_IN_MONTH:
case Calendar.AM_PM:
case Calendar.HOUR:
case Calendar.HOUR_OF_DAY:
case Calendar.MINUTE:
case Calendar.SECOND:
case Calendar.MILLISECOND:
return true;
default:
return false;
}
}
/**
* Creates a SpinnerDateModel
that represents a sequence of dates
* between start
and end
. The
* nextValue
and previousValue
methods
* compute elements of the sequence by advancing or reversing
* the current date value
by the
* calendarField
time unit. For a precise description
* of what it means to increment or decrement a Calendar
* field
, see the add
method in
* java.util.Calendar
.
*
* The start
and end
parameters can be
* null
to indicate that the range doesn't have an
* upper or lower bound. If value
or
* calendarField
is null
, or if both
* start
and end
are specified and
* minimum > maximum
then an
* IllegalArgumentException
is thrown.
* Similarly if (minimum <= value <= maximum)
is false,
* an IllegalArgumentException is thrown.
*
* @param value the current (non null
) value of the model
* @param start the first date in the sequence or null
* @param end the last date in the sequence or null
* @param calendarField one of
*
* Calendar.ERA
* Calendar.YEAR
* Calendar.MONTH
* Calendar.WEEK_OF_YEAR
* Calendar.WEEK_OF_MONTH
* Calendar.DAY_OF_MONTH
* Calendar.DAY_OF_YEAR
* Calendar.DAY_OF_WEEK
* Calendar.DAY_OF_WEEK_IN_MONTH
* Calendar.AM_PM
* Calendar.HOUR
* Calendar.HOUR_OF_DAY
* Calendar.MINUTE
* Calendar.SECOND
* Calendar.MILLISECOND
*
*
* @throws IllegalArgumentException if value
or
* calendarField
are null
,
* if calendarField
isn't valid,
* or if the following expression is
* false: (start <= value <= end)
.
*
* @see Calendar#add
* @see #setValue
* @see #setStart
* @see #setEnd
* @see #setCalendarField
*/
public SpinnerDateModel(Date value, Comparable start, Comparable end, int calendarField) {
if (value == null) {
throw new IllegalArgumentException("value is null");
}
if (!calendarFieldOK(calendarField)) {
throw new IllegalArgumentException("invalid calendarField");
}
if (!(((start == null) || (start.compareTo(value) <= 0)) &&
((end == null) || (end.compareTo(value) >= 0)))) {
throw new IllegalArgumentException("(start <= value <= end) is false");
}
this.value = Calendar.getInstance();
this.start = start;
this.end = end;
this.calendarField = calendarField;
this.value.setTime(value);
}
/**
* Constructs a SpinnerDateModel
whose initial
* value
is the current date, calendarField
* is equal to Calendar.DAY_OF_MONTH
, and for which
* there are no start
/end
limits.
*/
public SpinnerDateModel() {
this(new Date(), null, null, Calendar.DAY_OF_MONTH);
}
/**
* Changes the lower limit for Dates in this sequence.
* If start
is null
,
* then there is no lower limit. No bounds checking is done here:
* the new start value may invalidate the
* (start <= value <= end)
* invariant enforced by the constructors. This is to simplify updating
* the model. Naturally one should ensure that the invariant is true
* before calling the nextValue
, previousValue
,
* or setValue
methods.
*
* Typically this property is a Date
however it's possible to use
* a Comparable
with a compareTo
method for Dates.
* For example start
might be an instance of a class like this:
*
* MyStartDate implements Comparable {
* long t = 12345;
* public int compareTo(Date d) {
* return (t < d.getTime() ? -1 : (t == d.getTime() ? 0 : 1));
* }
* public int compareTo(Object o) {
* return compareTo((Date)o);
* }
* }
*
* Note that the above example will throw a ClassCastException
* if the Object
passed to compareTo(Object)
* is not a Date
.
*
* This method fires a ChangeEvent
if the
* start
has changed.
*
* @param start defines the first date in the sequence
* @see #getStart
* @see #setEnd
* @see #addChangeListener
*/
public void setStart(Comparable start) {
if ((start == null) ? (this.start != null) : !start.equals(this.start)) {
this.start = start;
fireStateChanged();
}
}
/**
* Returns the first Date
in the sequence.
*
* @return the value of the start
property
* @see #setStart
*/
public Comparable getStart() {
return start;
}
/**
* Changes the upper limit for Date
s in this sequence.
* If start
is null
, then there is no upper
* limit. No bounds checking is done here: the new
* start value may invalidate the (start <= value <= end)
* invariant enforced by the constructors. This is to simplify updating
* the model. Naturally, one should ensure that the invariant is true
* before calling the nextValue
, previousValue
,
* or setValue
methods.
*
* Typically this property is a Date
however it's possible to use
* Comparable
with a compareTo
method for
* Date
s. See setStart
for an example.
*
* This method fires a ChangeEvent
if the end
* has changed.
*
* @param end defines the last date in the sequence
* @see #getEnd
* @see #setStart
* @see #addChangeListener
*/
public void setEnd(Comparable end) {
if ((end == null) ? (this.end != null) : !end.equals(this.end)) {
this.end = end;
fireStateChanged();
}
}
/**
* Returns the last Date
in the sequence.
*
* @return the value of the end
property
* @see #setEnd
*/
public Comparable getEnd() {
return end;
}
/**
* Changes the size of the date value change computed
* by the nextValue
and previousValue
methods.
* The calendarField
parameter must be one of the
* Calendar
field constants like Calendar.MONTH
* or Calendar.MINUTE
.
* The nextValue
and previousValue
methods
* simply move the specified Calendar
field forward or backward
* by one unit with the Calendar.add
method.
* You should use this method with care as some UIs may set the
* calendarField before committing the edit to spin the field under
* the cursor. If you only want one field to spin you can subclass
* and ignore the setCalendarField calls.
*
* @param calendarField one of
*
* Calendar.ERA
* Calendar.YEAR
* Calendar.MONTH
* Calendar.WEEK_OF_YEAR
* Calendar.WEEK_OF_MONTH
* Calendar.DAY_OF_MONTH
* Calendar.DAY_OF_YEAR
* Calendar.DAY_OF_WEEK
* Calendar.DAY_OF_WEEK_IN_MONTH
* Calendar.AM_PM
* Calendar.HOUR
* Calendar.HOUR_OF_DAY
* Calendar.MINUTE
* Calendar.SECOND
* Calendar.MILLISECOND
*
*
* This method fires a ChangeEvent
if the
* calendarField
has changed.
*
* @see #getCalendarField
* @see #getNextValue
* @see #getPreviousValue
* @see Calendar#add
* @see #addChangeListener
*/
public void setCalendarField(int calendarField) {
if (!calendarFieldOK(calendarField)) {
throw new IllegalArgumentException("invalid calendarField");
}
if (calendarField != this.calendarField) {
this.calendarField = calendarField;
fireStateChanged();
}
}
/**
* Returns the Calendar
field that is added to or subtracted from
* by the nextValue
and previousValue
methods.
*
* @return the value of the calendarField
property
* @see #setCalendarField
*/
public int getCalendarField() {
return calendarField;
}
/**
* Returns the next Date
in the sequence, or null
if
* the next date is after end
.
*
* @return the next Date
in the sequence, or null
if
* the next date is after end
.
*
* @see SpinnerModel#getNextValue
* @see #getPreviousValue
* @see #setCalendarField
*/
public Object getNextValue() {
Calendar cal = Calendar.getInstance();
cal.setTime(value.getTime());
cal.add(calendarField, 1);
Date next = cal.getTime();
return ((end == null) || (end.compareTo(next) >= 0)) ? next : null;
}
/**
* Returns the previous Date
in the sequence, or null
* if the previous date is before start
.
*
* @return the previous Date
in the sequence, or
* null
if the previous date
* is before start
*
* @see SpinnerModel#getPreviousValue
* @see #getNextValue
* @see #setCalendarField
*/
public Object getPreviousValue() {
Calendar cal = Calendar.getInstance();
cal.setTime(value.getTime());
cal.add(calendarField, -1);
Date prev = cal.getTime();
return ((start == null) || (start.compareTo(prev) <= 0)) ? prev : null;
}
/**
* Returns the current element in this sequence of Date
s.
* This method is equivalent to (Date)getValue
.
*
* @return the value
property
* @see #setValue
*/
public Date getDate() {
return value.getTime();
}
/**
* Returns the current element in this sequence of Date
s.
*
* @return the value
property
* @see #setValue
* @see #getDate
*/
public Object getValue() {
return value.getTime();
}
/**
* Sets the current Date
for this sequence.
* If value
is null
,
* an IllegalArgumentException
is thrown. No bounds
* checking is done here:
* the new value may invalidate the (start <= value < end)
* invariant enforced by the constructors. Naturally, one should ensure
* that the (start <= value <= maximum)
invariant is true
* before calling the nextValue
, previousValue
,
* or setValue
methods.
*
* This method fires a ChangeEvent
if the
* value
has changed.
*
* @param value the current (non null
)
* Date
for this sequence
* @throws IllegalArgumentException if value is null
* or not a Date
* @see #getDate
* @see #getValue
* @see #addChangeListener
*/
public void setValue(Object value) {
if ((value == null) || !(value instanceof Date)) {
throw new IllegalArgumentException("illegal value");
}
if (!value.equals(this.value.getTime())) {
this.value.setTime((Date)value);
fireStateChanged();
}
}
}