3 * Copyright (C) 2004 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * PROJECT: ReactOS International Control Panel
21 * FILE: dll/cpl/intl/date.c
22 * PURPOSE: Date property page
23 * PROGRAMMER: Eric Kohl
28 /* GLOBALS ******************************************************************/
30 #define YEAR_STR_MAX_SIZE 5
31 #define MAX_SHRT_DATE_SEPARATORS 3
32 #define STD_DATE_SEP L"."
33 #define YEAR_DIFF (99)
34 #define MAX_YEAR (9999)
36 static HWND hwndEnum
= NULL
;
38 /* FUNCTIONS ****************************************************************/
40 /* If char is 'y' or 'M' or 'd' return TRUE, else FALSE */
42 isDateCompAl(WCHAR alpha
)
44 if ((alpha
== L
'y') || (alpha
== L
'M') || (alpha
== L
'd') || (alpha
== L
' '))
50 /* Find first date separator in string */
52 FindDateSep(const WCHAR
*szSourceStr
)
55 UINT nDateCompCount
=0;
58 pszFoundSep
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, MAX_SAMPLES_STR_SIZE
* sizeof(WCHAR
));
59 if (pszFoundSep
== NULL
)
62 wcscpy(pszFoundSep
,STD_DATE_SEP
);
64 while (nDateCompCount
< wcslen(szSourceStr
))
66 if (!isDateCompAl(szSourceStr
[nDateCompCount
]) && (szSourceStr
[nDateCompCount
] != L
'\''))
68 while (!isDateCompAl(szSourceStr
[nDateCompCount
]) && (szSourceStr
[nDateCompCount
] != L
'\''))
70 pszFoundSep
[nDateSepCount
++] = szSourceStr
[nDateCompCount
];
74 pszFoundSep
[nDateSepCount
] = L
'\0';
84 /* Replace given template in source string with string to replace and return received string */
87 /* Setted up short date separator to registry */
89 SetShortDateSep(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
91 WCHAR szShortDateSep
[MAX_SAMPLES_STR_SIZE
];
96 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
98 (WPARAM
)MAX_SAMPLES_STR_SIZE
,
99 (LPARAM
)szShortDateSep
);
101 /* Get separator string size */
102 nSepStrSize
= wcslen(szShortDateSep
);
104 /* Check date components */
105 for (nSepCount
= 0; nSepCount
< nSepStrSize
; nSepCount
++)
107 if (iswalnum(szShortDateSep
[nSepCount
]) || (szShortDateSep
[nSepCount
] == L
'\''))
109 PrintErrorMsgBox(IDS_ERROR_SYMBOL_SEPARATE
);
114 /* Save date separator */
115 wcscpy(pGlobalData
->szDateSep
, szShortDateSep
);
120 /* Setted up short date format to registry */
122 SetShortDateFormat(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
124 WCHAR szShortDateFmt
[MAX_SAMPLES_STR_SIZE
];
125 WCHAR szShortDateSep
[MAX_SAMPLES_STR_SIZE
];
126 WCHAR szFoundDateSep
[MAX_SAMPLES_STR_SIZE
];
129 BOOL OpenApostFlg
= FALSE
;
134 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATEFMT_COMBO
,
136 (WPARAM
)MAX_SAMPLES_STR_SIZE
,
137 (LPARAM
)szShortDateFmt
);
140 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
142 (WPARAM
)MAX_SAMPLES_STR_SIZE
,
143 (LPARAM
)szShortDateSep
);
145 /* Get format-string size */
146 nFmtStrSize
= wcslen(szShortDateFmt
);
148 /* Check date components */
149 for (nDateCompCount
= 0; nDateCompCount
< nFmtStrSize
; nDateCompCount
++)
151 if (szShortDateFmt
[nDateCompCount
] == L
'\'')
153 OpenApostFlg
= !OpenApostFlg
;
156 if (iswalnum(szShortDateFmt
[nDateCompCount
]) &&
157 !isDateCompAl(szShortDateFmt
[nDateCompCount
]) &&
160 PrintErrorMsgBox(IDS_ERROR_SYMBOL_FORMAT_SHORT
);
168 PrintErrorMsgBox(IDS_ERROR_SYMBOL_FORMAT_SHORT
);
172 pszFoundSep
= FindDateSep(szShortDateFmt
);
173 if (pszFoundSep
!= NULL
)
175 /* Substring replacement of separator */
176 wcscpy(szFoundDateSep
, pszFoundSep
);
177 pszResultStr
= ReplaceSubStr(szShortDateFmt
, szShortDateSep
, szFoundDateSep
);
178 if (pszResultStr
!= NULL
)
180 wcscpy(szShortDateFmt
, pszResultStr
);
181 HeapFree(GetProcessHeap(), 0, pszResultStr
);
184 HeapFree(GetProcessHeap(), 0, pszFoundSep
);
187 /* Save short date format */
188 wcscpy(pGlobalData
->szShortDateFormat
, szShortDateFmt
);
193 /* Setted up long date format to registry */
195 SetLongDateFormat(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
197 WCHAR szLongDateFmt
[MAX_SAMPLES_STR_SIZE
];
198 BOOL OpenApostFlg
= FALSE
;
203 SendDlgItemMessageW(hwndDlg
, IDC_LONGDATEFMT_COMBO
,
205 (WPARAM
)MAX_SAMPLES_STR_SIZE
,
206 (LPARAM
)szLongDateFmt
);
208 /* Get format string size */
209 nFmtStrSize
= wcslen(szLongDateFmt
);
211 /* Check date components */
212 for (nDateCompCount
= 0; nDateCompCount
< nFmtStrSize
; nDateCompCount
++)
214 if (szLongDateFmt
[nDateCompCount
] == L
'\'')
216 OpenApostFlg
= !OpenApostFlg
;
219 if (iswalnum(szLongDateFmt
[nDateCompCount
]) &&
220 !isDateCompAl(szLongDateFmt
[nDateCompCount
]) &&
223 PrintErrorMsgBox(IDS_ERROR_SYMBOL_FORMAT_LONG
);
231 PrintErrorMsgBox(IDS_ERROR_SYMBOL_FORMAT_LONG
);
235 /* Save long date format */
236 wcscpy(pGlobalData
->szLongDateFormat
, szLongDateFmt
);
241 /* Init short date separator control box */
243 InitShortDateSepSamples(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
245 PWSTR ShortDateSepSamples
[MAX_SHRT_DATE_SEPARATORS
] =
254 /* Clear all box content */
255 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
260 /* Create standard list of separators */
261 for (nCBIndex
= 0; nCBIndex
< MAX_SHRT_DATE_SEPARATORS
; nCBIndex
++)
263 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
266 (LPARAM
)ShortDateSepSamples
[nCBIndex
]);
269 /* Set current item to value from registry */
270 nRetCode
= SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
273 (LPARAM
)pGlobalData
->szDateSep
);
275 /* If it is not successful, add new value to list and select them */
276 if (nRetCode
== CB_ERR
)
278 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
281 (LPARAM
)pGlobalData
->szDateSep
);
282 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
285 (LPARAM
)pGlobalData
->szDateSep
);
290 ShortDateFormatEnumProc(PWSTR lpTimeFormatString
)
292 SendMessageW(hwndEnum
,
295 (LPARAM
)lpTimeFormatString
);
300 /* Init short date control box */
302 InitShortDateCB(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
306 /* Limit text lengths */
307 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATEFMT_COMBO
,
311 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
316 /* Clear all box content */
317 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATEFMT_COMBO
,
322 /* Enumerate short date formats */
323 hwndEnum
= GetDlgItem(hwndDlg
, IDC_SHRTDATEFMT_COMBO
);
324 EnumDateFormatsW(ShortDateFormatEnumProc
, pGlobalData
->UserLCID
, DATE_SHORTDATE
);
326 /* Set current item to value from registry */
327 nRetCode
= SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATEFMT_COMBO
,
330 (LPARAM
)pGlobalData
->szShortDateFormat
);
332 /* If it is not successful, add new value to list and select them */
333 if (nRetCode
== CB_ERR
)
335 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATEFMT_COMBO
,
338 (LPARAM
)pGlobalData
->szShortDateFormat
);
339 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATEFMT_COMBO
,
342 (LPARAM
)pGlobalData
->szShortDateFormat
);
346 /* Init long date control box */
348 InitLongDateCB(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
352 /* Limit text length */
353 SendDlgItemMessageW(hwndDlg
, IDC_LONGDATEFMT_COMBO
,
358 /* Clear all box content */
359 SendDlgItemMessageW(hwndDlg
, IDC_LONGDATEFMT_COMBO
,
364 /* Enumerate short long formats */
365 hwndEnum
= GetDlgItem(hwndDlg
, IDC_LONGDATEFMT_COMBO
);
366 EnumDateFormatsW(ShortDateFormatEnumProc
, pGlobalData
->UserLCID
, DATE_LONGDATE
);
368 /* Set current item to value from registry */
369 nRetCode
= SendDlgItemMessageW(hwndDlg
, IDC_LONGDATEFMT_COMBO
,
372 (LPARAM
)pGlobalData
->szLongDateFormat
);
374 /* If it is not successful, add new value to list and select them */
375 if (nRetCode
== CB_ERR
)
377 SendDlgItemMessageW(hwndDlg
, IDC_LONGDATEFMT_COMBO
,
380 (LPARAM
)pGlobalData
->szLongDateFormat
);
381 SendDlgItemMessageW(hwndDlg
, IDC_LONGDATEFMT_COMBO
,
384 (LPARAM
)pGlobalData
->szLongDateFormat
);
388 /* Set up max date value to registry */
390 SetMaxDate(HWND hwndDlg
, LCID lcid
)
392 WCHAR szMaxDateVal
[YEAR_STR_MAX_SIZE
];
396 hWndYearSpin
= GetDlgItem(hwndDlg
, IDC_SCR_MAX_YEAR
);
399 nSpinVal
= LOWORD(SendMessageW(hWndYearSpin
,
404 /* convert to wide char */
405 _itow(nSpinVal
, szMaxDateVal
, DECIMAL_RADIX
);
407 /* Save max date value */
408 SetCalendarInfoW(lcid
,
410 48 , /* CAL_ITWODIGITYEARMAX */
411 (PCWSTR
)szMaxDateVal
);
414 /* Get max date value from registry set */
416 GetMaxDate(LCID lcid
)
420 GetCalendarInfoW(lcid
,
422 CAL_ITWODIGITYEARMAX
| CAL_RETURN_NUMBER
,
424 0, /* ret type - number */
425 (LPDWORD
)&nMaxDateVal
);
430 /* Set's MIN data edit control value to MAX-99 */
432 SetMinDate(HWND hwndDlg
)
434 WCHAR OutBuffer
[YEAR_STR_MAX_SIZE
];
438 hWndYearSpin
= GetDlgItem(hwndDlg
, IDC_SCR_MAX_YEAR
);
441 nSpinVal
= LOWORD(SendMessageW(hWndYearSpin
,
446 /* Set min year value */
447 wsprintf(OutBuffer
, L
"%d", (DWORD
)nSpinVal
- YEAR_DIFF
);
448 SendDlgItemMessageW(hwndDlg
, IDC_FIRSTYEAR_EDIT
,
454 /* Init spin control */
456 InitMinMaxDateSpin(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
458 WCHAR OutBuffer
[YEAR_STR_MAX_SIZE
];
461 /* Limit text lengths */
462 SendDlgItemMessageW(hwndDlg
, IDC_FIRSTYEAR_EDIT
,
466 SendDlgItemMessageW(hwndDlg
, IDC_SECONDYEAR_EDIT
,
471 hWndYearSpin
= GetDlgItem(hwndDlg
, IDC_SCR_MAX_YEAR
);
473 /* Init max date value */
474 wsprintf(OutBuffer
, L
"%04d", (DWORD
)GetMaxDate(pGlobalData
->UserLCID
));
475 SendDlgItemMessageW(hwndDlg
, IDC_SECONDYEAR_EDIT
,
480 /* Init min date value */
481 wsprintf(OutBuffer
, L
"%04d", (DWORD
)GetMaxDate(pGlobalData
->UserLCID
) - YEAR_DIFF
);
482 SendDlgItemMessageW(hwndDlg
, IDC_FIRSTYEAR_EDIT
,
487 /* Init updown control */
489 SendMessageW(hWndYearSpin
,
492 MAKELONG(MAX_YEAR
,YEAR_DIFF
));
494 /* Set current value */
495 SendMessageW(hWndYearSpin
,
498 MAKELONG(GetMaxDate(pGlobalData
->UserLCID
),0));
501 /* Update all date locale samples */
503 UpdateDateLocaleSamples(HWND hwndDlg
,
504 PGLOBALDATA pGlobalData
)
506 WCHAR OutBuffer
[MAX_SAMPLES_STR_SIZE
];
508 /* Get short date format sample */
509 GetDateFormatW(pGlobalData
->UserLCID
, 0, NULL
,
510 pGlobalData
->szShortDateFormat
, OutBuffer
,
511 MAX_SAMPLES_STR_SIZE
);
512 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESAMPLE_EDIT
, WM_SETTEXT
,
513 0, (LPARAM
)OutBuffer
);
515 /* Get long date sample */
516 GetDateFormatW(pGlobalData
->UserLCID
, 0, NULL
,
517 pGlobalData
->szLongDateFormat
, OutBuffer
,
518 MAX_SAMPLES_STR_SIZE
);
519 SendDlgItemMessageW(hwndDlg
, IDC_LONGDATESAMPLE_EDIT
,
520 WM_SETTEXT
, 0, (LPARAM
)OutBuffer
);
523 /* Property page dialog callback */
525 DatePageProc(HWND hwndDlg
,
530 PGLOBALDATA pGlobalData
;
532 pGlobalData
= (PGLOBALDATA
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
537 pGlobalData
= (PGLOBALDATA
)((LPPROPSHEETPAGE
)lParam
)->lParam
;
538 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)pGlobalData
);
540 InitMinMaxDateSpin(hwndDlg
, pGlobalData
);
541 UpdateDateLocaleSamples(hwndDlg
, pGlobalData
);
542 InitShortDateCB(hwndDlg
, pGlobalData
);
543 InitLongDateCB(hwndDlg
, pGlobalData
);
544 InitShortDateSepSamples(hwndDlg
, pGlobalData
);
545 /* TODO: Add other calendar types */
549 switch (LOWORD(wParam
))
551 case IDC_SECONDYEAR_EDIT
:
552 if (HIWORD(wParam
) == EN_CHANGE
)
558 case IDC_SCR_MAX_YEAR
:
559 /* Set "Apply" button enabled */
561 //PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
564 case IDC_CALTYPE_COMBO
:
565 case IDC_HIJCHRON_COMBO
:
566 case IDC_SHRTDATEFMT_COMBO
:
567 case IDC_LONGDATEFMT_COMBO
:
568 case IDC_SHRTDATESEP_COMBO
:
569 if (HIWORD(wParam
) == CBN_SELCHANGE
|| HIWORD(wParam
) == CBN_EDITCHANGE
)
571 /* Set "Apply" button enabled */
572 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
579 if (((LPNMHDR
)lParam
)->code
== (UINT
)PSN_APPLY
)
581 if (!SetLongDateFormat(hwndDlg
, pGlobalData
))
584 if (!SetShortDateFormat(hwndDlg
, pGlobalData
))
587 if (!SetShortDateSep(hwndDlg
, pGlobalData
))
590 pGlobalData
->bUserLocaleChanged
= TRUE
;
592 SetMaxDate(hwndDlg
, pGlobalData
->UserLCID
);
593 InitShortDateCB(hwndDlg
, pGlobalData
);
594 UpdateDateLocaleSamples(hwndDlg
, pGlobalData
);