1 /*******************************************************************************
2 * Copyright (c) 2000, 2012 IBM Corporation and others.
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
9 * SPDX-License-Identifier: EPL-2.0
12 * IBM Corporation - initial API and implementation
13 *******************************************************************************/
14 package org.eclipse.swt.widgets;
16 import org.eclipse.swt.*;
17 import org.eclipse.swt.events.*;
18 import org.eclipse.swt.graphics.*;
19 import org.eclipse.swt.internal.win32.*;
22 * Instances of this class are selectable user interface
23 * objects that allow the user to enter and modify date
26 * Note that although this class is a subclass of <code>Composite</code>,
27 * it does not make sense to add children to it, or set a layout on it.
30 * <dt><b>Styles:</b></dt>
31 * <dd>DATE, TIME, CALENDAR, SHORT, MEDIUM, LONG, DROP_DOWN, CALENDAR_WEEKNUMBERS</dd>
32 * <dt><b>Events:</b></dt>
33 * <dd>DefaultSelection, Selection</dd>
36 * Note: Only one of the styles DATE, TIME, or CALENDAR may be specified,
37 * and only one of the styles SHORT, MEDIUM, or LONG may be specified.
38 * The DROP_DOWN style is only valid with the DATE style.
40 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
43 * @see <a href="http://www.eclipse.org/swt/snippets/#datetime">DateTime snippets</a>
44 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
45 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
48 * @noextend This class is not intended to be subclassed by clients.
50 public class DateTime extends Composite {
51 static final int MIN_YEAR = 1752; // Gregorian switchover in North America: September 19, 1752
52 static final int MAX_YEAR = 9999;
53 boolean doubleClick, ignoreSelection;
54 SYSTEMTIME lastSystemTime;
55 SYSTEMTIME time = new SYSTEMTIME (); // only used in calendar mode
56 static final long DateTimeProc;
57 static final TCHAR DateTimeClass = new TCHAR (0, OS.DATETIMEPICK_CLASS, true);
58 static final long CalendarProc;
59 static final TCHAR CalendarClass = new TCHAR (0, OS.MONTHCAL_CLASS, true);
61 INITCOMMONCONTROLSEX icex = new INITCOMMONCONTROLSEX ();
62 icex.dwSize = INITCOMMONCONTROLSEX.sizeof;
63 icex.dwICC = OS.ICC_DATE_CLASSES;
64 OS.InitCommonControlsEx (icex);
67 WNDCLASS lpWndClass = new WNDCLASS ();
68 OS.GetClassInfo (0, DateTimeClass, lpWndClass);
69 DateTimeProc = lpWndClass.lpfnWndProc;
71 * Feature in Windows. The date time window class
72 * does not include CS_DBLCLKS. This means that these
73 * controls will not get double click messages such as
74 * WM_LBUTTONDBLCLK. The fix is to register a new
75 * window class with CS_DBLCLKS.
77 * NOTE: Screen readers look for the exact class name
78 * of the control in order to provide the correct kind
79 * of assistance. Therefore, it is critical that the
80 * new window class have the same name. It is possible
81 * to register a local window class with the same name
82 * as a global class. Since bits that affect the class
83 * are being changed, it is possible that other native
84 * code, other than SWT, could create a control with
85 * this class name, and fail unexpectedly.
87 lpWndClass.hInstance = OS.GetModuleHandle (null);
88 lpWndClass.style &= ~OS.CS_GLOBALCLASS;
89 lpWndClass.style |= OS.CS_DBLCLKS;
90 OS.RegisterClass (DateTimeClass, lpWndClass);
93 WNDCLASS lpWndClass = new WNDCLASS ();
94 OS.GetClassInfo (0, CalendarClass, lpWndClass);
95 CalendarProc = lpWndClass.lpfnWndProc;
97 * Feature in Windows. The date time window class
98 * does not include CS_DBLCLKS. This means that these
99 * controls will not get double click messages such as
100 * WM_LBUTTONDBLCLK. The fix is to register a new
101 * window class with CS_DBLCLKS.
103 * NOTE: Screen readers look for the exact class name
104 * of the control in order to provide the correct kind
105 * of assistance. Therefore, it is critical that the
106 * new window class have the same name. It is possible
107 * to register a local window class with the same name
108 * as a global class. Since bits that affect the class
109 * are being changed, it is possible that other native
110 * code, other than SWT, could create a control with
111 * this class name, and fail unexpectedly.
113 lpWndClass.hInstance = OS.GetModuleHandle (null);;
114 lpWndClass.style &= ~OS.CS_GLOBALCLASS;
115 lpWndClass.style |= OS.CS_DBLCLKS;
116 OS.RegisterClass (CalendarClass, lpWndClass);
118 static final char SINGLE_QUOTE = '\''; //$NON-NLS-1$ short date format may include quoted text
119 static final char DAY_FORMAT_CONSTANT = 'd'; //$NON-NLS-1$ 1-4 lowercase 'd's represent day
120 static final char MONTH_FORMAT_CONSTANT = 'M'; //$NON-NLS-1$ 1-4 uppercase 'M's represent month
121 static final char YEAR_FORMAT_CONSTANT = 'y'; //$NON-NLS-1$ 1-5 lowercase 'y's represent year
122 static final char HOURS_FORMAT_CONSTANT = 'h'; //$NON-NLS-1$ 1-2 upper or lowercase 'h's represent hours
123 static final char MINUTES_FORMAT_CONSTANT = 'm'; //$NON-NLS-1$ 1-2 lowercase 'm's represent minutes
124 static final char SECONDS_FORMAT_CONSTANT = 's'; //$NON-NLS-1$ 1-2 lowercase 's's represent seconds
125 static final char AMPM_FORMAT_CONSTANT = 't'; //$NON-NLS-1$ 1-2 lowercase 't's represent am/pm
129 * Constructs a new instance of this class given its parent
130 * and a style value describing its behavior and appearance.
132 * The style value is either one of the style constants defined in
133 * class <code>SWT</code> which is applicable to instances of this
134 * class, or must be built by <em>bitwise OR</em>'ing together
135 * (that is, using the <code>int</code> "|" operator) two or more
136 * of those <code>SWT</code> style constants. The class description
137 * lists the style constants that are applicable to the class.
138 * Style bits are also inherited from superclasses.
141 * @param parent a composite control which will be the parent of the new instance (cannot be null)
142 * @param style the style of control to construct
144 * @exception IllegalArgumentException <ul>
145 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
147 * @exception SWTException <ul>
148 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
149 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
155 * @see SWT#CALENDAR_WEEKNUMBERS
160 * @see Widget#checkSubclass
161 * @see Widget#getStyle
163 public DateTime (Composite parent, int style) {
164 super (parent, checkStyle (style));
165 if ((this.style & SWT.SHORT) != 0) {
166 String buffer = ((this.style & SWT.DATE) != 0) ? getCustomShortDateFormat() : getCustomShortTimeFormat();
167 TCHAR lpszFormat = new TCHAR (0, buffer, true);
168 OS.SendMessage (handle, OS.DTM_SETFORMAT, 0, lpszFormat);
173 * Adds the listener to the collection of listeners who will
174 * be notified when the control is selected by the user, by sending
175 * it one of the messages defined in the <code>SelectionListener</code>
178 * <code>widgetSelected</code> is called when the user changes the control's value.
179 * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed.
182 * @param listener the listener which should be notified
184 * @exception IllegalArgumentException <ul>
185 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
187 * @exception SWTException <ul>
188 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
189 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
192 * @see SelectionListener
193 * @see #removeSelectionListener
194 * @see SelectionEvent
196 public void addSelectionListener (SelectionListener listener) {
198 if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
199 TypedListener typedListener = new TypedListener (listener);
200 addListener (SWT.Selection, typedListener);
201 addListener (SWT.DefaultSelection, typedListener);
205 long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
206 if (handle == 0) return 0;
207 return OS.CallWindowProc (windowProc (), hwnd, msg, wParam, lParam);
210 static int checkStyle (int style) {
212 * Even though it is legal to create this widget
213 * with scroll bars, they serve no useful purpose
214 * because they do not automatically scroll the
215 * widget's client area. The fix is to clear
218 style &= ~(SWT.H_SCROLL | SWT.V_SCROLL);
219 style = checkBits (style, SWT.DATE, SWT.TIME, SWT.CALENDAR, 0, 0, 0);
220 style = checkBits (style, SWT.MEDIUM, SWT.SHORT, SWT.LONG, 0, 0, 0);
221 if ((style & SWT.DATE) == 0) style &=~ SWT.DROP_DOWN;
226 protected void checkSubclass () {
227 if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
230 @Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
232 int width = 0, height = 0;
233 if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) {
234 if ((style & SWT.CALENDAR) != 0) {
235 RECT rect = new RECT ();
236 OS.SendMessage(handle, OS.MCM_GETMINREQRECT, 0, rect);
238 height = rect.bottom;
240 // customize the style of the drop-down calendar, to get the correct size
241 if ((style & SWT.CALENDAR_WEEKNUMBERS) != 0) {
242 // get current style and add week numbers to the calendar drop-down
243 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
244 OS.SendMessage(handle, OS.DTM_SETMCSTYLE, 0, bits | OS.MCS_WEEKNUMBERS);
246 SIZE size = new SIZE ();
247 OS.SendMessage(handle, OS.DTM_GETIDEALSIZE, 0, size);
250 // TODO: Can maybe use DTM_GETDATETIMEPICKERINFO for this
251 int upDownHeight = OS.GetSystemMetrics (OS.SM_CYVSCROLL) + 7;
252 height = Math.max (height, upDownHeight);
255 if (width == 0) width = DEFAULT_WIDTH;
256 if (height == 0) height = DEFAULT_HEIGHT;
257 if (wHint != SWT.DEFAULT) width = wHint;
258 if (hHint != SWT.DEFAULT) height = hHint;
259 int border = getBorderWidthInPixels ();
261 height += border * 2;
262 return new Point (width, height);
266 void createHandle () {
267 super.createHandle ();
268 state &= ~(CANVAS | THEME_BACKGROUND);
270 if ((style & SWT.BORDER) == 0) {
271 int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
272 bits &= ~(OS.WS_EX_CLIENTEDGE | OS.WS_EX_STATICEDGE);
273 OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits);
278 int defaultBackground () {
279 return OS.GetSysColor (OS.COLOR_WINDOW);
282 String getCustomShortDateFormat () {
283 TCHAR tchar = new TCHAR (getCodePage (), 80);
284 int size = OS.GetLocaleInfo (OS.LOCALE_USER_DEFAULT, OS.LOCALE_SYEARMONTH, tchar, 80);
285 return size != 0 ? tchar.toString (0, size - 1) : "M/yyyy"; //$NON-NLS-1$
288 String getCustomShortTimeFormat () {
289 StringBuilder buffer = new StringBuilder (getTimeFormat ());
290 int length = buffer.length ();
291 boolean inQuotes = false;
292 int start = 0, end = 0;
293 while (start < length) {
294 char ch = buffer.charAt (start);
295 if (ch == SINGLE_QUOTE) inQuotes = !inQuotes;
296 else if (ch == SECONDS_FORMAT_CONSTANT && !inQuotes) {
298 while (end < length && buffer.charAt (end) == SECONDS_FORMAT_CONSTANT) end++;
299 // skip the preceding separator
300 while (start > 0 && buffer.charAt (start) != MINUTES_FORMAT_CONSTANT) start--;
306 if (start < end) buffer.delete (start, end);
307 return buffer.toString ();
310 String getTimeFormat () {
311 TCHAR tchar = new TCHAR (getCodePage (), 80);
312 int size = OS.GetLocaleInfo (OS.LOCALE_USER_DEFAULT, OS.LOCALE_STIMEFORMAT, tchar, 80);
313 return size > 0 ? tchar.toString (0, size - 1) : "h:mm:ss tt"; //$NON-NLS-1$
317 * Returns the receiver's date, or day of the month.
319 * The first day of the month is 1, and the last day depends on the month and year.
322 * @return a positive integer beginning with 1
324 * @exception SWTException <ul>
325 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
326 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
329 public int getDay () {
331 SYSTEMTIME systime = new SYSTEMTIME ();
332 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
333 OS.SendMessage (handle, msg, 0, systime);
338 * Returns the receiver's hours.
340 * Hours is an integer between 0 and 23.
343 * @return an integer between 0 and 23
345 * @exception SWTException <ul>
346 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
347 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
350 public int getHours () {
352 if ((style & SWT.CALENDAR) != 0) return time.wHour;
353 SYSTEMTIME systime = new SYSTEMTIME ();
354 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
355 OS.SendMessage (handle, msg, 0, systime);
356 return systime.wHour;
360 * Returns the receiver's minutes.
362 * Minutes is an integer between 0 and 59.
365 * @return an integer between 0 and 59
367 * @exception SWTException <ul>
368 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
369 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
372 public int getMinutes () {
374 if ((style & SWT.CALENDAR) != 0) return time.wMinute;
375 SYSTEMTIME systime = new SYSTEMTIME ();
376 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
377 OS.SendMessage (handle, msg, 0, systime);
378 return systime.wMinute;
382 * Returns the receiver's month.
384 * The first month of the year is 0, and the last month is 11.
387 * @return an integer between 0 and 11
389 * @exception SWTException <ul>
390 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
391 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
394 public int getMonth () {
396 SYSTEMTIME systime = new SYSTEMTIME ();
397 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
398 OS.SendMessage (handle, msg, 0, systime);
399 return systime.wMonth - 1;
403 String getNameText() {
404 return (style & SWT.TIME) != 0 ? getHours() + ":" + getMinutes() + ":" + getSeconds()
405 : (getMonth() + 1) + "/" + getDay() + "/" + getYear();
409 * Returns the receiver's seconds.
411 * Seconds is an integer between 0 and 59.
414 * @return an integer between 0 and 59
416 * @exception SWTException <ul>
417 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
418 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
421 public int getSeconds () {
423 if ((style & SWT.CALENDAR) != 0) return time.wSecond;
424 SYSTEMTIME systime = new SYSTEMTIME ();
425 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
426 OS.SendMessage (handle, msg, 0, systime);
427 return systime.wSecond;
431 * Returns the receiver's year.
433 * The first year is 1752 and the last year is 9999.
436 * @return an integer between 1752 and 9999
438 * @exception SWTException <ul>
439 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
440 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
443 public int getYear () {
445 SYSTEMTIME systime = new SYSTEMTIME ();
446 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
447 OS.SendMessage (handle, msg, 0, systime);
448 return systime.wYear;
452 void releaseWidget () {
453 super.releaseWidget ();
454 lastSystemTime = null;
458 * Removes the listener from the collection of listeners who will
459 * be notified when the control is selected by the user.
461 * @param listener the listener which should no longer be notified
463 * @exception IllegalArgumentException <ul>
464 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
466 * @exception SWTException <ul>
467 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
468 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
471 * @see SelectionListener
472 * @see #addSelectionListener
474 public void removeSelectionListener (SelectionListener listener) {
476 if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
477 if (eventTable == null) return;
478 eventTable.unhook (SWT.Selection, listener);
479 eventTable.unhook (SWT.DefaultSelection, listener);
483 * Sets the receiver's year, month, and day in a single operation.
485 * This is the recommended way to set the date, because setting the year,
486 * month, and day separately may result in invalid intermediate dates.
489 * @param year an integer between 1752 and 9999
490 * @param month an integer between 0 and 11
491 * @param day a positive integer beginning with 1
493 * @exception SWTException <ul>
494 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
495 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
500 public void setDate (int year, int month, int day) {
502 if (year < MIN_YEAR || year > MAX_YEAR) return;
503 SYSTEMTIME systime = new SYSTEMTIME ();
504 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
505 OS.SendMessage (handle, msg, 0, systime);
506 msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
507 systime.wYear = (short)year;
508 systime.wMonth = (short)(month + 1);
509 systime.wDay = (short)day;
510 OS.SendMessage (handle, msg, 0, systime);
511 lastSystemTime = null;
515 * Sets the receiver's date, or day of the month, to the specified day.
517 * The first day of the month is 1, and the last day depends on the month and year.
518 * If the specified day is not valid for the receiver's month and year, then it is ignored.
521 * @param day a positive integer beginning with 1
523 * @exception SWTException <ul>
524 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
525 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
530 public void setDay (int day) {
532 SYSTEMTIME systime = new SYSTEMTIME ();
533 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
534 OS.SendMessage (handle, msg, 0, systime);
535 msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
536 systime.wDay = (short)day;
537 OS.SendMessage (handle, msg, 0, systime);
538 lastSystemTime = null;
542 * Sets the receiver's hours.
544 * Hours is an integer between 0 and 23.
547 * @param hours an integer between 0 and 23
549 * @exception SWTException <ul>
550 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
551 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
554 public void setHours (int hours) {
556 if (hours < 0 || hours > 23) return;
557 SYSTEMTIME systime = new SYSTEMTIME ();
558 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
559 OS.SendMessage (handle, msg, 0, systime);
560 msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
561 systime.wHour = (short)hours;
562 OS.SendMessage (handle, msg, 0, systime);
563 if ((style & SWT.CALENDAR) != 0 && hours >= 0 && hours <= 23) time.wHour = (short)hours;
567 * Sets the receiver's minutes.
569 * Minutes is an integer between 0 and 59.
572 * @param minutes an integer between 0 and 59
574 * @exception SWTException <ul>
575 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
576 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
579 public void setMinutes (int minutes) {
581 if (minutes < 0 || minutes > 59) return;
582 SYSTEMTIME systime = new SYSTEMTIME ();
583 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
584 OS.SendMessage (handle, msg, 0, systime);
585 msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
586 systime.wMinute = (short)minutes;
587 OS.SendMessage (handle, msg, 0, systime);
588 if ((style & SWT.CALENDAR) != 0 && minutes >= 0 && minutes <= 59) time.wMinute = (short)minutes;
592 * Sets the receiver's month.
594 * The first month of the year is 0, and the last month is 11.
595 * If the specified month is not valid for the receiver's day and year, then it is ignored.
598 * @param month an integer between 0 and 11
600 * @exception SWTException <ul>
601 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
602 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
607 public void setMonth (int month) {
609 SYSTEMTIME systime = new SYSTEMTIME ();
610 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
611 OS.SendMessage (handle, msg, 0, systime);
612 msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
613 systime.wMonth = (short)(month + 1);
614 OS.SendMessage (handle, msg, 0, systime);
615 lastSystemTime = null;
619 public void setOrientation (int orientation) {
620 /* Currently supported only for CALENDAR style. */
621 if ((style & SWT.CALENDAR) != 0) super.setOrientation (orientation);
624 * Sets the receiver's seconds.
626 * Seconds is an integer between 0 and 59.
629 * @param seconds an integer between 0 and 59
631 * @exception SWTException <ul>
632 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
633 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
636 public void setSeconds (int seconds) {
638 if (seconds < 0 || seconds > 59) return;
639 SYSTEMTIME systime = new SYSTEMTIME ();
640 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
641 OS.SendMessage (handle, msg, 0, systime);
642 msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
643 systime.wSecond = (short)seconds;
644 OS.SendMessage (handle, msg, 0, systime);
645 if ((style & SWT.CALENDAR) != 0 && seconds >= 0 && seconds <= 59) time.wSecond = (short)seconds;
649 * Sets the receiver's hours, minutes, and seconds in a single operation.
651 * @param hours an integer between 0 and 23
652 * @param minutes an integer between 0 and 59
653 * @param seconds an integer between 0 and 59
655 * @exception SWTException <ul>
656 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
657 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
662 public void setTime (int hours, int minutes, int seconds) {
664 if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59) return;
665 SYSTEMTIME systime = new SYSTEMTIME ();
666 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
667 OS.SendMessage (handle, msg, 0, systime);
668 msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
669 systime.wHour = (short)hours;
670 systime.wMinute = (short)minutes;
671 systime.wSecond = (short)seconds;
672 OS.SendMessage (handle, msg, 0, systime);
673 if ((style & SWT.CALENDAR) != 0
674 && hours >= 0 && hours <= 23
675 && minutes >= 0 && minutes <= 59
676 && seconds >= 0 && seconds <= 59) {
677 time.wHour = (short)hours;
678 time.wMinute = (short)minutes;
679 time.wSecond = (short)seconds;
684 * Sets the receiver's year.
686 * The first year is 1752 and the last year is 9999.
687 * If the specified year is not valid for the receiver's day and month, then it is ignored.
690 * @param year an integer between 1752 and 9999
692 * @exception SWTException <ul>
693 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
694 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
699 public void setYear (int year) {
701 if (year < MIN_YEAR || year > MAX_YEAR) return;
702 SYSTEMTIME systime = new SYSTEMTIME ();
703 int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
704 OS.SendMessage (handle, msg, 0, systime);
705 msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
706 systime.wYear = (short)year;
707 OS.SendMessage (handle, msg, 0, systime);
708 lastSystemTime = null;
713 int bits = super.widgetStyle () | OS.WS_TABSTOP;
714 if ((style & SWT.CALENDAR_WEEKNUMBERS) != 0) {
715 bits |= OS.MCS_WEEKNUMBERS;
717 if ((style & SWT.CALENDAR) != 0) return bits | OS.MCS_NOTODAY;
719 * Bug in Windows: When WS_CLIPCHILDREN is set in a
720 * Date and Time Picker, the widget draws on top of
721 * the updown control. The fix is to clear the bits.
723 bits &= ~OS.WS_CLIPCHILDREN;
724 if ((style & SWT.TIME) != 0) bits |= OS.DTS_TIMEFORMAT;
725 if ((style & SWT.DATE) != 0) {
726 bits |= ((style & SWT.MEDIUM) != 0 ? OS.DTS_SHORTDATECENTURYFORMAT : OS.DTS_LONGDATEFORMAT);
727 if ((style & SWT.DROP_DOWN) == 0) bits |= OS.DTS_UPDOWN;
733 TCHAR windowClass () {
734 return (style & SWT.CALENDAR) != 0 ? CalendarClass : DateTimeClass;
739 return (style & SWT.CALENDAR) != 0 ? CalendarProc : DateTimeProc;
743 LRESULT wmNotifyChild (NMHDR hdr, long wParam, long lParam) {
745 case OS.DTN_CLOSEUP: {
747 * Feature in Windows. When the user selects the drop-down button,
748 * the DateTimePicker runs a modal loop and consumes WM_LBUTTONUP.
749 * This is done without adding a mouse capture. Since WM_LBUTTONUP
750 * is not delivered, the normal mechanism where a mouse capture is
751 * added on mouse down and removed when the mouse is released
752 * is broken, leaving an unwanted capture. The fix is to avoid
753 * setting capture on mouse down right after WM_LBUTTONUP is consumed.
755 display.captureChanged = true;
758 case OS.MCN_SELCHANGE: {
759 if (ignoreSelection) break;
760 SYSTEMTIME systime = new SYSTEMTIME ();
761 OS.SendMessage (handle, OS.MCM_GETCURSEL, 0, systime);
762 sendSelectionEvent (SWT.Selection);
765 case OS.DTN_DATETIMECHANGE: {
766 SYSTEMTIME systime = new SYSTEMTIME ();
767 OS.SendMessage (handle, OS.DTM_GETSYSTEMTIME, 0, systime);
768 if (lastSystemTime == null || systime.wDay != lastSystemTime.wDay || systime.wMonth != lastSystemTime.wMonth || systime.wYear != lastSystemTime.wYear) {
769 sendSelectionEvent (SWT.Selection);
770 if ((style & SWT.TIME) == 0) lastSystemTime = systime;
775 return super.wmNotifyChild (hdr, wParam, lParam);
779 LRESULT WM_CHAR (long wParam, long lParam) {
780 LRESULT result = super.WM_CHAR (wParam, lParam);
781 if (result != null) return result;
783 * Feature in Windows. For some reason, when the
784 * user presses tab, return or escape, Windows beeps.
785 * The fix is to look for these keys and not call
788 switch ((int)wParam) {
790 sendSelectionEvent (SWT.DefaultSelection);
793 case SWT.ESC: return LRESULT.ZERO;
799 LRESULT WM_LBUTTONDBLCLK (long wParam, long lParam) {
800 LRESULT result = super.WM_LBUTTONDBLCLK (wParam, lParam);
801 if (isDisposed ()) return LRESULT.ZERO;
802 if ((style & SWT.CALENDAR) != 0) {
803 MCHITTESTINFO pMCHitTest = new MCHITTESTINFO ();
804 pMCHitTest.cbSize = MCHITTESTINFO.sizeof;
805 POINT pt = new POINT ();
806 pt.x = OS.GET_X_LPARAM (lParam);
807 pt.y = OS.GET_Y_LPARAM (lParam);
809 long code = OS.SendMessage (handle, OS.MCM_HITTEST, 0, pMCHitTest);
810 if ((code & OS.MCHT_CALENDARDATE) == OS.MCHT_CALENDARDATE) doubleClick = true;
816 LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
817 LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
818 if (result == LRESULT.ZERO) return result;
821 * Feature in Windows. For some reason, the calendar control
822 * does not take focus on WM_LBUTTONDOWN. The fix is to
823 * explicitly set focus.
825 if ((style & SWT.CALENDAR) != 0) {
826 if ((style & SWT.NO_FOCUS) == 0) OS.SetFocus (handle);
832 LRESULT WM_LBUTTONUP (long wParam, long lParam) {
833 LRESULT result = super.WM_LBUTTONUP (wParam, lParam);
834 if (isDisposed ()) return LRESULT.ZERO;
835 if (doubleClick) sendSelectionEvent (SWT.DefaultSelection);
841 LRESULT WM_TIMER (long wParam, long lParam) {
842 LRESULT result = super.WM_TIMER (wParam, lParam);
843 if (result != null) return result;
845 * Feature in Windows. For some reason, Windows sends WM_NOTIFY with
846 * MCN_SELCHANGE at regular intervals. This is unexpected. The fix is
847 * to ignore MCN_SELCHANGE during WM_TIMER.
849 ignoreSelection = true;
850 long code = callWindowProc(handle, OS.WM_TIMER, wParam, lParam);
851 ignoreSelection = false;
852 return code == 0 ? LRESULT.ZERO : new LRESULT(code);