001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package javax.microedition.lcdui;
028:
029: import java.util.Calendar;
030: import java.util.Date;
031: import java.util.TimeZone;
032:
033: /**
034: * A <code>DateField</code> is an editable component for presenting
035: * date and time (calendar)
036: * information that may be placed into a <code>Form</code>. Value for
037: * this field can be
038: * initially set or left unset. If value is not set then the UI for the field
039: * shows this clearly. The field value for "not initialized
040: * state" is not valid
041: * value and <code>getDate()</code> for this state returns <code>null</code>.
042: * <p>
043: * Instance of a <code>DateField</code> can be configured to accept
044: * date or time information
045: * or both of them. This input mode configuration is done by
046: * <code>DATE</code>, <code>TIME</code> or
047: * <code>DATE_TIME</code> static fields of this
048: * class. <code>DATE</code> input mode allows to set only
049: * date information and <code>TIME</code> only time information
050: * (hours, minutes). <code>DATE_TIME</code>
051: * allows to set both clock time and date values.
052: * <p>
053: * In <code>TIME</code> input mode the date components of
054: * <code>Date</code> object
055: * must be set to the "zero epoch" value of January 1, 1970.
056: * <p>
057: * Calendar calculations in this field are based on default locale and defined
058: * time zone. Because of the calculations and different input modes date object
059: * may not contain same millisecond value when set to this field and get back
060: * from this field.
061: * @since MIDP 1.0
062: */
063: public class DateField extends Item {
064:
065: /**
066: * Input mode for date information (day, month, year). With this mode this
067: * <code>DateField</code> presents and allows only to modify date
068: * value. The time
069: * information of date object is ignored.
070: *
071: * <P>Value <code>1</code> is assigned to <code>DATE</code>.</P>
072: */
073: public static final int DATE = 1;
074:
075: /**
076: * Input mode for time information (hours and minutes). With this mode this
077: * <code>DateField</code> presents and allows only to modify
078: * time. The date components
079: * should be set to the "zero epoch" value of January 1, 1970 and
080: * should not be accessed.
081: *
082: * <P>Value <code>2</code> is assigned to <code>TIME</code>.</P>
083: */
084: public static final int TIME = 2;
085:
086: /**
087: * Input mode for date (day, month, year) and time (minutes, hours)
088: * information. With this mode this <code>DateField</code>
089: * presents and allows to modify
090: * both time and date information.
091: *
092: * <P>Value <code>3</code> is assigned to <code>DATE_TIME</code>.</P>
093: */
094: public static final int DATE_TIME = 3;
095:
096: /**
097: * Creates a <code>DateField</code> object with the specified
098: * label and mode. This call
099: * is identical to <code>DateField(label, mode, null)</code>.
100: *
101: * @param label item label
102: * @param mode the input mode, one of <code>DATE</code>, <code>TIME</code>
103: * or <code>DATE_TIME</code>
104: * @throws IllegalArgumentException if the input <code>mode's</code>
105: * value is invalid
106: */
107: public DateField(String label, int mode) {
108: this (label, mode, null);
109: }
110:
111: /**
112: * Creates a date field in which calendar calculations are based
113: * on specific
114: * <code>TimeZone</code> object and the default calendaring system for the
115: * current locale.
116: * The value of the <code>DateField</code> is initially in the
117: * "uninitialized" state.
118: * If <code>timeZone</code> is <code>null</code>, the system's
119: * default time zone is used.
120: *
121: * @param label item label
122: * @param mode the input mode, one of <code>DATE</code>, <code>TIME</code>
123: * or <code>DATE_TIME</code>
124: * @param timeZone a specific time zone, or <code>null</code> for the
125: * default time zone
126: * @throws IllegalArgumentException if the input <code>mode's</code> value
127: * is invalid
128: */
129: public DateField(String label, int mode, java.util.TimeZone timeZone) {
130: super (label);
131:
132: synchronized (Display.LCDUILock) {
133: if ((mode != DATE) && (mode != TIME) && (mode != DATE_TIME)) {
134: throw new IllegalArgumentException("Invalid input mode");
135: }
136:
137: this .mode = mode;
138:
139: if (timeZone == null) {
140: timeZone = TimeZone.getDefault();
141: }
142:
143: this .currentDate = Calendar.getInstance(timeZone);
144:
145: itemLF = dateFieldLF = LFFactory.getFactory()
146: .getDateFieldLF(this );
147:
148: } // synchronized
149: }
150:
151: /**
152: * Returns date value of this field. Returned value is
153: * <code>null</code> if field
154: * value is
155: * not initialized. The date object is constructed according the rules of
156: * locale specific calendaring system and defined time zone.
157: *
158: * In <code>TIME</code> mode field the date components are set to
159: * the "zero
160: * epoch" value of January 1, 1970. If a date object that presents
161: * time beyond one day from this "zero epoch" then this field
162: * is in "not
163: * initialized" state and this method returns <code>null</code>.
164: *
165: * In <code>DATE</code> mode field the time component of the calendar is
166: * set to zero when constructing the date object.
167: *
168: * @return date object representing time or date depending on input mode
169: * @see #setDate
170: */
171: public java.util.Date getDate() {
172: synchronized (Display.LCDUILock) {
173: // NOTE:
174: // defensive copy of the Date object is necessary
175: // because CLDC's Calendar returns a reference to an internal,
176: // shared Date object. See bugID: 4479408.
177:
178: // original:
179: // return (initialized ?
180: // new java.util.Date(currentDate.getTime().getTime()) : null);
181:
182: if (initialized) {
183: java.util.Date retDate = dateFieldLF.lGetDate();
184: if (retDate == null) {
185: return new java.util.Date(currentDate.getTime()
186: .getTime());
187: } else {
188: return retDate;
189: }
190: }
191:
192: return null;
193:
194: } // synchronized
195: }
196:
197: /**
198: * Sets a new value for this field. <code>null</code> can be
199: * passed to set the field
200: * state to "not initialized" state. The input mode of
201: * this field defines
202: * what components of passed <code>Date</code> object is used.<p>
203: *
204: * In <code>TIME</code> input mode the date components must be set
205: * to the "zero
206: * epoch" value of January 1, 1970. If a date object that presents
207: * time
208: * beyond one day then this field is in "not initialized" state.
209: * In <code>TIME</code> input mode the date component of
210: * <code>Date</code> object is ignored and time
211: * component is used to precision of minutes.<p>
212: *
213: * In <code>DATE</code> input mode the time component of
214: * <code>Date</code> object is ignored.<p>
215: *
216: * In <code>DATE_TIME</code> input mode the date and time
217: * component of <code>Date</code> are used but
218: * only to precision of minutes.
219: *
220: * @param date new value for this field
221: * @see #getDate
222: */
223: public void setDate(java.util.Date date) {
224: synchronized (Display.LCDUILock) {
225: setDateImpl(date);
226: dateFieldLF.lSetDate(date);
227: } // synchronized
228: }
229:
230: /**
231: * Gets input mode for this date field. Valid input modes are
232: * <code>DATE</code>, <code>TIME</code> and <code>DATE_TIME</code>.
233: *
234: * @return input mode of this field
235: * @see #setInputMode
236: */
237: public int getInputMode() {
238: // SYNC NOTE: return of atomic value, no locking necessary
239: return mode;
240: }
241:
242: /**
243: * Set input mode for this date field. Valid input modes are
244: * <code>DATE</code>, <code>TIME</code> and <code>DATE_TIME</code>.
245: *
246: * @param mode the input mode, must be one of <code>DATE</code>,
247: * <code>TIME</code> or <code>DATE_TIME</code>
248: * @throws IllegalArgumentException if an invalid value is specified
249: * @see #getInputMode
250: */
251: public void setInputMode(int mode) {
252:
253: if ((mode != DATE) && (mode != TIME) && (mode != DATE_TIME)) {
254: throw new IllegalArgumentException("Invalid input mode");
255: }
256:
257: synchronized (Display.LCDUILock) {
258: if (this .mode != mode) {
259: this .mode = mode;
260:
261: // While the input mode is changed
262: // some irrelevant values for new mode could be lost.
263: // Currently that is allowed by the spec.
264:
265: // So for TIME mode we make sure that time is set
266: // on a zero epoch date
267: // and for DATE mode we zero out hours and minutes
268: if (mode == TIME) {
269: currentDate.set(Calendar.YEAR, 1970);
270: currentDate.set(Calendar.MONTH, Calendar.JANUARY);
271: currentDate.set(Calendar.DATE, 1);
272: } else if (mode == DATE) {
273: currentDate.set(Calendar.HOUR, 0);
274: currentDate.set(Calendar.HOUR_OF_DAY, 0);
275: currentDate.set(Calendar.MINUTE, 0);
276: }
277: dateFieldLF.lSetInputMode(mode);
278: }
279: } // synchronized
280: }
281:
282: // package private
283: /**
284: * Sets the date.
285: * @param date the date value to set to.
286: */
287: void setDateImpl(java.util.Date date) {
288:
289: if (date == null) {
290: initialized = false;
291: } else {
292: currentDate.setTime(date);
293:
294: if (mode == TIME) {
295:
296: if (currentDate.getTime().getTime() >= 24 * 60 * 60 * 1000) {
297: initialized = false;
298: } else {
299: currentDate.set(Calendar.YEAR, 1970);
300: currentDate.set(Calendar.MONTH, Calendar.JANUARY);
301: currentDate.set(Calendar.DATE, 1);
302: initialized = true;
303: }
304: } else {
305: // Currently spec does not prohibit from losing
306: // irrelevant for that mode information
307: // so we always zero out hours and minutes
308:
309: // NOTE: the specification doesn't prohibit
310: // the loss of information irrelevant to
311: // the current input mode, so we always zero out the
312: // hours and minutes.
313: if (mode == DATE) {
314: currentDate.set(Calendar.HOUR, 0);
315: currentDate.set(Calendar.HOUR_OF_DAY, 0);
316: currentDate.set(Calendar.MINUTE, 0);
317: }
318: initialized = true;
319: }
320:
321: // always ignore seconds and milliseconds
322: currentDate.set(Calendar.SECOND, 0);
323: currentDate.set(Calendar.MILLISECOND, 0);
324: }
325: }
326:
327: /**
328: * Return whether the Item takes user input focus.
329: *
330: * @return Always return <code>true</code>
331: */
332: boolean acceptFocus() {
333: return true;
334: }
335:
336: /**
337: * The look&feel associated with this DateField.
338: * Set in the constructor.
339: */
340: DateFieldLF dateFieldLF; // = null
341:
342: /**
343: * A flag indicating the initialization state of this DateField
344: */
345: boolean initialized; // = false;
346:
347: /**
348: * The mode of this DateField
349: */
350: int mode;
351:
352: /**
353: * The last saved date.
354: * This is used for making the last saved date bold.
355: */
356: Calendar currentDate;
357:
358: }
|