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