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
ViewTree_FindIcon(LPCWSTR pszPath,UINT nIconIndex)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
ViewTree_AddIcon(LPCWSTR pszPath,UINT nIconIndex)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
ViewTree_GetItem(DWORD dwID)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
ViewTree_GetImage(PVIEWTREE_ENTRY pEntry)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
ViewTree_InsertEntry(HWND hwndTreeView,PVIEWTREE_ENTRY pEntry)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
ViewTree_InsertAll(HWND hwndTreeView)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
ViewTree_LoadTree(HKEY hKey,LPCWSTR pszKeyName,DWORD dwParentID)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
ViewTree_LoadAll(VOID)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
ViewTree_Compare(const void * x,const void * y)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
ViewTree_SortAll(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
ViewDlg_CreateTreeImageList(VOID)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
ViewDlg_OnInitDialog(HWND hwndDlg,LPPROPSHEETPAGE psp)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
ViewDlg_ToggleCheckItem(HWND hwndDlg,HTREEITEM hItem)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
ViewDlg_OnTreeViewClick(HWND hwndDlg)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
ViewDlg_OnTreeViewKeyDown(HWND hwndDlg,TV_KEYDOWN * KeyDown)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
ViewDlg_OnTreeCustomDraw(HWND hwndDlg,NMTVCUSTOMDRAW * Draw)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
ViewDlg_RestoreDefaults(HWND hwndDlg)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
ScanAdvancedSettings(SHELLSTATE * pSS,DWORD * pdwMask)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
PostCabinetMessageCallback(HWND hWnd,LPARAM param)863 PostCabinetMessageCallback(HWND hWnd, LPARAM param)
864 {
865 MSG &data = *(MSG*)param;
866 WCHAR ClassName[100];
867 if (GetClassNameW(hWnd, ClassName, _countof(ClassName)))
868 {
869 if (!wcscmp(ClassName, L"Progman") ||
870 !wcscmp(ClassName, L"CabinetWClass") ||
871 !wcscmp(ClassName, L"ExploreWClass"))
872 {
873 PostMessage(hWnd, data.message, data.wParam, data.lParam);
874 }
875 }
876 return TRUE;
877 }
878
879 void
PostCabinetMessage(UINT Msg,WPARAM wParam,LPARAM lParam)880 PostCabinetMessage(UINT Msg, WPARAM wParam, LPARAM lParam)
881 {
882 MSG data;
883 data.message = Msg;
884 data.wParam = wParam;
885 data.lParam = lParam;
886 EnumWindows(PostCabinetMessageCallback, (LPARAM)&data);
887 }
888
889 static VOID
ViewDlg_Apply(HWND hwndDlg)890 ViewDlg_Apply(HWND hwndDlg)
891 {
892 for (INT i = 0; i < s_ViewTreeEntryCount; ++i)
893 {
894 // ignore the entry if the type is group or the entry is grayed
895 VIEWTREE_ENTRY *pEntry = &s_ViewTreeEntries[i];
896 if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed)
897 continue;
898
899 // open the registry key
900 HKEY hkeyTarget;
901 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0,
902 KEY_WRITE, &hkeyTarget) != ERROR_SUCCESS)
903 {
904 continue;
905 }
906
907 // checked or unchecked?
908 DWORD dwValue, dwSize;
909 if (pEntry->bChecked)
910 {
911 dwValue = pEntry->dwCheckedValue;
912 }
913 else
914 {
915 if (pEntry->bHasUncheckedValue)
916 {
917 dwValue = pEntry->dwUncheckedValue;
918 }
919 else
920 {
921 // there is no unchecked value
922 RegCloseKey(hkeyTarget);
923 continue; // ignore
924 }
925 }
926
927 // set the value
928 dwSize = sizeof(dwValue);
929 RegSetValueExW(hkeyTarget, pEntry->szValueName, 0, REG_DWORD,
930 LPBYTE(&dwValue), dwSize);
931
932 // close now
933 RegCloseKey(hkeyTarget);
934 }
935
936 // scan advanced settings for user's settings
937 DWORD dwMask = 0;
938 SHELLSTATE ShellState;
939 ZeroMemory(&ShellState, sizeof(ShellState));
940 ScanAdvancedSettings(&ShellState, &dwMask);
941
942 // update user's settings
943 SHGetSetSettings(&ShellState, dwMask, TRUE);
944
945 // notify all
946 SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0);
947
948 PostCabinetMessage(WM_COMMAND, FCIDM_DESKBROWSER_REFRESH, 0);
949 }
950
951 // IDD_FOLDER_OPTIONS_VIEW
952 INT_PTR CALLBACK
FolderOptionsViewDlg(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)953 FolderOptionsViewDlg(
954 HWND hwndDlg,
955 UINT uMsg,
956 WPARAM wParam,
957 LPARAM lParam)
958 {
959 INT_PTR Result;
960 NMTVCUSTOMDRAW *Draw;
961
962 switch (uMsg)
963 {
964 case WM_INITDIALOG:
965 return ViewDlg_OnInitDialog(hwndDlg, (LPPROPSHEETPAGE)lParam);
966
967 case WM_COMMAND:
968 switch (LOWORD(wParam))
969 {
970 case IDC_VIEW_RESTORE_DEFAULTS: // Restore Defaults
971 ViewDlg_RestoreDefaults(hwndDlg);
972 break;
973
974 case IDC_VIEW_APPLY_TO_ALL:
975 case IDC_VIEW_RESET_ALL:
976 {
977 HRESULT hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
978 CFolderOptions *pFO = (CFolderOptions*)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
979 if (pFO)
980 hr = pFO->ApplyDefFolderSettings(LOWORD(wParam) == IDC_VIEW_RESET_ALL);
981 if (FAILED(hr))
982 SHELL_ErrorBox(hwndDlg, hr);
983 break;
984 }
985 }
986 break;
987
988 case WM_NOTIFY:
989 switch (LPNMHDR(lParam)->code)
990 {
991 case NM_CLICK: // clicked on treeview
992 ViewDlg_OnTreeViewClick(hwndDlg);
993 break;
994
995 case NM_CUSTOMDRAW: // custom draw (for graying)
996 Draw = (NMTVCUSTOMDRAW *)lParam;
997 Result = ViewDlg_OnTreeCustomDraw(hwndDlg, Draw);
998 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, Result);
999 return Result;
1000
1001 case TVN_KEYDOWN: // key is down
1002 ViewDlg_OnTreeViewKeyDown(hwndDlg, (TV_KEYDOWN *)lParam);
1003 break;
1004
1005 case PSN_APPLY: // [Apply] is clicked
1006 ViewDlg_Apply(hwndDlg);
1007 break;
1008
1009 default:
1010 break;
1011 }
1012 break;
1013 }
1014
1015 return FALSE;
1016 }
1017