001: package com.jidesoft.spinner;
002:
003: import javax.swing.*;
004: import javax.swing.text.DefaultFormatter;
005: import javax.swing.text.InternationalFormatter;
006: import java.text.DateFormat;
007: import java.text.Format;
008: import java.util.Calendar;
009: import java.util.Date;
010: import java.util.TimeZone;
011:
012: /**
013: * <code>DateSpinner</code> is a spinner that is specialized in displaying or editing a a date or time.
014: * <p/>
015: * To change the value, you can use {@link #setValue(Object)} and pass in a Date. To get the
016: * Date, using {@link #getValue()}.
017: */
018: public class DateSpinner extends JSpinner {
019: public DefaultFormatter _formatter;
020: public DateEditor _timeEditor;
021: public DateFormat _format;
022:
023: /**
024: * Creates a date spinner using "hh:mm:ss" as the format string.
025: */
026: public DateSpinner() {
027: this ("hh:mm:ss");
028: }
029:
030: /**
031: * Creates a date spinner using the specified format string.
032: *
033: * @param format the format string as defined in {@link java.text.SimpleDateFormat}.
034: */
035: public DateSpinner(String format) {
036: this (format, new Date());
037: }
038:
039: /**
040: * Creates a date spinner using the specified format string and an initial value.
041: *
042: * @param format the format string as defined in {@link java.text.SimpleDateFormat}.
043: * @param date initial value
044: */
045: public DateSpinner(String format, Date date) {
046: super (new SpinnerDateModel(date, null, null,
047: Calendar.DAY_OF_MONTH));
048: // setBorder(BorderFactory.createEmptyBorder());
049: // setOpaque(true);
050:
051: setFormat(format);
052:
053: customizeSpinner();
054: }
055:
056: private void customizeDateEditor() {
057: // _timeEditor.setBorder(BorderFactory.createEmptyBorder());
058: JFormattedTextField.AbstractFormatter formatter = _timeEditor
059: .getTextField().getFormatter();
060: if (formatter instanceof DefaultFormatter) {
061: _formatter = (DefaultFormatter) formatter;
062: } else {
063: throw new IllegalStateException(
064: "The formatter is not an instance of DefaultFormatter.");
065: }
066:
067: if (formatter instanceof InternationalFormatter) {
068: Format f = ((InternationalFormatter) formatter).getFormat();
069: if (f instanceof DateFormat) {
070: _format = ((DateFormat) f);
071: }
072: }
073:
074: if (_format == null) {
075: throw new IllegalStateException(
076: "The format is not an instance of SimpleDateFormat.");
077: }
078: }
079:
080: /**
081: * Sets the date format string used by this DateSpinner. Please note, this method call
082: * will receate the DateEditor used by DateSpinner.
083: *
084: * @param format the format
085: */
086: public void setFormat(String format) {
087: _timeEditor = createDateEditor(format);
088: customizeDateEditor();
089: setEditor(_timeEditor);
090: }
091:
092: /**
093: * Customizes the spinner.
094: */
095: protected void customizeSpinner() {
096: setLenient(false);
097: setCommitsOnValidEdit(true);
098: setAllowsInvalid(false);
099: setOverwriteMode(true);
100: SpinnerWheelSupport.installMouseWheelSupport(this );
101: }
102:
103: /**
104: * Creates the DateEditor.
105: *
106: * @param format the format
107: * @return the DateEditor.
108: */
109: protected DateEditor createDateEditor(String format) {
110: return new DateEditor(this , format);
111: }
112:
113: /**
114: * Sets when edits are published back to the
115: * <code>JFormattedTextField</code>. If true, <code>commitEdit</code>
116: * is invoked after every valid edit (any time the text is edited). On
117: * the other hand, if this is false than the <code>DefaultFormatter</code>
118: * does not publish edits back to the <code>JFormattedTextField</code>.
119: * As such, the only time the value of the <code>JFormattedTextField</code>
120: * will change is when <code>commitEdit</code> is invoked on
121: * <code>JFormattedTextField</code>, typically when enter is pressed
122: * or focus leaves the <code>JFormattedTextField</code>.
123: *
124: * @param commit Used to indicate when edits are commited back to the
125: * JTextComponent
126: */
127: public void setCommitsOnValidEdit(boolean commit) {
128: _formatter.setCommitsOnValidEdit(commit);
129: }
130:
131: /**
132: * Returns when edits are published back to the
133: * <code>JFormattedTextField</code>.
134: *
135: * @return true if edits are commited after evey valid edit
136: */
137: public boolean getCommitsOnValidEdit() {
138: return _formatter.getCommitsOnValidEdit();
139: }
140:
141: /**
142: * Configures the behavior when inserting characters. If
143: * <code>overwriteMode</code> is true (the default), new characters
144: * overwrite existing characters in the model.
145: *
146: * @param overwriteMode Indicates if overwrite or overstrike mode is used
147: */
148: public void setOverwriteMode(boolean overwriteMode) {
149: _formatter.setOverwriteMode(overwriteMode);
150: }
151:
152: /**
153: * Returns the behavior when inserting characters.
154: *
155: * @return true if newly inserted characters overwrite existing characters
156: */
157: public boolean getOverwriteMode() {
158: return _formatter.getOverwriteMode();
159: }
160:
161: /**
162: * Sets whether or not the value being edited is allowed to be invalid
163: * for a length of time (that is, <code>stringToValue</code> throws
164: * a <code>ParseException</code>).
165: * It is often convenient to allow the user to temporarily input an
166: * invalid value.
167: *
168: * @param allowsInvalid Used to indicate if the edited value must always
169: * be valid
170: */
171: public void setAllowsInvalid(boolean allowsInvalid) {
172: _formatter.setAllowsInvalid(allowsInvalid);
173: }
174:
175: /**
176: * Returns whether or not the value being edited is allowed to be invalid
177: * for a length of time.
178: *
179: * @return false if the edited value must always be valid
180: */
181: public boolean getAllowsInvalid() {
182: return _formatter.getAllowsInvalid();
183: }
184:
185: /**
186: * Sets the time zone for the calendar of this DateFormat object.
187: *
188: * @param zone the given new time zone.
189: */
190: public void setTimeZone(TimeZone zone) {
191: _format.setTimeZone(zone);
192: }
193:
194: /**
195: * Gets the time zone.
196: *
197: * @return the time zone associated with the calendar of DateFormat.
198: */
199: public TimeZone getTimeZone() {
200: return _format.getTimeZone();
201: }
202:
203: /**
204: * Specify whether or not date/time parsing is to be lenient. With
205: * lenient parsing, the parser may use heuristics to interpret inputs that
206: * do not precisely match this object's format. With strict parsing,
207: * inputs must match this object's format.
208: *
209: * @param lenient when true, parsing is lenient
210: * @see java.util.Calendar#setLenient
211: */
212: public void setLenient(boolean lenient) {
213: _format.setLenient(lenient);
214: }
215:
216: /**
217: * Tell whether date/time parsing is to be lenient. It is the same as {@link java.text.DateFormat#isLenient()}.
218: *
219: * @return true or false.
220: */
221: public boolean isLenient() {
222: return _format.isLenient();
223: }
224: }
|