1 /* 2 * 'View' tab property sheet of Folder Options 3 * 4 * Copyright 2007 Johannes Anderwald <johannes.anderwald@reactos.org> 5 * Copyright 2016-2018 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "precomp.h" 23 24 WINE_DEFAULT_DEBUG_CHANNEL (fprop); 25 26 ///////////////////////////////////////////////////////////////////////////// 27 // View Tree 28 29 // predefined icon IDs (See ViewDlg_CreateTreeImageList function below) 30 #define I_CHECKED 0 31 #define I_UNCHECKED 1 32 #define I_CHECKED_DISABLED 2 33 #define I_UNCHECKED_DISABLED 3 34 #define I_RADIO_CHECKED 4 35 #define I_RADIO_UNCHECKED 5 36 #define I_RADIO_CHECKED_DISABLED 6 37 #define I_RADIO_UNCHECKED_DISABLED 7 38 #define PREDEFINED_ICON_COUNT 8 39 40 // uniquely-defined icon entry for View Advanced Settings 41 typedef struct VIEWTREE_ICON 42 { 43 WCHAR szPath[MAX_PATH]; 44 UINT nIconIndex; 45 } VIEWTREE_ICON, *PVIEWTREE_ICON; 46 47 // types of View Advanced Setting entry 48 typedef enum VIEWTREE_ENTRY_TYPE 49 { 50 AETYPE_GROUP, 51 AETYPE_CHECKBOX, 52 AETYPE_RADIO, 53 } VIEWTREE_ENTRY_TYPE, *PVIEWTREE_ENTRY_TYPE; 54 55 // an entry info of View Advanced Settings 56 typedef struct VIEWTREE_ENTRY 57 { 58 DWORD dwID; // entry ID 59 DWORD dwParentID; // parent entry ID 60 DWORD dwResourceID; // resource ID 61 WCHAR szKeyName[64]; // entry key name 62 DWORD dwType; // VIEWTREE_ENTRY_TYPE 63 WCHAR szText[MAX_PATH]; // text 64 INT nIconID; // icon ID (See VIEWTREE_ICON) 65 66 HKEY hkeyRoot; // registry root key 67 WCHAR szRegPath[MAX_PATH]; // registry path 68 WCHAR szValueName[64]; // registry value name 69 70 DWORD dwCheckedValue; // checked value 71 DWORD dwUncheckedValue; // unchecked value 72 DWORD dwDefaultValue; // defalut value 73 BOOL bHasUncheckedValue; // If FALSE, UncheckedValue is invalid 74 75 HTREEITEM hItem; // for TreeView 76 BOOL bGrayed; // disabled? 77 BOOL bChecked; // checked? 78 } VIEWTREE_ENTRY, *PVIEWTREE_ENTRY; 79 80 // definition of view advanced entries 81 static PVIEWTREE_ENTRY s_ViewTreeEntries = NULL; 82 static INT s_ViewTreeEntryCount = 0; 83 84 // definition of icon stock 85 static PVIEWTREE_ICON s_ViewTreeIcons = NULL; 86 static INT s_ViewTreeIconCount = 0; 87 static HIMAGELIST s_hTreeImageList = NULL; 88 89 static INT 90 ViewTree_FindIcon(LPCWSTR pszPath, UINT nIconIndex) 91 { 92 for (INT i = PREDEFINED_ICON_COUNT; i < s_ViewTreeIconCount; ++i) 93 { 94 PVIEWTREE_ICON pIcon = &s_ViewTreeIcons[i]; 95 if (pIcon->nIconIndex == nIconIndex && 96 lstrcmpiW(pIcon->szPath, pszPath) == 0) 97 { 98 return i; // icon ID 99 } 100 } 101 return -1; // not found 102 } 103 104 static INT 105 ViewTree_AddIcon(LPCWSTR pszPath, UINT nIconIndex) 106 { 107 PVIEWTREE_ICON pAllocated; 108 109 // return the ID if already existed 110 INT nIconID = ViewTree_FindIcon(pszPath, nIconIndex); 111 if (nIconID != -1) 112 return nIconID; // already exists 113 114 // extract a small icon 115 HICON hIconSmall = NULL; 116 ExtractIconExW(pszPath, nIconIndex, NULL, &hIconSmall, 1); 117 if (hIconSmall == NULL) 118 return -1; // failure 119 120 // resize s_ViewTreeIcons 121 size_t Size = (s_ViewTreeIconCount + 1) * sizeof(VIEWTREE_ICON); 122 pAllocated = (PVIEWTREE_ICON)realloc(s_ViewTreeIcons, Size); 123 if (pAllocated == NULL) 124 return -1; // failure 125 else 126 s_ViewTreeIcons = pAllocated; 127 128 // save icon information 129 PVIEWTREE_ICON pIcon = &s_ViewTreeIcons[s_ViewTreeIconCount]; 130 lstrcpynW(pIcon->szPath, pszPath, _countof(pIcon->szPath)); 131 pIcon->nIconIndex = nIconIndex; 132 133 // add the icon to the image list 134 ImageList_AddIcon(s_hTreeImageList, hIconSmall); 135 136 // increment the counter 137 nIconID = s_ViewTreeIconCount; 138 ++s_ViewTreeIconCount; 139 140 DestroyIcon(hIconSmall); 141 142 return nIconID; // newly-added icon ID 143 } 144 145 static PVIEWTREE_ENTRY 146 ViewTree_GetItem(DWORD dwID) 147 { 148 if (dwID == DWORD(-1)) 149 return NULL; 150 151 for (INT i = 0; i < s_ViewTreeEntryCount; ++i) 152 { 153 PVIEWTREE_ENTRY pEntry = &s_ViewTreeEntries[i]; 154 if (pEntry->dwID == dwID) 155 return pEntry; 156 } 157 return NULL; // failure 158 } 159 160 static INT 161 ViewTree_GetImage(PVIEWTREE_ENTRY pEntry) 162 { 163 switch (pEntry->dwType) 164 { 165 case AETYPE_GROUP: 166 return pEntry->nIconID; 167 168 case AETYPE_CHECKBOX: 169 if (pEntry->bGrayed) 170 { 171 if (pEntry->bChecked) 172 return I_CHECKED_DISABLED; 173 else 174 return I_UNCHECKED_DISABLED; 175 } 176 else 177 { 178 if (pEntry->bChecked) 179 return I_CHECKED; 180 else 181 return I_UNCHECKED; 182 } 183 184 case AETYPE_RADIO: 185 if (pEntry->bGrayed) 186 { 187 if (pEntry->bChecked) 188 return I_RADIO_CHECKED_DISABLED; 189 else 190 return I_RADIO_UNCHECKED_DISABLED; 191 } 192 else 193 { 194 if (pEntry->bChecked) 195 return I_RADIO_CHECKED; 196 else 197 return I_RADIO_UNCHECKED; 198 } 199 } 200 return -1; // failure 201 } 202 203 static VOID 204 ViewTree_InsertEntry(HWND hwndTreeView, PVIEWTREE_ENTRY pEntry) 205 { 206 PVIEWTREE_ENTRY pParent = ViewTree_GetItem(pEntry->dwParentID); 207 HTREEITEM hParent = TVI_ROOT; 208 if (pParent) 209 hParent = pParent->hItem; 210 211 TV_INSERTSTRUCT Insertion; 212 ZeroMemory(&Insertion, sizeof(Insertion)); 213 Insertion.hParent = hParent; 214 Insertion.hInsertAfter = TVI_LAST; 215 Insertion.item.mask = 216 TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; 217 Insertion.item.pszText = pEntry->szText; 218 219 INT iImage = ViewTree_GetImage(pEntry); 220 Insertion.item.iImage = Insertion.item.iSelectedImage = iImage; 221 Insertion.item.lParam = pEntry->dwID; 222 pEntry->hItem = TreeView_InsertItem(hwndTreeView, &Insertion); 223 } 224 225 static VOID 226 ViewTree_InsertAll(HWND hwndTreeView) 227 { 228 TreeView_DeleteAllItems(hwndTreeView); 229 230 // insert the entries 231 PVIEWTREE_ENTRY pEntry; 232 for (INT i = 0; i < s_ViewTreeEntryCount; ++i) 233 { 234 pEntry = &s_ViewTreeEntries[i]; 235 ViewTree_InsertEntry(hwndTreeView, pEntry); 236 } 237 238 // expand all 239 for (INT i = 0; i < s_ViewTreeEntryCount; ++i) 240 { 241 pEntry = &s_ViewTreeEntries[i]; 242 if (pEntry->dwType == AETYPE_GROUP) 243 { 244 TreeView_Expand(hwndTreeView, pEntry->hItem, TVE_EXPAND); 245 } 246 } 247 } 248 249 static BOOL 250 ViewTree_LoadTree(HKEY hKey, LPCWSTR pszKeyName, DWORD dwParentID) 251 { 252 DWORD dwIndex; 253 WCHAR szKeyName[64], szText[MAX_PATH], *pch; 254 DWORD Size, Value; 255 PVIEWTREE_ENTRY pAllocated; 256 257 // resize s_ViewTreeEntries 258 Size = (s_ViewTreeEntryCount + 1) * sizeof(VIEWTREE_ENTRY); 259 pAllocated = (PVIEWTREE_ENTRY)realloc(s_ViewTreeEntries, Size); 260 if (pAllocated == NULL) 261 return FALSE; // failure 262 else 263 s_ViewTreeEntries = pAllocated; 264 265 PVIEWTREE_ENTRY pEntry = &s_ViewTreeEntries[s_ViewTreeEntryCount]; 266 267 // dwID, dwParentID, szKeyName 268 pEntry->dwID = s_ViewTreeEntryCount; 269 pEntry->dwParentID = dwParentID; 270 lstrcpynW(pEntry->szKeyName, pszKeyName, _countof(pEntry->szKeyName)); 271 272 // Text, ResourceID 273 pEntry->szText[0] = 0; 274 pEntry->dwResourceID = 0; 275 szText[0] = 0; 276 Size = sizeof(szText); 277 RegQueryValueExW(hKey, L"Text", NULL, NULL, LPBYTE(szText), &Size); 278 if (szText[0] == L'@') 279 { 280 pch = wcsrchr(szText, L','); 281 if (pch) 282 { 283 *pch = 0; 284 dwIndex = abs(_wtoi(pch + 1)); 285 pEntry->dwResourceID = dwIndex; 286 } 287 HINSTANCE hInst = LoadLibraryW(&szText[1]); 288 LoadStringW(hInst, dwIndex, szText, _countof(szText)); 289 FreeLibrary(hInst); 290 } 291 else 292 { 293 pEntry->dwResourceID = DWORD(-1); 294 } 295 lstrcpynW(pEntry->szText, szText, _countof(pEntry->szText)); 296 297 // Type 298 szText[0] = 0; 299 RegQueryValueExW(hKey, L"Type", NULL, NULL, LPBYTE(szText), &Size); 300 if (lstrcmpiW(szText, L"checkbox") == 0) 301 pEntry->dwType = AETYPE_CHECKBOX; 302 else if (lstrcmpiW(szText, L"radio") == 0) 303 pEntry->dwType = AETYPE_RADIO; 304 else if (lstrcmpiW(szText, L"group") == 0) 305 pEntry->dwType = AETYPE_GROUP; 306 else 307 return FALSE; // failure 308 309 pEntry->nIconID = -1; 310 if (pEntry->dwType == AETYPE_GROUP) 311 { 312 // Bitmap (Icon) 313 UINT nIconIndex = 0; 314 Size = sizeof(szText); 315 szText[0] = 0; 316 RegQueryValueExW(hKey, L"Bitmap", NULL, NULL, LPBYTE(szText), &Size); 317 318 WCHAR szExpanded[MAX_PATH]; 319 ExpandEnvironmentStringsW(szText, szExpanded, _countof(szExpanded)); 320 pch = wcsrchr(szExpanded, L','); 321 if (pch) 322 { 323 *pch = 0; 324 nIconIndex = abs(_wtoi(pch + 1)); 325 } 326 pEntry->nIconID = ViewTree_AddIcon(szExpanded, nIconIndex); 327 } 328 329 if (pEntry->dwType == AETYPE_GROUP) 330 { 331 pEntry->hkeyRoot = NULL; 332 pEntry->szRegPath[0] = 0; 333 pEntry->szValueName[0] = 0; 334 pEntry->dwCheckedValue = 0; 335 pEntry->bHasUncheckedValue = FALSE; 336 pEntry->dwUncheckedValue = 0; 337 pEntry->dwDefaultValue = 0; 338 pEntry->hItem = NULL; 339 pEntry->bGrayed = FALSE; 340 pEntry->bChecked = FALSE; 341 } 342 else 343 { 344 // HKeyRoot 345 HKEY HKeyRoot = HKEY_CURRENT_USER; 346 Size = sizeof(HKeyRoot); 347 RegQueryValueExW(hKey, L"HKeyRoot", NULL, NULL, LPBYTE(&HKeyRoot), &Size); 348 pEntry->hkeyRoot = HKeyRoot; 349 350 // RegPath 351 pEntry->szRegPath[0] = 0; 352 Size = sizeof(szText); 353 RegQueryValueExW(hKey, L"RegPath", NULL, NULL, LPBYTE(szText), &Size); 354 lstrcpynW(pEntry->szRegPath, szText, _countof(pEntry->szRegPath)); 355 356 // ValueName 357 pEntry->szValueName[0] = 0; 358 Size = sizeof(szText); 359 RegQueryValueExW(hKey, L"ValueName", NULL, NULL, LPBYTE(szText), &Size); 360 lstrcpynW(pEntry->szValueName, szText, _countof(pEntry->szValueName)); 361 362 // CheckedValue 363 Size = sizeof(Value); 364 Value = 0x00000001; 365 RegQueryValueExW(hKey, L"CheckedValue", NULL, NULL, LPBYTE(&Value), &Size); 366 pEntry->dwCheckedValue = Value; 367 368 // UncheckedValue 369 Size = sizeof(Value); 370 Value = 0x00000000; 371 pEntry->bHasUncheckedValue = TRUE; 372 if (RegQueryValueExW(hKey, L"UncheckedValue", NULL, 373 NULL, LPBYTE(&Value), &Size) != ERROR_SUCCESS) 374 { 375 pEntry->bHasUncheckedValue = FALSE; 376 } 377 pEntry->dwUncheckedValue = Value; 378 379 // DefaultValue 380 Size = sizeof(Value); 381 Value = 0x00000001; 382 RegQueryValueExW(hKey, L"DefaultValue", NULL, NULL, LPBYTE(&Value), &Size); 383 pEntry->dwDefaultValue = Value; 384 385 // hItem 386 pEntry->hItem = NULL; 387 388 // bGrayed, bChecked 389 HKEY hkeyTarget; 390 Value = pEntry->dwDefaultValue; 391 pEntry->bGrayed = TRUE; 392 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0, 393 KEY_READ, &hkeyTarget) == ERROR_SUCCESS) 394 { 395 Size = sizeof(Value); 396 if (RegQueryValueExW(hkeyTarget, pEntry->szValueName, NULL, NULL, 397 LPBYTE(&Value), &Size) == ERROR_SUCCESS) 398 { 399 pEntry->bGrayed = FALSE; 400 } 401 RegCloseKey(hkeyTarget); 402 } 403 pEntry->bChecked = (Value == pEntry->dwCheckedValue); 404 } 405 406 // Grayed (ReactOS extension) 407 Size = sizeof(Value); 408 Value = FALSE; 409 RegQueryValueExW(hKey, L"Grayed", NULL, NULL, LPBYTE(&Value), &Size); 410 if (!pEntry->bGrayed) 411 pEntry->bGrayed = Value; 412 413 BOOL bIsGroup = (pEntry->dwType == AETYPE_GROUP); 414 dwParentID = pEntry->dwID; 415 ++s_ViewTreeEntryCount; 416 417 if (!bIsGroup) 418 return TRUE; // success 419 420 // load the children 421 dwIndex = 0; 422 while (RegEnumKeyW(hKey, dwIndex, szKeyName, 423 _countof(szKeyName)) == ERROR_SUCCESS) 424 { 425 HKEY hkeyChild; 426 if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ, 427 &hkeyChild) != ERROR_SUCCESS) 428 { 429 ++dwIndex; 430 continue; // failure 431 } 432 433 ViewTree_LoadTree(hkeyChild, szKeyName, dwParentID); 434 RegCloseKey(hkeyChild); 435 436 ++dwIndex; 437 } 438 439 return TRUE; // success 440 } 441 442 static BOOL ViewTree_LoadAll(VOID) 443 { 444 // free if already existed 445 if (s_ViewTreeEntries) 446 { 447 free(s_ViewTreeEntries); 448 s_ViewTreeEntries = NULL; 449 } 450 s_ViewTreeEntryCount = 0; 451 452 HKEY hKey; 453 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, 454 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", 455 0, KEY_READ, &hKey) != ERROR_SUCCESS) 456 { 457 return FALSE; // failure 458 } 459 460 // load the children 461 WCHAR szKeyName[64]; 462 DWORD dwIndex = 0; 463 while (RegEnumKeyW(hKey, dwIndex, szKeyName, 464 _countof(szKeyName)) == ERROR_SUCCESS) 465 { 466 HKEY hkeyChild; 467 if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ, 468 &hkeyChild) != ERROR_SUCCESS) 469 { 470 ++dwIndex; 471 continue; // failure 472 } 473 474 ViewTree_LoadTree(hkeyChild, szKeyName, DWORD(-1)); 475 RegCloseKey(hkeyChild); 476 477 ++dwIndex; 478 } 479 480 RegCloseKey(hKey); 481 482 return TRUE; // success 483 } 484 485 static int ViewTree_Compare(const void *x, const void *y) 486 { 487 PVIEWTREE_ENTRY pEntry1 = (PVIEWTREE_ENTRY)x; 488 PVIEWTREE_ENTRY pEntry2 = (PVIEWTREE_ENTRY)y; 489 490 DWORD dwParentID1 = pEntry1->dwParentID; 491 DWORD dwParentID2 = pEntry2->dwParentID; 492 493 if (dwParentID1 == dwParentID2) 494 return lstrcmpi(pEntry1->szText, pEntry2->szText); 495 496 DWORD i, m, n; 497 const UINT MAX_DEPTH = 32; 498 PVIEWTREE_ENTRY pArray1[MAX_DEPTH]; 499 PVIEWTREE_ENTRY pArray2[MAX_DEPTH]; 500 501 // Make ancestor lists 502 for (i = m = n = 0; i < MAX_DEPTH; ++i) 503 { 504 PVIEWTREE_ENTRY pParent1 = ViewTree_GetItem(dwParentID1); 505 PVIEWTREE_ENTRY pParent2 = ViewTree_GetItem(dwParentID2); 506 if (!pParent1 && !pParent2) 507 break; 508 509 if (pParent1) 510 { 511 pArray1[m++] = pParent1; 512 dwParentID1 = pParent1->dwParentID; 513 } 514 if (pParent2) 515 { 516 pArray2[n++] = pParent2; 517 dwParentID2 = pParent2->dwParentID; 518 } 519 } 520 521 UINT k = min(m, n); 522 for (i = 0; i < k; ++i) 523 { 524 INT nCompare = lstrcmpi(pArray1[m - i - 1]->szText, pArray2[n - i - 1]->szText); 525 if (nCompare < 0) 526 return -1; 527 if (nCompare > 0) 528 return 1; 529 } 530 531 if (m < n) 532 return -1; 533 if (m > n) 534 return 1; 535 return lstrcmpi(pEntry1->szText, pEntry2->szText); 536 } 537 538 static VOID 539 ViewTree_SortAll(VOID) 540 { 541 qsort(s_ViewTreeEntries, s_ViewTreeEntryCount, sizeof(VIEWTREE_ENTRY), ViewTree_Compare); 542 } 543 544 ///////////////////////////////////////////////////////////////////////////// 545 // ViewDlg 546 547 static HIMAGELIST 548 ViewDlg_CreateTreeImageList(VOID) 549 { 550 HIMAGELIST hImageList; 551 hImageList = ImageList_Create(16, 16, ILC_COLOR24 | ILC_MASK, 9, 1); 552 if (hImageList == NULL) 553 return NULL; // failure 554 555 // free if existed 556 if (s_ViewTreeIcons) 557 { 558 free(s_ViewTreeIcons); 559 s_ViewTreeIcons = NULL; 560 } 561 s_ViewTreeIconCount = 0; 562 563 // allocate now 564 PVIEWTREE_ICON pAllocated; 565 size_t Size = PREDEFINED_ICON_COUNT * sizeof(VIEWTREE_ICON); 566 pAllocated = (PVIEWTREE_ICON)calloc(1, Size); 567 if (pAllocated == NULL) 568 return NULL; // failure 569 570 s_ViewTreeIconCount = PREDEFINED_ICON_COUNT; 571 s_ViewTreeIcons = pAllocated; 572 573 // add the predefined icons 574 575 HDC hDC = CreateCompatibleDC(NULL); 576 HBITMAP hbmMask = CreateCheckMask(hDC); 577 578 HBITMAP hbmChecked, hbmUnchecked; 579 580 hbmChecked = CreateCheckImage(hDC, TRUE); 581 ImageList_Add(hImageList, hbmChecked, hbmMask); 582 DeleteObject(hbmChecked); 583 584 hbmUnchecked = CreateCheckImage(hDC, FALSE); 585 ImageList_Add(hImageList, hbmUnchecked, hbmMask); 586 DeleteObject(hbmUnchecked); 587 588 hbmChecked = CreateCheckImage(hDC, TRUE, FALSE); 589 ImageList_Add(hImageList, hbmChecked, hbmMask); 590 DeleteObject(hbmChecked); 591 592 hbmUnchecked = CreateCheckImage(hDC, FALSE, FALSE); 593 ImageList_Add(hImageList, hbmUnchecked, hbmMask); 594 DeleteObject(hbmUnchecked); 595 596 DeleteObject(hbmMask); 597 hbmMask = CreateRadioMask(hDC); 598 599 hbmChecked = CreateRadioImage(hDC, TRUE); 600 ImageList_Add(hImageList, hbmChecked, hbmMask); 601 DeleteObject(hbmChecked); 602 603 hbmUnchecked = CreateRadioImage(hDC, FALSE); 604 ImageList_Add(hImageList, hbmUnchecked, hbmMask); 605 DeleteObject(hbmUnchecked); 606 607 hbmChecked = CreateRadioImage(hDC, TRUE, FALSE); 608 ImageList_Add(hImageList, hbmChecked, hbmMask); 609 DeleteObject(hbmChecked); 610 611 hbmUnchecked = CreateRadioImage(hDC, FALSE, FALSE); 612 ImageList_Add(hImageList, hbmUnchecked, hbmMask); 613 DeleteObject(hbmUnchecked); 614 615 DeleteObject(hbmMask); 616 617 return hImageList; 618 } 619 620 static BOOL 621 ViewDlg_OnInitDialog(HWND hwndDlg, LPPROPSHEETPAGE psp) 622 { 623 SetWindowLongPtr(hwndDlg, GWL_USERDATA, psp->lParam); 624 CFolderOptions *pFO = (CFolderOptions*)psp->lParam; 625 626 if (!pFO || !pFO->CanSetDefFolderSettings()) 627 { 628 // The global options (started from rundll32 or control panel) 629 // has no browser to copy the current settings from. 630 EnableWindow(GetDlgItem(hwndDlg, IDC_VIEW_APPLY_TO_ALL), FALSE); 631 } 632 633 HWND hwndTreeView = GetDlgItem(hwndDlg, IDC_VIEW_TREEVIEW); 634 635 s_hTreeImageList = ViewDlg_CreateTreeImageList(); 636 TreeView_SetImageList(hwndTreeView, s_hTreeImageList, TVSIL_NORMAL); 637 638 ViewTree_LoadAll(); 639 ViewTree_SortAll(); 640 ViewTree_InsertAll(hwndTreeView); 641 642 return TRUE; // set focus 643 } 644 645 static BOOL 646 ViewDlg_ToggleCheckItem(HWND hwndDlg, HTREEITEM hItem) 647 { 648 HWND hwndTreeView = GetDlgItem(hwndDlg, IDC_VIEW_TREEVIEW); 649 650 // get the item 651 TV_ITEM Item; 652 INT i; 653 ZeroMemory(&Item, sizeof(Item)); 654 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_PARAM; 655 Item.hItem = hItem; 656 if (!TreeView_GetItem(hwndTreeView, &Item)) 657 return FALSE; // no such item 658 659 VIEWTREE_ENTRY *pEntry = ViewTree_GetItem(Item.lParam); 660 if (pEntry == NULL) 661 return FALSE; // no such item 662 if (pEntry->bGrayed) 663 return FALSE; // disabled 664 665 // toggle check mark 666 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; 667 switch (pEntry->dwType) 668 { 669 case AETYPE_CHECKBOX: 670 pEntry->bChecked = !pEntry->bChecked; 671 break; 672 673 case AETYPE_RADIO: 674 // reset all the entries of the same parent 675 for (i = 0; i < s_ViewTreeEntryCount; ++i) 676 { 677 VIEWTREE_ENTRY *pEntry2 = &s_ViewTreeEntries[i]; 678 if (pEntry->dwParentID == pEntry2->dwParentID) 679 { 680 pEntry2->bChecked = FALSE; 681 682 Item.hItem = pEntry2->hItem; 683 INT iImage = ViewTree_GetImage(pEntry2); 684 Item.iImage = Item.iSelectedImage = iImage; 685 TreeView_SetItem(hwndTreeView, &Item); 686 } 687 } 688 pEntry->bChecked = TRUE; 689 break; 690 691 default: 692 return FALSE; // failure 693 } 694 Item.iImage = Item.iSelectedImage = ViewTree_GetImage(pEntry); 695 Item.hItem = hItem; 696 TreeView_SetItem(hwndTreeView, &Item); 697 698 // redraw the item 699 RECT rcItem; 700 TreeView_GetItemRect(hwndTreeView, hItem, &rcItem, FALSE); 701 InvalidateRect(hwndTreeView, &rcItem, TRUE); 702 return TRUE; // success 703 } 704 705 static VOID 706 ViewDlg_OnTreeViewClick(HWND hwndDlg) 707 { 708 HWND hwndTreeView = GetDlgItem(hwndDlg, IDC_VIEW_TREEVIEW); 709 710 // do hit test to get the clicked item 711 TV_HITTESTINFO HitTest; 712 ZeroMemory(&HitTest, sizeof(HitTest)); 713 DWORD dwPos = GetMessagePos(); 714 HitTest.pt.x = LOWORD(dwPos); 715 HitTest.pt.y = HIWORD(dwPos); 716 ScreenToClient(hwndTreeView, &HitTest.pt); 717 HTREEITEM hItem = TreeView_HitTest(hwndTreeView, &HitTest); 718 719 // toggle the check mark if possible 720 if (ViewDlg_ToggleCheckItem(hwndDlg, hItem)) 721 { 722 // property sheet was changed 723 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 724 } 725 } 726 727 static void 728 ViewDlg_OnTreeViewKeyDown(HWND hwndDlg, TV_KEYDOWN *KeyDown) 729 { 730 HWND hwndTreeView = GetDlgItem(hwndDlg, IDC_VIEW_TREEVIEW); 731 732 if (KeyDown->wVKey == VK_SPACE) 733 { 734 // [Space] key was pressed 735 HTREEITEM hItem = TreeView_GetSelection(hwndTreeView); 736 if (ViewDlg_ToggleCheckItem(hwndDlg, hItem)) 737 { 738 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 739 } 740 } 741 } 742 743 static INT_PTR 744 ViewDlg_OnTreeCustomDraw(HWND hwndDlg, NMTVCUSTOMDRAW *Draw) 745 { 746 NMCUSTOMDRAW& nmcd = Draw->nmcd; 747 switch (nmcd.dwDrawStage) 748 { 749 case CDDS_PREPAINT: 750 return CDRF_NOTIFYITEMDRAW; // for CDDS_ITEMPREPAINT 751 752 case CDDS_ITEMPREPAINT: 753 if (!(nmcd.uItemState & CDIS_SELECTED)) // not selected 754 { 755 LPARAM lParam = nmcd.lItemlParam; 756 VIEWTREE_ENTRY *pEntry = ViewTree_GetItem(lParam); 757 if (pEntry && pEntry->bGrayed) // disabled 758 { 759 // draw as grayed 760 Draw->clrText = GetSysColor(COLOR_GRAYTEXT); 761 Draw->clrTextBk = GetSysColor(COLOR_WINDOW); 762 return CDRF_NEWFONT; 763 } 764 } 765 break; 766 767 default: 768 break; 769 } 770 return CDRF_DODEFAULT; 771 } 772 773 static VOID 774 ViewDlg_RestoreDefaults(HWND hwndDlg) 775 { 776 HWND hwndTreeView = GetDlgItem(hwndDlg, IDC_VIEW_TREEVIEW); 777 778 for (INT i = 0; i < s_ViewTreeEntryCount; ++i) 779 { 780 // ignore if the type is group 781 VIEWTREE_ENTRY *pEntry = &s_ViewTreeEntries[i]; 782 if (pEntry->dwType == AETYPE_GROUP) 783 continue; 784 785 // set default value on registry 786 HKEY hKey; 787 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 788 0, KEY_WRITE, &hKey) != ERROR_SUCCESS) 789 { 790 continue; 791 } 792 RegSetValueExW(hKey, pEntry->szValueName, 0, REG_DWORD, 793 LPBYTE(&pEntry->dwDefaultValue), sizeof(DWORD)); 794 RegCloseKey(hKey); 795 796 // update check status 797 pEntry->bChecked = (pEntry->dwCheckedValue == pEntry->dwDefaultValue); 798 799 // update the image 800 TV_ITEM Item; 801 ZeroMemory(&Item, sizeof(Item)); 802 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; 803 Item.hItem = pEntry->hItem; 804 Item.iImage = Item.iSelectedImage = ViewTree_GetImage(pEntry); 805 TreeView_SetItem(hwndTreeView, &Item); 806 } 807 808 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 809 } 810 811 static VOID 812 ScanAdvancedSettings(SHELLSTATE *pSS, DWORD *pdwMask) 813 { 814 for (INT i = 0; i < s_ViewTreeEntryCount; ++i) 815 { 816 const VIEWTREE_ENTRY *pEntry = &s_ViewTreeEntries[i]; 817 if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed) 818 continue; 819 820 BOOL bChecked = pEntry->bChecked; 821 822 // FIXME: Add more items 823 if (lstrcmpiW(pEntry->szKeyName, L"SuperHidden") == 0) 824 { 825 pSS->fShowSuperHidden = !bChecked ? 1 : 0; 826 *pdwMask |= SSF_SHOWSUPERHIDDEN; 827 continue; 828 } 829 if (lstrcmpiW(pEntry->szKeyName, L"DesktopProcess") == 0) 830 { 831 pSS->fSepProcess = bChecked ? 1 : 0; 832 *pdwMask |= SSF_SEPPROCESS; 833 continue; 834 } 835 if (lstrcmpiW(pEntry->szKeyName, L"SHOWALL") == 0) 836 { 837 pSS->fShowAllObjects = !bChecked ? 1 : 0; 838 *pdwMask |= SSF_SHOWALLOBJECTS; 839 continue; 840 } 841 if (lstrcmpiW(pEntry->szKeyName, L"HideFileExt") == 0) 842 { 843 pSS->fShowExtensions = !bChecked ? 1 : 0; 844 *pdwMask |= SSF_SHOWEXTENSIONS; 845 continue; 846 } 847 if (lstrcmpiW(pEntry->szKeyName, L"ShowCompColor") == 0) 848 { 849 pSS->fShowCompColor = bChecked ? 1 : 0; 850 *pdwMask |= SSF_SHOWCOMPCOLOR; 851 continue; 852 } 853 if (lstrcmpiW(pEntry->szKeyName, L"ShowInfoTip") == 0) 854 { 855 pSS->fShowInfoTip = bChecked ? 1 : 0; 856 *pdwMask |= SSF_SHOWINFOTIP; 857 continue; 858 } 859 } 860 } 861 862 static BOOL CALLBACK 863 RefreshBrowsersCallback(HWND hWnd, LPARAM msg) 864 { 865 WCHAR ClassName[100]; 866 if (GetClassNameW(hWnd, ClassName, _countof(ClassName))) 867 { 868 if (!wcscmp(ClassName, L"Progman") || 869 !wcscmp(ClassName, L"CabinetWClass") || 870 !wcscmp(ClassName, L"ExploreWClass")) 871 { 872 PostMessage(hWnd, WM_COMMAND, FCIDM_DESKBROWSER_REFRESH, 0); 873 } 874 } 875 return TRUE; 876 } 877 878 static VOID 879 ViewDlg_Apply(HWND hwndDlg) 880 { 881 for (INT i = 0; i < s_ViewTreeEntryCount; ++i) 882 { 883 // ignore the entry if the type is group or the entry is grayed 884 VIEWTREE_ENTRY *pEntry = &s_ViewTreeEntries[i]; 885 if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed) 886 continue; 887 888 // open the registry key 889 HKEY hkeyTarget; 890 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0, 891 KEY_WRITE, &hkeyTarget) != ERROR_SUCCESS) 892 { 893 continue; 894 } 895 896 // checked or unchecked? 897 DWORD dwValue, dwSize; 898 if (pEntry->bChecked) 899 { 900 dwValue = pEntry->dwCheckedValue; 901 } 902 else 903 { 904 if (pEntry->bHasUncheckedValue) 905 { 906 dwValue = pEntry->dwUncheckedValue; 907 } 908 else 909 { 910 // there is no unchecked value 911 RegCloseKey(hkeyTarget); 912 continue; // ignore 913 } 914 } 915 916 // set the value 917 dwSize = sizeof(dwValue); 918 RegSetValueExW(hkeyTarget, pEntry->szValueName, 0, REG_DWORD, 919 LPBYTE(&dwValue), dwSize); 920 921 // close now 922 RegCloseKey(hkeyTarget); 923 } 924 925 // scan advanced settings for user's settings 926 DWORD dwMask = 0; 927 SHELLSTATE ShellState; 928 ZeroMemory(&ShellState, sizeof(ShellState)); 929 ScanAdvancedSettings(&ShellState, &dwMask); 930 931 // update user's settings 932 SHGetSetSettings(&ShellState, dwMask, TRUE); 933 934 // notify all 935 SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0); 936 937 EnumWindows(RefreshBrowsersCallback, NULL); 938 } 939 940 // IDD_FOLDER_OPTIONS_VIEW 941 INT_PTR CALLBACK 942 FolderOptionsViewDlg( 943 HWND hwndDlg, 944 UINT uMsg, 945 WPARAM wParam, 946 LPARAM lParam) 947 { 948 INT_PTR Result; 949 NMTVCUSTOMDRAW *Draw; 950 951 switch (uMsg) 952 { 953 case WM_INITDIALOG: 954 return ViewDlg_OnInitDialog(hwndDlg, (LPPROPSHEETPAGE)lParam); 955 956 case WM_COMMAND: 957 switch (LOWORD(wParam)) 958 { 959 case IDC_VIEW_RESTORE_DEFAULTS: // Restore Defaults 960 ViewDlg_RestoreDefaults(hwndDlg); 961 break; 962 963 case IDC_VIEW_APPLY_TO_ALL: 964 case IDC_VIEW_RESET_ALL: 965 { 966 HRESULT hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); 967 CFolderOptions *pFO = (CFolderOptions*)GetWindowLongPtr(hwndDlg, GWL_USERDATA); 968 if (pFO) 969 hr = pFO->ApplyDefFolderSettings(LOWORD(wParam) == IDC_VIEW_RESET_ALL); 970 if (FAILED(hr)) 971 SHELL_ErrorBox(hwndDlg, hr); 972 break; 973 } 974 } 975 break; 976 977 case WM_NOTIFY: 978 switch (LPNMHDR(lParam)->code) 979 { 980 case NM_CLICK: // clicked on treeview 981 ViewDlg_OnTreeViewClick(hwndDlg); 982 break; 983 984 case NM_CUSTOMDRAW: // custom draw (for graying) 985 Draw = (NMTVCUSTOMDRAW *)lParam; 986 Result = ViewDlg_OnTreeCustomDraw(hwndDlg, Draw); 987 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, Result); 988 return Result; 989 990 case TVN_KEYDOWN: // key is down 991 ViewDlg_OnTreeViewKeyDown(hwndDlg, (TV_KEYDOWN *)lParam); 992 break; 993 994 case PSN_APPLY: // [Apply] is clicked 995 ViewDlg_Apply(hwndDlg); 996 break; 997 998 default: 999 break; 1000 } 1001 break; 1002 } 1003 1004 return FALSE; 1005 } 1006