[DINPUT]
[reactos.git] / reactos / dll / cpl / intl / date.c
1 /*
2 * ReactOS
3 * Copyright (C) 2004 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /*
20 * PROJECT: ReactOS International Control Panel
21 * FILE: dll/cpl/intl/date.c
22 * PURPOSE: Date property page
23 * PROGRAMMER: Eric Kohl
24 */
25
26 #include "intl.h"
27
28 /* GLOBALS ******************************************************************/
29
30 #define YEAR_STR_MAX_SIZE 5
31 #define MAX_SHRT_DATE_SEPARATORS 3
32 #define STD_DATE_SEP _T(".")
33 #define YEAR_DIFF (99)
34 #define MAX_YEAR (9999)
35
36 static HWND hwndEnum = NULL;
37
38 /* FUNCTIONS ****************************************************************/
39
40 /* If char is 'y' or 'M' or 'd' return TRUE, else FALSE */
41 BOOL
42 isDateCompAl(TCHAR alpha)
43 {
44 if ((alpha == _T('y')) || (alpha == _T('M')) || (alpha == _T('d')) || (alpha == _T(' ')))
45 return TRUE;
46 else
47 return FALSE;
48 }
49
50 /* Find first date separator in string */
51 LPTSTR
52 FindDateSep(const TCHAR *szSourceStr)
53 {
54 LPTSTR pszFoundSep;
55 UINT nDateCompCount=0;
56 UINT nDateSepCount=0;
57
58 pszFoundSep = (LPTSTR)malloc(MAX_SAMPLES_STR_SIZE * sizeof(TCHAR));
59
60 _tcscpy(pszFoundSep,STD_DATE_SEP);
61
62 while (nDateCompCount < _tcslen(szSourceStr))
63 {
64 if (!isDateCompAl(szSourceStr[nDateCompCount]) && (szSourceStr[nDateCompCount] != _T('\'')))
65 {
66 while (!isDateCompAl(szSourceStr[nDateCompCount]) && (szSourceStr[nDateCompCount] != _T('\'')))
67 {
68 pszFoundSep[nDateSepCount++] = szSourceStr[nDateCompCount];
69 nDateCompCount++;
70 }
71
72 pszFoundSep[nDateSepCount] = _T('\0');
73 return pszFoundSep;
74 }
75
76 nDateCompCount++;
77 }
78
79 return pszFoundSep;
80 }
81
82 /* Replace given template in source string with string to replace and return received string */
83
84
85 /* Setted up short date separator to registry */
86 static BOOL
87 SetShortDateSep(HWND hwndDlg, LCID lcid)
88 {
89 TCHAR szShortDateSep[MAX_SAMPLES_STR_SIZE];
90 INT nSepStrSize;
91 INT nSepCount;
92
93 /* Get setted separator */
94 SendMessage(GetDlgItem(hwndDlg, IDC_SHRTDATESEP_COMBO),
95 WM_GETTEXT,
96 (WPARAM)MAX_SAMPLES_STR_SIZE,
97 (LPARAM)szShortDateSep);
98
99 /* Get setted separator string size */
100 nSepStrSize = _tcslen(szShortDateSep);
101
102 /* Check date components */
103 for (nSepCount = 0; nSepCount < nSepStrSize; nSepCount++)
104 {
105 if (_istalnum(szShortDateSep[nSepCount]) || (szShortDateSep[nSepCount] == _T('\'')))
106 {
107 MessageBox(NULL,
108 _T("Entered short date separator contain incorrect symbol"),
109 _T("Error"), MB_OK | MB_ICONERROR);
110 return FALSE;
111 }
112 }
113
114 /* Save date separator */
115 SetLocaleInfo(lcid, LOCALE_SDATE, szShortDateSep);
116
117 return TRUE;
118 }
119
120 /* Setted up short date format to registry */
121 static BOOL
122 SetShortDateFormat(HWND hwndDlg, LCID lcid)
123 {
124 TCHAR szShortDateFmt[MAX_SAMPLES_STR_SIZE];
125 TCHAR szShortDateSep[MAX_SAMPLES_STR_SIZE];
126 TCHAR szFindedDateSep[MAX_SAMPLES_STR_SIZE];
127 LPTSTR pszResultStr;
128 BOOL OpenApostFlg = FALSE;
129 INT nFmtStrSize;
130 INT nDateCompCount;
131
132 /* Get setted format */
133 SendMessage(GetDlgItem(hwndDlg, IDC_SHRTDATEFMT_COMBO),
134 WM_GETTEXT,
135 (WPARAM)MAX_SAMPLES_STR_SIZE,
136 (LPARAM)szShortDateFmt);
137
138 /* Get setted separator */
139 SendMessage(GetDlgItem(hwndDlg, IDC_SHRTDATESEP_COMBO),
140 WM_GETTEXT,
141 (WPARAM)MAX_SAMPLES_STR_SIZE,
142 (LPARAM)szShortDateSep);
143
144 /* Get setted format-string size */
145 nFmtStrSize = _tcslen(szShortDateFmt);
146
147 /* Check date components */
148 for (nDateCompCount = 0; nDateCompCount < nFmtStrSize; nDateCompCount++)
149 {
150 if (szShortDateFmt[nDateCompCount] == _T('\''))
151 {
152 OpenApostFlg = !OpenApostFlg;
153 }
154
155 if (_istalnum(szShortDateFmt[nDateCompCount]) &&
156 !isDateCompAl(szShortDateFmt[nDateCompCount]) &&
157 !OpenApostFlg)
158 {
159 MessageBox(NULL,
160 _T("Entered short date format contain incorrect symbol"),
161 _T("Error"), MB_OK | MB_ICONERROR);
162 return FALSE;
163 }
164
165 }
166
167 if (OpenApostFlg)
168 {
169 MessageBoxW(NULL,
170 _T("Entered short date format contain incorrect symbol"),
171 _T("Error"), MB_OK | MB_ICONERROR);
172 return FALSE;
173 }
174
175 /* Substring replacement of separator */
176 _tcscpy(szFindedDateSep, FindDateSep(szShortDateFmt));
177 pszResultStr = ReplaceSubStr(szShortDateFmt, szShortDateSep, szFindedDateSep);
178 _tcscpy(szShortDateFmt, pszResultStr);
179 free(pszResultStr);
180
181 /* Save short date format */
182 SetLocaleInfo(lcid, LOCALE_SSHORTDATE, szShortDateFmt);
183
184 return TRUE;
185 }
186
187 /* Setted up long date format to registry */
188 static BOOL
189 SetLongDateFormat(HWND hwndDlg, LCID lcid)
190 {
191 TCHAR szLongDateFmt[MAX_SAMPLES_STR_SIZE];
192 BOOL OpenApostFlg = FALSE;
193 INT nFmtStrSize;
194 INT nDateCompCount;
195
196 /* Get setted format */
197 SendMessage(GetDlgItem(hwndDlg, IDC_LONGDATEFMT_COMBO),
198 WM_GETTEXT,
199 (WPARAM)MAX_SAMPLES_STR_SIZE,
200 (LPARAM)szLongDateFmt);
201
202 /* Get setted format string size */
203 nFmtStrSize = _tcslen(szLongDateFmt);
204
205 /* Check date components */
206 for (nDateCompCount = 0; nDateCompCount < nFmtStrSize; nDateCompCount++)
207 {
208 if (szLongDateFmt[nDateCompCount] == _T('\''))
209 {
210 OpenApostFlg = !OpenApostFlg;
211 }
212
213 if (_istalnum(szLongDateFmt[nDateCompCount]) &&
214 !isDateCompAl(szLongDateFmt[nDateCompCount]) &&
215 !OpenApostFlg)
216 {
217 MessageBox(NULL,
218 _T("Entered long date format contain incorrect symbol"),
219 _T("Error"), MB_OK | MB_ICONERROR);
220 return FALSE;
221 }
222
223 }
224
225 if (OpenApostFlg)
226 {
227 MessageBoxW(NULL,
228 _T("Entered long date format contain incorrect symbol"),
229 _T("Error"), MB_OK | MB_ICONERROR);
230 return FALSE;
231 }
232
233 /* Save short date format */
234 SetLocaleInfo(lcid, LOCALE_SLONGDATE, szLongDateFmt);
235
236 return TRUE;
237 }
238
239 /* Init short date separator control box */
240 static VOID
241 InitShortDateSepSamples(HWND hwndDlg, LCID lcid)
242 {
243 LPTSTR ShortDateSepSamples[MAX_SHRT_DATE_SEPARATORS] =
244 {
245 _T("."),
246 _T("/"),
247 _T("-")
248 };
249 TCHAR szShortDateSep[MAX_SAMPLES_STR_SIZE];
250 INT nCBIndex;
251 INT nRetCode;
252
253 /* Get current short date separator */
254 GetLocaleInfo(lcid,
255 LOCALE_SDATE,
256 szShortDateSep,
257 MAX_SAMPLES_STR_SIZE);
258
259 /* Clear all box content */
260 SendMessage(GetDlgItem(hwndDlg, IDC_SHRTDATESEP_COMBO),
261 CB_RESETCONTENT,
262 (WPARAM)0,
263 (LPARAM)0);
264
265 /* Create standard list of separators */
266 for (nCBIndex = 0; nCBIndex < MAX_SHRT_DATE_SEPARATORS; nCBIndex++)
267 {
268 SendMessageW(GetDlgItem(hwndDlg, IDC_SHRTDATESEP_COMBO),
269 CB_ADDSTRING,
270 0,
271 (LPARAM)ShortDateSepSamples[nCBIndex]);
272 }
273
274 /* Set current item to value from registry */
275 nRetCode = SendMessage(GetDlgItem(hwndDlg, IDC_SHRTDATESEP_COMBO),
276 CB_SELECTSTRING,
277 -1,
278 (LPARAM)szShortDateSep);
279
280 /* If it is not successful, add new value to list and select them */
281 if (nRetCode == CB_ERR)
282 {
283 SendMessage(GetDlgItem(hwndDlg, IDC_SHRTDATESEP_COMBO),
284 CB_ADDSTRING,
285 0,
286 (LPARAM)szShortDateSep);
287 SendMessageW(GetDlgItem(hwndDlg, IDC_SHRTDATESEP_COMBO),
288 CB_SELECTSTRING,
289 -1,
290 (LPARAM)szShortDateSep);
291 }
292 }
293
294 static BOOL CALLBACK
295 ShortDateFormatEnumProc(LPTSTR lpTimeFormatString)
296 {
297 SendMessage(hwndEnum,
298 CB_ADDSTRING,
299 0,
300 (LPARAM)lpTimeFormatString);
301
302 return TRUE;
303 }
304
305 /* Init short date control box */
306 VOID
307 InitShortDateCB(HWND hwndDlg, LCID lcid)
308 {
309 TCHAR szShortDateFmt[MAX_SAMPLES_STR_SIZE];
310 INT nRetCode;
311
312 /* Limit text lengths */
313 SendMessage(GetDlgItem(hwndDlg, IDC_SHRTDATEFMT_COMBO),
314 CB_LIMITTEXT,
315 MAX_SHRTDATEFMT,
316 0);
317 SendMessage(GetDlgItem(hwndDlg, IDC_SHRTDATESEP_COMBO),
318 CB_LIMITTEXT,
319 MAX_SHRTDATESEP,
320 0);
321
322 /* Get current short date format */
323 GetLocaleInfo(lcid,
324 LOCALE_SSHORTDATE,
325 szShortDateFmt,
326 MAX_SAMPLES_STR_SIZE);
327
328 /* Clear all box content */
329 SendMessage(GetDlgItem(hwndDlg, IDC_SHRTDATEFMT_COMBO),
330 CB_RESETCONTENT,
331 (WPARAM)0,
332 (LPARAM)0);
333
334 /* Enumerate short date formats */
335 hwndEnum = GetDlgItem(hwndDlg, IDC_SHRTDATEFMT_COMBO);
336 EnumDateFormats(ShortDateFormatEnumProc, lcid, DATE_SHORTDATE);
337
338 /* Set current item to value from registry */
339 nRetCode = SendMessage(GetDlgItem(hwndDlg, IDC_SHRTDATEFMT_COMBO),
340 CB_SELECTSTRING,
341 -1,
342 (LPARAM)szShortDateFmt);
343
344 /* If it is not successful, add new value to list and select them */
345 if (nRetCode == CB_ERR)
346 {
347 SendMessage(GetDlgItem(hwndDlg, IDC_SHRTDATEFMT_COMBO),
348 CB_ADDSTRING,
349 0,
350 (LPARAM)szShortDateFmt);
351 SendMessage(GetDlgItem(hwndDlg, IDC_SHRTDATEFMT_COMBO),
352 CB_SELECTSTRING,
353 -1,
354 (LPARAM)szShortDateFmt);
355 }
356 }
357
358 /* Init long date control box */
359 static VOID
360 InitLongDateCB(HWND hwndDlg, LCID lcid)
361 {
362 TCHAR szLongDateFmt[MAX_SAMPLES_STR_SIZE];
363 INT nRetCode;
364
365 /* Limit text length */
366 SendMessage(GetDlgItem(hwndDlg, IDC_LONGDATEFMT_COMBO),
367 CB_LIMITTEXT,
368 MAX_LONGDATEFMT,
369 0);
370
371 /* Get current long date format */
372 GetLocaleInfo(lcid,
373 LOCALE_SLONGDATE,
374 szLongDateFmt,
375 MAX_SAMPLES_STR_SIZE);
376
377 /* Clear all box content */
378 SendMessage(GetDlgItem(hwndDlg, IDC_LONGDATEFMT_COMBO),
379 CB_RESETCONTENT,
380 (WPARAM)0,
381 (LPARAM)0);
382
383 /* Enumerate short long formats */
384 hwndEnum = GetDlgItem(hwndDlg, IDC_LONGDATEFMT_COMBO);
385 EnumDateFormats(ShortDateFormatEnumProc, lcid, DATE_LONGDATE);
386
387 /* Set current item to value from registry */
388 nRetCode = SendMessage(GetDlgItem(hwndDlg, IDC_LONGDATEFMT_COMBO),
389 CB_SELECTSTRING,
390 -1,
391 (LPARAM)szLongDateFmt);
392
393 /* If it is not successful, add new value to list and select them */
394 if (nRetCode == CB_ERR)
395 {
396 SendMessage(GetDlgItem(hwndDlg, IDC_LONGDATEFMT_COMBO),
397 CB_ADDSTRING,
398 0,
399 (LPARAM)szLongDateFmt);
400 SendMessage(GetDlgItem(hwndDlg, IDC_LONGDATEFMT_COMBO),
401 CB_SELECTSTRING,
402 -1,
403 (LPARAM)szLongDateFmt);
404 }
405 }
406
407 /* Set up max date value to registry */
408 static VOID
409 SetMaxDate(HWND hwndDlg, LCID lcid)
410 {
411 TCHAR szMaxDateVal[YEAR_STR_MAX_SIZE];
412 HWND hWndYearSpin;
413 INT nSpinVal;
414
415 hWndYearSpin = GetDlgItem(hwndDlg, IDC_SCR_MAX_YEAR);
416
417 /* Get spin value */
418 nSpinVal=LOWORD(SendMessage(hWndYearSpin,
419 UDM_GETPOS,
420 0,
421 0));
422
423 /* convert to wide char */
424 _itot(nSpinVal, szMaxDateVal, DECIMAL_RADIX);
425
426 /* Save max date value */
427 SetCalendarInfo(lcid,
428 CAL_GREGORIAN,
429 48 , /* CAL_ITWODIGITYEARMAX */
430 (LPCTSTR)szMaxDateVal);
431 }
432
433 /* Get max date value from registry set */
434 static INT
435 GetMaxDate(LCID lcid)
436 {
437 INT nMaxDateVal = 0;
438
439 GetCalendarInfo(lcid,
440 CAL_GREGORIAN,
441 CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
442 NULL,
443 0, /* ret type - number */
444 (LPDWORD)&nMaxDateVal);
445
446 return nMaxDateVal;
447 }
448
449 /* Set's MIN data edit control value to MAX-99 */
450 static VOID
451 SetMinData(HWND hwndDlg)
452 {
453 TCHAR OutBuffer[YEAR_STR_MAX_SIZE];
454 HWND hWndYearSpin;
455 INT nSpinVal;
456
457 hWndYearSpin = GetDlgItem(hwndDlg, IDC_SCR_MAX_YEAR);
458
459 /* Get spin value */
460 nSpinVal = LOWORD(SendMessage(hWndYearSpin,
461 UDM_GETPOS,
462 0,
463 0));
464
465 /* Set min year value */
466 wsprintf(OutBuffer, _T("%d"), (DWORD)nSpinVal - YEAR_DIFF);
467 SendMessage(GetDlgItem(hwndDlg, IDC_FIRSTYEAR_EDIT),
468 WM_SETTEXT,
469 0,
470 (LPARAM)OutBuffer);
471 }
472
473 /* Init spin control */
474 static VOID
475 InitMinMaxDateSpin(HWND hwndDlg, LCID lcid)
476 {
477 TCHAR OutBuffer[YEAR_STR_MAX_SIZE];
478 HWND hWndYearSpin;
479
480 /* Limit text lengths */
481 SendMessage(GetDlgItem(hwndDlg, IDC_FIRSTYEAR_EDIT),
482 EM_LIMITTEXT,
483 MAX_YEAR_EDIT,
484 0);
485 SendMessage(GetDlgItem(hwndDlg, IDC_SECONDYEAR_EDIT),
486 EM_LIMITTEXT,
487 MAX_YEAR_EDIT,
488 0);
489
490 hWndYearSpin = GetDlgItem(hwndDlg, IDC_SCR_MAX_YEAR);
491
492 /* Init max date value */
493 wsprintf(OutBuffer, _T("%04d"), (DWORD)GetMaxDate(lcid));
494 SendMessage(GetDlgItem(hwndDlg, IDC_SECONDYEAR_EDIT),
495 WM_SETTEXT,
496 0,
497 (LPARAM)OutBuffer);
498
499 /* Init min date value */
500 wsprintf(OutBuffer, _T("%04d"), (DWORD)GetMaxDate(lcid) - YEAR_DIFF);
501 SendMessage(GetDlgItem(hwndDlg, IDC_FIRSTYEAR_EDIT),
502 WM_SETTEXT,
503 0,
504 (LPARAM)OutBuffer);
505
506 /* Init updown control */
507 /* Set bounds */
508 SendMessage(hWndYearSpin,
509 UDM_SETRANGE,
510 0,
511 MAKELONG(MAX_YEAR,YEAR_DIFF));
512
513 /* Set current value */
514 SendMessage(hWndYearSpin,
515 UDM_SETPOS,
516 0,
517 MAKELONG(GetMaxDate(lcid),0));
518 }
519
520 /* Update all date locale samples */
521 static VOID
522 UpdateDateLocaleSamples(HWND hwndDlg,
523 LCID lcidLocale)
524 {
525 TCHAR OutBuffer[MAX_SAMPLES_STR_SIZE];
526
527 /* Get short date format sample */
528 GetDateFormat(lcidLocale, DATE_SHORTDATE, NULL, NULL, OutBuffer,
529 MAX_SAMPLES_STR_SIZE);
530 SendMessage(GetDlgItem(hwndDlg, IDC_SHRTDATESAMPLE_EDIT), WM_SETTEXT,
531 0, (LPARAM)OutBuffer);
532
533 /* Get long date sample */
534 GetDateFormat(lcidLocale, DATE_LONGDATE, NULL, NULL, OutBuffer,
535 MAX_SAMPLES_STR_SIZE);
536 SendMessage(GetDlgItem(hwndDlg, IDC_LONGDATESAMPLE_EDIT),
537 WM_SETTEXT, 0, (LPARAM)OutBuffer);
538 }
539
540 /* Property page dialog callback */
541 INT_PTR CALLBACK
542 DatePageProc(HWND hwndDlg,
543 UINT uMsg,
544 WPARAM wParam,
545 LPARAM lParam)
546 {
547 PGLOBALDATA pGlobalData;
548
549 pGlobalData = (PGLOBALDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
550
551 switch (uMsg)
552 {
553 case WM_INITDIALOG:
554 pGlobalData = (PGLOBALDATA)((LPPROPSHEETPAGE)lParam)->lParam;
555 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
556
557 InitMinMaxDateSpin(hwndDlg, pGlobalData->lcid);
558 UpdateDateLocaleSamples(hwndDlg, pGlobalData->lcid);
559 InitShortDateCB(hwndDlg, pGlobalData->lcid);
560 InitLongDateCB(hwndDlg, pGlobalData->lcid);
561 InitShortDateSepSamples(hwndDlg, pGlobalData->lcid);
562 /* TODO: Add other calendar types */
563 break;
564
565 case WM_COMMAND:
566 {
567 switch (LOWORD(wParam))
568 {
569 case IDC_SECONDYEAR_EDIT:
570 {
571 if(HIWORD(wParam)==EN_CHANGE)
572 {
573 SetMinData(hwndDlg);
574 }
575 }
576 case IDC_SCR_MAX_YEAR:
577 {
578 /* Set "Apply" button enabled */
579 /* FIXME */
580 //PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
581 }
582 break;
583 case IDC_CALTYPE_COMBO:
584 case IDC_HIJCHRON_COMBO:
585 case IDC_SHRTDATEFMT_COMBO:
586 case IDC_SHRTDATESEP_COMBO:
587 case IDC_LONGDATEFMT_COMBO:
588 {
589 if (HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_EDITCHANGE)
590 {
591 /* Set "Apply" button enabled */
592 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
593 }
594 }
595 break;
596 }
597 }
598 break;
599 case WM_NOTIFY:
600 {
601 LPNMHDR lpnm = (LPNMHDR)lParam;
602 /* If push apply button */
603 if (lpnm->code == (UINT)PSN_APPLY)
604 {
605 SetMaxDate(hwndDlg, pGlobalData->lcid);
606 if(!SetShortDateSep(hwndDlg, pGlobalData->lcid)) break;
607 if(!SetShortDateFormat(hwndDlg, pGlobalData->lcid)) break;
608 if(!SetLongDateFormat(hwndDlg, pGlobalData->lcid)) break;
609 InitShortDateCB(hwndDlg, pGlobalData->lcid);
610 /* FIXME: */
611 //Sleep(15);
612 UpdateDateLocaleSamples(hwndDlg, pGlobalData->lcid);
613 }
614 }
615 break;
616 }
617
618 return FALSE;
619 }
620
621 /* EOF */