f36fb10f90326da4b9fd707b639e2ffa93be5960
[reactos.git] / reactos / dll / cpl / intl / generalp.c
1 /*
2 * ReactOS
3 * Copyright (C) 2004, 2005 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/generalp.c
22 * PURPOSE: General property page
23 * PROGRAMMER: Eric Kohl
24 * Klemens Friedl
25 * Aleksey Bragin
26 */
27
28 #include "intl.h"
29
30 #include <debug.h>
31
32 #define SAMPLE_NUMBER _T("123456789")
33 #define NO_FLAG 0
34
35 typedef struct
36 {
37 LCTYPE lcType;
38 PWSTR pKeyName;
39 } LOCALE_KEY_DATA, *PLOCALE_KEY_DATA;
40
41 HWND hList;
42 HWND hLocaleList, hGeoList;
43 BOOL bSpain = FALSE;
44
45 LOCALE_KEY_DATA LocaleKeyData[] =
46 {
47 {LOCALE_ICALENDARTYPE, L"iCalendarType"},
48 {LOCALE_ICOUNTRY, L"iCountry"},
49 {LOCALE_ICURRDIGITS, L"iCurrDigits"},
50 {LOCALE_ICURRENCY, L"iCurrency"},
51 {LOCALE_IDATE, L"iDate"},
52 {LOCALE_IDIGITS, L"iDigits"},
53 {LOCALE_IFIRSTDAYOFWEEK, L"iFirstDayOfWeek"},
54 {LOCALE_IFIRSTWEEKOFYEAR, L"iFirstWeekOfYear"},
55 {LOCALE_ILZERO, L"iLZero"},
56 {LOCALE_IMEASURE, L"iMeasure"},
57 {LOCALE_INEGCURR, L"iNegCurr"},
58 {LOCALE_INEGNUMBER, L"iNegNumber"},
59 {LOCALE_ITIME, L"iTime"},
60 {LOCALE_ITIMEMARKPOSN, L"iTimePrefix"},
61 {LOCALE_ITLZERO, L"iTLZero"},
62 {LOCALE_IDIGITSUBSTITUTION, L"NumShape"},
63 {LOCALE_S1159, L"s1159"},
64 {LOCALE_S2359, L"s2359"},
65 {LOCALE_SCOUNTRY, L"sCountry"},
66 {LOCALE_SCURRENCY, L"sCurrency"},
67 {LOCALE_SDATE, L"sDate"},
68 {LOCALE_SDECIMAL, L"sDecimal"},
69 {LOCALE_SGROUPING, L"sGrouping"},
70 {LOCALE_SABBREVLANGNAME, L"sLanguage"},
71 {LOCALE_SLIST, L"sList"},
72 {LOCALE_SLONGDATE, L"sLongDate"},
73 {LOCALE_SMONDECIMALSEP, L"sMonDecimalSep"},
74 {LOCALE_SMONGROUPING, L"sMonGrouping"},
75 {LOCALE_SMONTHOUSANDSEP, L"sMonThousandSep"},
76 {LOCALE_SNATIVEDIGITS, L"sNativeDigits"},
77 {LOCALE_SNEGATIVESIGN, L"sNegativeSign"},
78 {LOCALE_SPOSITIVESIGN, L"sPositiveSign"},
79 {LOCALE_SSHORTDATE, L"sShortDate"},
80 {LOCALE_STHOUSAND, L"sThousand"},
81 {LOCALE_STIME, L"sTime"},
82 {LOCALE_STIMEFORMAT, L"sTimeFormat"}
83 };
84
85
86 static BOOL CALLBACK
87 LocalesEnumProc(LPTSTR lpLocale)
88 {
89 LCID lcid;
90 TCHAR lang[255];
91 INT index;
92 BOOL bNoShow = FALSE;
93
94 lcid = _tcstoul(lpLocale, NULL, 16);
95
96 /* Display only languages with installed support */
97 if (!IsValidLocale(lcid, LCID_INSTALLED))
98 return TRUE;
99
100 if (lcid == MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) ||
101 lcid == MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT))
102 {
103 if (bSpain == FALSE)
104 {
105 LoadString(hApplet, IDS_SPAIN, lang, 255);
106 bSpain = TRUE;
107 }
108 else
109 {
110 bNoShow = TRUE;
111 }
112 }
113 else
114 {
115 GetLocaleInfo(lcid, LOCALE_SLANGUAGE, lang, sizeof(lang)/sizeof(TCHAR));
116 }
117
118 if (bNoShow == FALSE)
119 {
120 index = SendMessage(hList,
121 CB_ADDSTRING,
122 0,
123 (LPARAM)lang);
124
125 SendMessage(hList,
126 CB_SETITEMDATA,
127 index,
128 (LPARAM)lcid);
129 }
130
131 return TRUE;
132 }
133
134
135 PWSTR
136 GetLocaleString(
137 PWSTR *pLocaleArray,
138 LCTYPE lcType)
139 {
140 DWORD dwDataCount, i;
141
142 dwDataCount = sizeof(LocaleKeyData) / sizeof(LOCALE_KEY_DATA);
143 for (i = 0; i < dwDataCount; i++)
144 {
145 if (LocaleKeyData[i].lcType == lcType)
146 return pLocaleArray[i];
147 }
148
149 return NULL;
150 }
151
152
153 /* Update all locale samples */
154 static
155 VOID
156 UpdateLocaleSample(
157 HWND hwndDlg,
158 PGLOBALDATA pGlobalData)
159 {
160 WCHAR OutBuffer[MAX_SAMPLES_STR_SIZE];
161
162 /* Get number format sample */
163 GetNumberFormatW(pGlobalData->lcid, NO_FLAG, SAMPLE_NUMBER, NULL,
164 OutBuffer, MAX_SAMPLES_STR_SIZE);
165 SendDlgItemMessageW(hwndDlg, IDC_NUMSAMPLE_EDIT,
166 WM_SETTEXT, 0, (LPARAM)OutBuffer);
167 ZeroMemory(OutBuffer, MAX_SAMPLES_STR_SIZE * sizeof(WCHAR));
168
169 /* Get monetary format sample */
170 GetCurrencyFormatW(pGlobalData->lcid, NO_FLAG, SAMPLE_NUMBER, NULL,
171 OutBuffer, MAX_SAMPLES_STR_SIZE);
172 SendDlgItemMessageW(hwndDlg, IDC_MONEYSAMPLE_EDIT,
173 WM_SETTEXT, 0, (LPARAM)OutBuffer);
174 ZeroMemory(OutBuffer, MAX_SAMPLES_STR_SIZE * sizeof(WCHAR));
175
176 /* Get time format sample */
177 GetTimeFormatW(pGlobalData->lcid, NO_FLAG, NULL, NULL,
178 OutBuffer, MAX_SAMPLES_STR_SIZE);
179 SendDlgItemMessageW(hwndDlg, IDC_TIMESAMPLE_EDIT,
180 WM_SETTEXT, 0, (LPARAM)OutBuffer);
181 ZeroMemory(OutBuffer, MAX_SAMPLES_STR_SIZE * sizeof(WCHAR));
182
183 /* Get short date format sample */
184 GetDateFormatW(pGlobalData->lcid, DATE_SHORTDATE, NULL, NULL,
185 OutBuffer, MAX_SAMPLES_STR_SIZE);
186 SendDlgItemMessageW(hwndDlg, IDC_SHORTTIMESAMPLE_EDIT,
187 WM_SETTEXT, 0, (LPARAM)OutBuffer);
188
189 /* Get long date sample */
190 GetDateFormatW(pGlobalData->lcid, DATE_LONGDATE, NULL, NULL,
191 OutBuffer, MAX_SAMPLES_STR_SIZE);
192 SendDlgItemMessageW(hwndDlg, IDC_FULLTIMESAMPLE_EDIT,
193 WM_SETTEXT, 0, (LPARAM)OutBuffer);
194 }
195
196 static VOID
197 CreateLanguagesList(HWND hwnd)
198 {
199 TCHAR langSel[255];
200
201 hList = hwnd;
202 bSpain = FALSE;
203 EnumSystemLocales(LocalesEnumProc, LCID_SUPPORTED);
204
205 /* Select current locale */
206 /* or should it be System and not user? */
207 GetLocaleInfo(GetUserDefaultLCID(), LOCALE_SLANGUAGE, langSel, sizeof(langSel)/sizeof(TCHAR));
208
209 SendMessage(hList,
210 CB_SELECTSTRING,
211 -1,
212 (LPARAM)langSel);
213 }
214
215
216 BOOL
217 LoadCurrentLocale(
218 PGLOBALDATA pGlobalData)
219 {
220 WCHAR szValue[9];
221 PWSTR ptr;
222 HKEY hLocaleKey;
223 DWORD ret;
224 DWORD dwSize;
225 DWORD i;
226
227 ret = RegOpenKeyExW(HKEY_CURRENT_USER,
228 L"Control Panel\\International",
229 0,
230 KEY_READ,
231 &hLocaleKey);
232 if (ret != ERROR_SUCCESS)
233 {
234 PrintErrorMsgBox(IDS_ERROR_INT_KEY_REG);
235 return FALSE;
236 }
237
238 pGlobalData->dwLocaleCount = sizeof(LocaleKeyData) / sizeof(LOCALE_KEY_DATA);
239
240 pGlobalData->pLocaleArray = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
241 pGlobalData->dwLocaleCount * sizeof(PWSTR));
242 if (pGlobalData->pLocaleArray == NULL)
243 {
244 RegCloseKey(hLocaleKey);
245 return FALSE;
246 }
247
248 dwSize = 9 * sizeof(WCHAR);
249 RegQueryValueExW(hLocaleKey,
250 L"Locale",
251 NULL,
252 NULL,
253 (PBYTE)szValue,
254 &dwSize);
255 pGlobalData->lcid = (LCID)wcstoul(szValue, &ptr, 16);
256
257 for (i = 0; i < pGlobalData->dwLocaleCount; i++)
258 {
259 RegQueryValueExW(hLocaleKey,
260 LocaleKeyData[i].pKeyName,
261 NULL,
262 NULL,
263 NULL,
264 &dwSize);
265 if (dwSize > 0)
266 {
267 pGlobalData->pLocaleArray[i] = HeapAlloc(GetProcessHeap(), 0, dwSize);
268 if (pGlobalData->pLocaleArray[i])
269 {
270 RegQueryValueExW(hLocaleKey,
271 LocaleKeyData[i].pKeyName,
272 NULL,
273 NULL,
274 (LPVOID)pGlobalData->pLocaleArray[i],
275 &dwSize);
276 }
277 }
278 }
279
280 RegCloseKey(hLocaleKey);
281
282 return TRUE;
283 }
284
285
286 VOID
287 FreeCurrentLocale(
288 PGLOBALDATA pGlobalData)
289 {
290 DWORD i;
291
292 if (pGlobalData == NULL || pGlobalData->pLocaleArray == NULL)
293 return;
294
295 for (i = 0; i < pGlobalData->dwLocaleCount; i++)
296 {
297 if (pGlobalData->pLocaleArray[i])
298 HeapFree(GetProcessHeap(), 0, pGlobalData->pLocaleArray[i]);
299 }
300 HeapFree(GetProcessHeap(), 0, pGlobalData->pLocaleArray);
301 }
302
303
304 VOID
305 SetNewLocale(
306 PGLOBALDATA pGlobalData,
307 LCID lcid)
308 {
309 DWORD i, dwSize;
310
311 pGlobalData->lcid = lcid;
312
313 for (i = 0; i < pGlobalData->dwLocaleCount; i++)
314 {
315 if (pGlobalData->pLocaleArray[i])
316 {
317 HeapFree(GetProcessHeap(), 0, pGlobalData->pLocaleArray[i]);
318 pGlobalData->pLocaleArray[i] = NULL;
319 }
320
321 dwSize = GetLocaleInfo(lcid,
322 LocaleKeyData[i].lcType | LOCALE_NOUSEROVERRIDE,
323 NULL,
324 0);
325 if (dwSize > 0)
326 {
327 pGlobalData->pLocaleArray[i] = HeapAlloc(GetProcessHeap(), 0, dwSize * sizeof(WCHAR));
328 if (pGlobalData->pLocaleArray[i])
329 {
330 GetLocaleInfo(lcid,
331 LocaleKeyData[i].lcType | LOCALE_NOUSEROVERRIDE,
332 pGlobalData->pLocaleArray[i],
333 dwSize);
334 }
335 }
336 }
337 }
338
339
340 /* Sets new locale */
341 VOID
342 SaveCurrentLocale(
343 PGLOBALDATA pGlobalData)
344 {
345 // HKCU\\Control Panel\\International\\Locale = 0409 (type=0)
346 // HKLM,"SYSTEM\CurrentControlSet\Control\NLS\Language","Default",0x00000000,"0409" (type=0)
347 // HKLM,"SYSTEM\CurrentControlSet\Control\NLS\Language","InstallLanguage",0x00000000,"0409" (type=0)
348
349 // Set locale
350 HKEY localeKey;
351 DWORD ret;
352 WCHAR value[9];
353 DWORD valuesize;
354 DWORD i;
355
356 ret = RegOpenKeyExW(HKEY_CURRENT_USER, L"Control Panel\\International",
357 0, KEY_READ | KEY_WRITE, &localeKey);
358 if (ret != ERROR_SUCCESS)
359 {
360 PrintErrorMsgBox(IDS_ERROR_INT_KEY_REG);
361 return;
362 }
363
364 wsprintf(value, L"%08x", (DWORD)pGlobalData->lcid);
365 valuesize = (wcslen(value) + 1) * sizeof(WCHAR);
366
367 ret = RegSetValueExW(localeKey, L"Locale", 0, REG_SZ, (PBYTE)value, valuesize);
368 if (ret != ERROR_SUCCESS)
369 {
370 RegCloseKey(localeKey);
371 PrintErrorMsgBox(IDS_ERROR_INT_KEY_REG);
372 return;
373 }
374
375 for (i = 0; i < pGlobalData->dwLocaleCount; i++)
376 {
377 RegSetValueExW(localeKey,
378 LocaleKeyData[i].pKeyName,
379 0,
380 REG_SZ,
381 (PBYTE)pGlobalData->pLocaleArray[i],
382 (wcslen(pGlobalData->pLocaleArray[i]) + 1) * sizeof(WCHAR));
383 }
384
385 /* Flush and close the locale key */
386 RegFlushKey(localeKey);
387 RegCloseKey(localeKey);
388
389 /* Set the new locale for the current process */
390 NtSetDefaultLocale(TRUE, pGlobalData->lcid);
391
392 }
393
394 /* Location enumerate procedure */
395 BOOL
396 CALLBACK
397 LocationsEnumProc(GEOID gId)
398 {
399 TCHAR loc[MAX_STR_SIZE];
400 INT index;
401
402 if (GetGeoInfo(gId, GEO_FRIENDLYNAME, loc, MAX_STR_SIZE, LANG_SYSTEM_DEFAULT) == 0)
403 return TRUE;
404
405 index = (INT)SendMessage(hGeoList,
406 CB_ADDSTRING,
407 0,
408 (LPARAM)loc);
409
410 SendMessage(hGeoList,
411 CB_SETITEMDATA,
412 index,
413 (LPARAM)gId);
414
415 return TRUE;
416 }
417
418 /* Enumerate all system locations identifiers */
419 static
420 GEOID
421 CreateLocationsList(HWND hWnd)
422 {
423 GEOID userGeoID;
424 TCHAR loc[MAX_STR_SIZE];
425
426 hGeoList = hWnd;
427
428 EnumSystemGeoID(GEOCLASS_NATION, 0, LocationsEnumProc);
429
430 /* Select current location */
431 userGeoID = GetUserGeoID(GEOCLASS_NATION);
432 GetGeoInfo(userGeoID,
433 GEO_FRIENDLYNAME,
434 loc,
435 MAX_STR_SIZE,
436 LANG_SYSTEM_DEFAULT);
437
438 SendMessage(hGeoList,
439 CB_SELECTSTRING,
440 (WPARAM) -1,
441 (LPARAM)loc);
442
443 return userGeoID;
444 }
445
446 DWORD
447 VerifyUnattendLCID(HWND hwndDlg)
448 {
449 LRESULT lCount, lIndex, lResult;
450
451 lCount = SendMessage(hList, CB_GETCOUNT, (WPARAM)0, (LPARAM)0);
452 if (lCount == CB_ERR)
453 {
454 return 0;
455 }
456
457 for (lIndex = 0; lIndex < lCount; lIndex++)
458 {
459 lResult = SendMessage(hList, CB_GETITEMDATA, (WPARAM)lIndex, (LPARAM)0);
460 if (lResult == CB_ERR)
461 {
462 continue;
463 }
464
465 if (lResult == (LRESULT)UnattendLCID)
466 {
467 SendMessage(hList, CB_SETCURSEL, (WPARAM)lIndex, (LPARAM)0);
468 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
469 return 1;
470 }
471 }
472
473 return 0;
474 }
475
476
477 /* Property page dialog callback */
478 INT_PTR CALLBACK
479 GeneralPageProc(HWND hwndDlg,
480 UINT uMsg,
481 WPARAM wParam,
482 LPARAM lParam)
483 {
484 PGLOBALDATA pGlobalData;
485
486 pGlobalData = (PGLOBALDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
487
488 switch (uMsg)
489 {
490 case WM_INITDIALOG:
491 pGlobalData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLOBALDATA));
492 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
493
494 if (pGlobalData)
495 {
496 LoadCurrentLocale(pGlobalData);
497
498 CreateLanguagesList(GetDlgItem(hwndDlg, IDC_LANGUAGELIST));
499 UpdateLocaleSample(hwndDlg, pGlobalData);
500 pGlobalData->geoid = CreateLocationsList(GetDlgItem(hwndDlg, IDC_LOCATION_COMBO));
501 if (IsUnattendedSetupEnabled)
502 {
503 if (VerifyUnattendLCID(hwndDlg))
504 {
505 SetNewLocale(pGlobalData, UnattendLCID);
506 SaveCurrentLocale(pGlobalData);
507 PostQuitMessage(0);
508 }
509 else
510 {
511 DPRINT1("VerifyUnattendLCID failed\n");
512 }
513 return TRUE;
514 }
515 }
516 break;
517
518 case WM_COMMAND:
519 switch (LOWORD(wParam))
520 {
521 case IDC_LANGUAGELIST:
522 if (HIWORD(wParam) == CBN_SELCHANGE)
523 {
524 LCID NewLcid;
525 INT iCurSel;
526
527 iCurSel = SendMessage(hList,
528 CB_GETCURSEL,
529 0,
530 0);
531 if (iCurSel == CB_ERR)
532 break;
533
534 NewLcid = SendMessage(hList,
535 CB_GETITEMDATA,
536 iCurSel,
537 0);
538 if (NewLcid == (LCID)CB_ERR)
539 break;
540
541 SetNewLocale(pGlobalData, NewLcid);
542 UpdateLocaleSample(hwndDlg, pGlobalData);
543 pGlobalData->fUserLocaleChanged = TRUE;
544
545 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
546 }
547 break;
548
549 case IDC_LOCATION_COMBO:
550 if (HIWORD(wParam) == CBN_SELCHANGE)
551 {
552 GEOID NewGeoID;
553 INT iCurSel;
554
555 iCurSel = SendMessage(GetDlgItem(hwndDlg, IDC_LOCATION_COMBO),
556 CB_GETCURSEL,
557 0,
558 0);
559 if (iCurSel == CB_ERR)
560 break;
561
562 NewGeoID = SendMessage(GetDlgItem(hwndDlg, IDC_LOCATION_COMBO),
563 CB_GETITEMDATA,
564 iCurSel,
565 0);
566 if (NewGeoID == (GEOID)CB_ERR)
567 break;
568
569 pGlobalData->geoid = NewGeoID;
570 pGlobalData->fGeoIdChanged = TRUE;
571
572 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
573 }
574 break;
575
576 case IDC_SETUP_BUTTON:
577 SetupApplet(GetParent(hwndDlg), pGlobalData);
578 break;
579 }
580 break;
581
582 case WM_NOTIFY:
583 {
584 LPNMHDR lpnm = (LPNMHDR)lParam;
585
586 if (lpnm->code == (UINT)PSN_APPLY)
587 {
588 /* Apply changes */
589 PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg);
590
591 /* Set new locale */
592 if (pGlobalData->fUserLocaleChanged == TRUE)
593 {
594 SaveCurrentLocale(pGlobalData);
595 pGlobalData->fUserLocaleChanged = FALSE;
596 }
597
598 /* Set new GEO ID */
599 if (pGlobalData->fGeoIdChanged == TRUE)
600 {
601 SetUserGeoID(pGlobalData->geoid);
602 pGlobalData->fGeoIdChanged = FALSE;
603 }
604
605 AddNewKbLayoutsByLcid(pGlobalData->lcid);
606 }
607 }
608 break;
609
610 case WM_DESTROY:
611 if (pGlobalData)
612 {
613 FreeCurrentLocale(pGlobalData);
614 HeapFree(GetProcessHeap(), 0, pGlobalData);
615 }
616 break;
617 }
618
619 return FALSE;
620 }
621
622 /* EOF */