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
)malloc(MAX_SAMPLES_STR_SIZE
* sizeof(WCHAR
));
63 wcscpy(pszFoundSep
,STD_DATE_SEP
);
65 while (nDateCompCount
< wcslen(szSourceStr
))
67 if (!isDateCompAl(szSourceStr
[nDateCompCount
]) && (szSourceStr
[nDateCompCount
] != L
'\''))
69 while (!isDateCompAl(szSourceStr
[nDateCompCount
]) && (szSourceStr
[nDateCompCount
] != L
'\''))
71 pszFoundSep
[nDateSepCount
++] = szSourceStr
[nDateCompCount
];
75 pszFoundSep
[nDateSepCount
] = L
'\0';
85 /* Replace given template in source string with string to replace and return received string */
88 /* Setted up short date separator to registry */
90 SetShortDateSep(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
92 WCHAR szShortDateSep
[MAX_SAMPLES_STR_SIZE
];
97 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
99 (WPARAM
)MAX_SAMPLES_STR_SIZE
,
100 (LPARAM
)szShortDateSep
);
102 /* Get separator string size */
103 nSepStrSize
= wcslen(szShortDateSep
);
105 /* Check date components */
106 for (nSepCount
= 0; nSepCount
< nSepStrSize
; nSepCount
++)
108 if (iswalnum(szShortDateSep
[nSepCount
]) || (szShortDateSep
[nSepCount
] == L
'\''))
110 PrintErrorMsgBox(IDS_ERROR_SYMBOL_SEPARATE
);
115 /* Save date separator */
116 wcscpy(pGlobalData
->szDateSep
, szShortDateSep
);
121 /* Setted up short date format to registry */
123 SetShortDateFormat(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
125 WCHAR szShortDateFmt
[MAX_SAMPLES_STR_SIZE
];
126 WCHAR szShortDateSep
[MAX_SAMPLES_STR_SIZE
];
127 WCHAR szFoundDateSep
[MAX_SAMPLES_STR_SIZE
];
130 BOOL OpenApostFlg
= FALSE
;
135 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATEFMT_COMBO
,
137 (WPARAM
)MAX_SAMPLES_STR_SIZE
,
138 (LPARAM
)szShortDateFmt
);
141 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
143 (WPARAM
)MAX_SAMPLES_STR_SIZE
,
144 (LPARAM
)szShortDateSep
);
146 /* Get format-string size */
147 nFmtStrSize
= wcslen(szShortDateFmt
);
149 /* Check date components */
150 for (nDateCompCount
= 0; nDateCompCount
< nFmtStrSize
; nDateCompCount
++)
152 if (szShortDateFmt
[nDateCompCount
] == L
'\'')
154 OpenApostFlg
= !OpenApostFlg
;
157 if (iswalnum(szShortDateFmt
[nDateCompCount
]) &&
158 !isDateCompAl(szShortDateFmt
[nDateCompCount
]) &&
161 PrintErrorMsgBox(IDS_ERROR_SYMBOL_FORMAT_SHORT
);
169 PrintErrorMsgBox(IDS_ERROR_SYMBOL_FORMAT_SHORT
);
173 pszFoundSep
= FindDateSep(szShortDateFmt
);
175 /* Substring replacement of separator */
176 wcscpy(szFoundDateSep
, pszFoundSep
);
177 pszResultStr
= ReplaceSubStr(szShortDateFmt
, szShortDateSep
, szFoundDateSep
);
178 wcscpy(szShortDateFmt
, pszResultStr
);
184 /* Save short date format */
185 wcscpy(pGlobalData
->szShortDateFormat
, szShortDateFmt
);
190 /* Setted up long date format to registry */
192 SetLongDateFormat(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
194 WCHAR szLongDateFmt
[MAX_SAMPLES_STR_SIZE
];
195 BOOL OpenApostFlg
= FALSE
;
200 SendDlgItemMessageW(hwndDlg
, IDC_LONGDATEFMT_COMBO
,
202 (WPARAM
)MAX_SAMPLES_STR_SIZE
,
203 (LPARAM
)szLongDateFmt
);
205 /* Get format string size */
206 nFmtStrSize
= wcslen(szLongDateFmt
);
208 /* Check date components */
209 for (nDateCompCount
= 0; nDateCompCount
< nFmtStrSize
; nDateCompCount
++)
211 if (szLongDateFmt
[nDateCompCount
] == L
'\'')
213 OpenApostFlg
= !OpenApostFlg
;
216 if (iswalnum(szLongDateFmt
[nDateCompCount
]) &&
217 !isDateCompAl(szLongDateFmt
[nDateCompCount
]) &&
220 PrintErrorMsgBox(IDS_ERROR_SYMBOL_FORMAT_LONG
);
228 PrintErrorMsgBox(IDS_ERROR_SYMBOL_FORMAT_LONG
);
232 /* Save long date format */
233 wcscpy(pGlobalData
->szLongDateFormat
, szLongDateFmt
);
238 /* Init short date separator control box */
240 InitShortDateSepSamples(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
242 PWSTR ShortDateSepSamples
[MAX_SHRT_DATE_SEPARATORS
] =
251 /* Clear all box content */
252 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
257 /* Create standard list of separators */
258 for (nCBIndex
= 0; nCBIndex
< MAX_SHRT_DATE_SEPARATORS
; nCBIndex
++)
260 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
263 (LPARAM
)ShortDateSepSamples
[nCBIndex
]);
266 /* Set current item to value from registry */
267 nRetCode
= SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
270 (LPARAM
)pGlobalData
->szDateSep
);
272 /* If it is not successful, add new value to list and select them */
273 if (nRetCode
== CB_ERR
)
275 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
278 (LPARAM
)pGlobalData
->szDateSep
);
279 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
282 (LPARAM
)pGlobalData
->szDateSep
);
287 ShortDateFormatEnumProc(PWSTR lpTimeFormatString
)
289 SendMessageW(hwndEnum
,
292 (LPARAM
)lpTimeFormatString
);
297 /* Init short date control box */
299 InitShortDateCB(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
303 /* Limit text lengths */
304 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATEFMT_COMBO
,
308 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESEP_COMBO
,
313 /* Clear all box content */
314 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATEFMT_COMBO
,
319 /* Enumerate short date formats */
320 hwndEnum
= GetDlgItem(hwndDlg
, IDC_SHRTDATEFMT_COMBO
);
321 EnumDateFormatsW(ShortDateFormatEnumProc
, pGlobalData
->UserLCID
, DATE_SHORTDATE
);
323 /* Set current item to value from registry */
324 nRetCode
= SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATEFMT_COMBO
,
327 (LPARAM
)pGlobalData
->szShortDateFormat
);
329 /* If it is not successful, add new value to list and select them */
330 if (nRetCode
== CB_ERR
)
332 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATEFMT_COMBO
,
335 (LPARAM
)pGlobalData
->szShortDateFormat
);
336 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATEFMT_COMBO
,
339 (LPARAM
)pGlobalData
->szShortDateFormat
);
343 /* Init long date control box */
345 InitLongDateCB(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
349 /* Limit text length */
350 SendDlgItemMessageW(hwndDlg
, IDC_LONGDATEFMT_COMBO
,
355 /* Clear all box content */
356 SendDlgItemMessageW(hwndDlg
, IDC_LONGDATEFMT_COMBO
,
361 /* Enumerate short long formats */
362 hwndEnum
= GetDlgItem(hwndDlg
, IDC_LONGDATEFMT_COMBO
);
363 EnumDateFormatsW(ShortDateFormatEnumProc
, pGlobalData
->UserLCID
, DATE_LONGDATE
);
365 /* Set current item to value from registry */
366 nRetCode
= SendDlgItemMessageW(hwndDlg
, IDC_LONGDATEFMT_COMBO
,
369 (LPARAM
)pGlobalData
->szLongDateFormat
);
371 /* If it is not successful, add new value to list and select them */
372 if (nRetCode
== CB_ERR
)
374 SendDlgItemMessageW(hwndDlg
, IDC_LONGDATEFMT_COMBO
,
377 (LPARAM
)pGlobalData
->szLongDateFormat
);
378 SendDlgItemMessageW(hwndDlg
, IDC_LONGDATEFMT_COMBO
,
381 (LPARAM
)pGlobalData
->szLongDateFormat
);
385 /* Set up max date value to registry */
387 SetMaxDate(HWND hwndDlg
, LCID lcid
)
389 WCHAR szMaxDateVal
[YEAR_STR_MAX_SIZE
];
393 hWndYearSpin
= GetDlgItem(hwndDlg
, IDC_SCR_MAX_YEAR
);
396 nSpinVal
=LOWORD(SendMessageW(hWndYearSpin
,
401 /* convert to wide char */
402 _itow(nSpinVal
, szMaxDateVal
, DECIMAL_RADIX
);
404 /* Save max date value */
405 SetCalendarInfoW(lcid
,
407 48 , /* CAL_ITWODIGITYEARMAX */
408 (PCWSTR
)szMaxDateVal
);
411 /* Get max date value from registry set */
413 GetMaxDate(LCID lcid
)
417 GetCalendarInfoW(lcid
,
419 CAL_ITWODIGITYEARMAX
| CAL_RETURN_NUMBER
,
421 0, /* ret type - number */
422 (LPDWORD
)&nMaxDateVal
);
427 /* Set's MIN data edit control value to MAX-99 */
429 SetMinDate(HWND hwndDlg
)
431 WCHAR OutBuffer
[YEAR_STR_MAX_SIZE
];
435 hWndYearSpin
= GetDlgItem(hwndDlg
, IDC_SCR_MAX_YEAR
);
438 nSpinVal
= LOWORD(SendMessageW(hWndYearSpin
,
443 /* Set min year value */
444 wsprintf(OutBuffer
, L
"%d", (DWORD
)nSpinVal
- YEAR_DIFF
);
445 SendDlgItemMessageW(hwndDlg
, IDC_FIRSTYEAR_EDIT
,
451 /* Init spin control */
453 InitMinMaxDateSpin(HWND hwndDlg
, PGLOBALDATA pGlobalData
)
455 WCHAR OutBuffer
[YEAR_STR_MAX_SIZE
];
458 /* Limit text lengths */
459 SendDlgItemMessageW(hwndDlg
, IDC_FIRSTYEAR_EDIT
,
463 SendDlgItemMessageW(hwndDlg
, IDC_SECONDYEAR_EDIT
,
468 hWndYearSpin
= GetDlgItem(hwndDlg
, IDC_SCR_MAX_YEAR
);
470 /* Init max date value */
471 wsprintf(OutBuffer
, L
"%04d", (DWORD
)GetMaxDate(pGlobalData
->UserLCID
));
472 SendDlgItemMessageW(hwndDlg
, IDC_SECONDYEAR_EDIT
,
477 /* Init min date value */
478 wsprintf(OutBuffer
, L
"%04d", (DWORD
)GetMaxDate(pGlobalData
->UserLCID
) - YEAR_DIFF
);
479 SendDlgItemMessageW(hwndDlg
, IDC_FIRSTYEAR_EDIT
,
484 /* Init updown control */
486 SendMessageW(hWndYearSpin
,
489 MAKELONG(MAX_YEAR
,YEAR_DIFF
));
491 /* Set current value */
492 SendMessageW(hWndYearSpin
,
495 MAKELONG(GetMaxDate(pGlobalData
->UserLCID
),0));
498 /* Update all date locale samples */
500 UpdateDateLocaleSamples(HWND hwndDlg
,
501 PGLOBALDATA pGlobalData
)
503 WCHAR OutBuffer
[MAX_SAMPLES_STR_SIZE
];
505 /* Get short date format sample */
506 GetDateFormatW(pGlobalData
->UserLCID
, 0, NULL
,
507 pGlobalData
->szShortDateFormat
, OutBuffer
,
508 MAX_SAMPLES_STR_SIZE
);
509 SendDlgItemMessageW(hwndDlg
, IDC_SHRTDATESAMPLE_EDIT
, WM_SETTEXT
,
510 0, (LPARAM
)OutBuffer
);
512 /* Get long date sample */
513 GetDateFormatW(pGlobalData
->UserLCID
, 0, NULL
,
514 pGlobalData
->szLongDateFormat
, OutBuffer
,
515 MAX_SAMPLES_STR_SIZE
);
516 SendDlgItemMessageW(hwndDlg
, IDC_LONGDATESAMPLE_EDIT
,
517 WM_SETTEXT
, 0, (LPARAM
)OutBuffer
);
520 /* Property page dialog callback */
522 DatePageProc(HWND hwndDlg
,
527 PGLOBALDATA pGlobalData
;
529 pGlobalData
= (PGLOBALDATA
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
534 pGlobalData
= (PGLOBALDATA
)((LPPROPSHEETPAGE
)lParam
)->lParam
;
535 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)pGlobalData
);
537 InitMinMaxDateSpin(hwndDlg
, pGlobalData
);
538 UpdateDateLocaleSamples(hwndDlg
, pGlobalData
);
539 InitShortDateCB(hwndDlg
, pGlobalData
);
540 InitLongDateCB(hwndDlg
, pGlobalData
);
541 InitShortDateSepSamples(hwndDlg
, pGlobalData
);
542 /* TODO: Add other calendar types */
546 switch (LOWORD(wParam
))
548 case IDC_SECONDYEAR_EDIT
:
549 if (HIWORD(wParam
) == EN_CHANGE
)
555 case IDC_SCR_MAX_YEAR
:
556 /* Set "Apply" button enabled */
558 //PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
561 case IDC_CALTYPE_COMBO
:
562 case IDC_HIJCHRON_COMBO
:
563 case IDC_SHRTDATEFMT_COMBO
:
564 case IDC_LONGDATEFMT_COMBO
:
565 case IDC_SHRTDATESEP_COMBO
:
566 if (HIWORD(wParam
) == CBN_SELCHANGE
|| HIWORD(wParam
) == CBN_EDITCHANGE
)
568 /* Set "Apply" button enabled */
569 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
576 if (((LPNMHDR
)lParam
)->code
== (UINT
)PSN_APPLY
)
578 if (!SetLongDateFormat(hwndDlg
, pGlobalData
))
581 if (!SetShortDateFormat(hwndDlg
, pGlobalData
))
584 if (!SetShortDateSep(hwndDlg
, pGlobalData
))
587 pGlobalData
->fUserLocaleChanged
= TRUE
;
589 SetMaxDate(hwndDlg
, pGlobalData
->UserLCID
);
590 InitShortDateCB(hwndDlg
, pGlobalData
);
591 UpdateDateLocaleSamples(hwndDlg
, pGlobalData
);