[REGEDIT] Code formatting
[reactos.git] / base / applications / regedit / childwnd.c
1 /*
2 * Regedit child window
3 *
4 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "regedit.h"
22
23 ChildWnd* g_pChildWnd;
24 static int last_split;
25 HBITMAP SizingPattern = 0;
26 HBRUSH SizingBrush = 0;
27 static WCHAR Suggestions[256];
28
29 extern LPCWSTR get_root_key_name(HKEY hRootKey)
30 {
31 if (hRootKey == HKEY_CLASSES_ROOT) return L"HKEY_CLASSES_ROOT";
32 if (hRootKey == HKEY_CURRENT_USER) return L"HKEY_CURRENT_USER";
33 if (hRootKey == HKEY_LOCAL_MACHINE) return L"HKEY_LOCAL_MACHINE";
34 if (hRootKey == HKEY_USERS) return L"HKEY_USERS";
35 if (hRootKey == HKEY_CURRENT_CONFIG) return L"HKEY_CURRENT_CONFIG";
36 if (hRootKey == HKEY_DYN_DATA) return L"HKEY_DYN_DATA";
37
38 return L"UNKNOWN HKEY, PLEASE REPORT";
39 }
40
41 extern void ResizeWnd(int cx, int cy)
42 {
43 HDWP hdwp = BeginDeferWindowPos(4);
44 RECT rt, rs, rb;
45 const int tHeight = 22;
46 const UINT uFlags = SWP_NOZORDER | SWP_NOACTIVATE;
47 SetRect(&rt, 0, 0, cx, cy);
48 cy = 0;
49 if (hStatusBar != NULL)
50 {
51 GetWindowRect(hStatusBar, &rs);
52 cy = rs.bottom - rs.top;
53 }
54 GetWindowRect(g_pChildWnd->hAddressBtnWnd, &rb);
55 cx = g_pChildWnd->nSplitPos + SPLIT_WIDTH / 2;
56 if (hdwp)
57 hdwp = DeferWindowPos(hdwp, g_pChildWnd->hAddressBarWnd, NULL,
58 rt.left, rt.top,
59 rt.right - rt.left - 2*tHeight, tHeight,
60 uFlags);
61 if (hdwp)
62 hdwp = DeferWindowPos(hdwp, g_pChildWnd->hAddressBtnWnd, NULL,
63 rt.right - 2*tHeight, rt.top,
64 2*tHeight, tHeight,
65 uFlags);
66 if (hdwp)
67 hdwp = DeferWindowPos(hdwp, g_pChildWnd->hTreeWnd, NULL,
68 rt.left, rt.top + tHeight + 2,
69 g_pChildWnd->nSplitPos - SPLIT_WIDTH/2 - rt.left, rt.bottom - rt.top - cy,
70 uFlags);
71 if (hdwp)
72 hdwp = DeferWindowPos(hdwp, g_pChildWnd->hListWnd, NULL,
73 rt.left + cx, rt.top + tHeight + 2,
74 rt.right - cx, rt.bottom - rt.top - cy,
75 uFlags);
76 if (hdwp)
77 EndDeferWindowPos(hdwp);
78 }
79
80 /*******************************************************************************
81 * Local module support methods
82 */
83
84 static void draw_splitbar(HWND hWnd, int x)
85 {
86 RECT rt;
87 HGDIOBJ OldObj;
88 HDC hdc = GetDC(hWnd);
89
90 if(!SizingPattern)
91 {
92 const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
93 SizingPattern = CreateBitmap(8, 8, 1, 1, Pattern);
94 }
95 if(!SizingBrush)
96 {
97 SizingBrush = CreatePatternBrush(SizingPattern);
98 }
99 GetClientRect(hWnd, &rt);
100 rt.left = x - SPLIT_WIDTH/2;
101 rt.right = x + SPLIT_WIDTH/2+1;
102 OldObj = SelectObject(hdc, SizingBrush);
103 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
104 SelectObject(hdc, OldObj);
105 ReleaseDC(hWnd, hdc);
106 }
107
108 static void OnPaint(HWND hWnd)
109 {
110 PAINTSTRUCT ps;
111 RECT rt;
112
113 GetClientRect(hWnd, &rt);
114 BeginPaint(hWnd, &ps);
115 FillRect(ps.hdc, &rt, GetSysColorBrush(COLOR_BTNFACE));
116 EndPaint(hWnd, &ps);
117 }
118
119 /*******************************************************************************
120 * finish_splitbar [internal]
121 *
122 * make the splitbar invisible and resize the windows
123 * (helper for ChildWndProc)
124 */
125 static void finish_splitbar(HWND hWnd, int x)
126 {
127 RECT rt;
128
129 draw_splitbar(hWnd, last_split);
130 last_split = -1;
131 GetClientRect(hWnd, &rt);
132 g_pChildWnd->nSplitPos = x;
133 ResizeWnd(rt.right, rt.bottom);
134 ReleaseCapture();
135 }
136
137 /*******************************************************************************
138 *
139 * FUNCTION: ChildWnd_CmdWndProc(HWND, unsigned, WORD, LONG)
140 *
141 * PURPOSE: Processes WM_COMMAND messages for the main frame window.
142 *
143 */
144
145 static BOOL ChildWnd_CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
146 {
147 HTREEITEM hSelection;
148 HKEY hRootKey;
149 LPCWSTR keyPath, s;
150 WORD wID = LOWORD(wParam);
151
152 UNREFERENCED_PARAMETER(message);
153
154 switch (wID)
155 {
156 /* Parse the menu selections: */
157 case ID_REGISTRY_EXIT:
158 DestroyWindow(hWnd);
159 break;
160 case ID_VIEW_REFRESH:
161 /* TODO */
162 break;
163 case ID_TREE_EXPANDBRANCH:
164 TreeView_Expand(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd), TVE_EXPAND);
165 break;
166 case ID_TREE_COLLAPSEBRANCH:
167 TreeView_Expand(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd), TVE_COLLAPSE);
168 break;
169 case ID_TREE_RENAME:
170 SetFocus(g_pChildWnd->hTreeWnd);
171 TreeView_EditLabel(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd));
172 break;
173 case ID_TREE_DELETE:
174 hSelection = TreeView_GetSelection(g_pChildWnd->hTreeWnd);
175 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, hSelection, &hRootKey);
176
177 if (keyPath == 0 || *keyPath == 0)
178 {
179 MessageBeep(MB_ICONHAND);
180 }
181 else if (DeleteKey(hWnd, hRootKey, keyPath))
182 DeleteNode(g_pChildWnd->hTreeWnd, 0);
183 break;
184 case ID_TREE_EXPORT:
185 ExportRegistryFile(g_pChildWnd->hTreeWnd);
186 break;
187 case ID_EDIT_FIND:
188 FindDialog(hWnd);
189 break;
190 case ID_EDIT_COPYKEYNAME:
191 hSelection = TreeView_GetSelection(g_pChildWnd->hTreeWnd);
192 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, hSelection, &hRootKey);
193 CopyKeyName(hWnd, hRootKey, keyPath);
194 break;
195 case ID_EDIT_NEW_KEY:
196 CreateNewKey(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd));
197 break;
198 case ID_EDIT_NEW_STRINGVALUE:
199 case ID_EDIT_NEW_BINARYVALUE:
200 case ID_EDIT_NEW_DWORDVALUE:
201 SendMessageW(hFrameWnd, WM_COMMAND, wParam, lParam);
202 break;
203 case ID_SWITCH_PANELS:
204 g_pChildWnd->nFocusPanel = !g_pChildWnd->nFocusPanel;
205 SetFocus(g_pChildWnd->nFocusPanel? g_pChildWnd->hListWnd: g_pChildWnd->hTreeWnd);
206 break;
207 default:
208 if ((wID >= ID_TREE_SUGGESTION_MIN) && (wID <= ID_TREE_SUGGESTION_MAX))
209 {
210 s = Suggestions;
211 while(wID > ID_TREE_SUGGESTION_MIN)
212 {
213 if (*s)
214 s += wcslen(s) + 1;
215 wID--;
216 }
217 SelectNode(g_pChildWnd->hTreeWnd, s);
218 break;
219 }
220 return FALSE;
221 }
222 return TRUE;
223 }
224
225 /*******************************************************************************
226 *
227 * Key suggestion
228 */
229
230 #define MIN(a,b) ((a < b) ? (a) : (b))
231
232 static void SuggestKeys(HKEY hRootKey, LPCWSTR pszKeyPath, LPWSTR pszSuggestions,
233 size_t iSuggestionsLength)
234 {
235 WCHAR szBuffer[256];
236 WCHAR szLastFound[256];
237 size_t i;
238 HKEY hOtherKey, hSubKey;
239 BOOL bFound;
240
241 memset(pszSuggestions, 0, iSuggestionsLength * sizeof(*pszSuggestions));
242 iSuggestionsLength--;
243
244 /* Are we a root key in HKEY_CLASSES_ROOT? */
245 if ((hRootKey == HKEY_CLASSES_ROOT) && pszKeyPath[0] && !wcschr(pszKeyPath, L'\\'))
246 {
247 do
248 {
249 bFound = FALSE;
250
251 /* Check default key */
252 if (QueryStringValue(hRootKey, pszKeyPath, NULL,
253 szBuffer, COUNT_OF(szBuffer)) == ERROR_SUCCESS)
254 {
255 /* Sanity check this key; it cannot be empty, nor can it be a
256 * loop back */
257 if ((szBuffer[0] != L'\0') && _wcsicmp(szBuffer, pszKeyPath))
258 {
259 if (RegOpenKeyW(hRootKey, szBuffer, &hOtherKey) == ERROR_SUCCESS)
260 {
261 lstrcpynW(pszSuggestions, L"HKCR\\", (int) iSuggestionsLength);
262 i = wcslen(pszSuggestions);
263 pszSuggestions += i;
264 iSuggestionsLength -= i;
265
266 lstrcpynW(pszSuggestions, szBuffer, (int) iSuggestionsLength);
267 i = MIN(wcslen(pszSuggestions) + 1, iSuggestionsLength);
268 pszSuggestions += i;
269 iSuggestionsLength -= i;
270 RegCloseKey(hOtherKey);
271
272 bFound = TRUE;
273 wcscpy(szLastFound, szBuffer);
274 pszKeyPath = szLastFound;
275 }
276 }
277 }
278 }
279 while(bFound && (iSuggestionsLength > 0));
280
281 /* Check CLSID key */
282 if (RegOpenKeyW(hRootKey, pszKeyPath, &hSubKey) == ERROR_SUCCESS)
283 {
284 if (QueryStringValue(hSubKey, L"CLSID", NULL, szBuffer,
285 COUNT_OF(szBuffer)) == ERROR_SUCCESS)
286 {
287 lstrcpynW(pszSuggestions, L"HKCR\\CLSID\\", (int)iSuggestionsLength);
288 i = wcslen(pszSuggestions);
289 pszSuggestions += i;
290 iSuggestionsLength -= i;
291
292 lstrcpynW(pszSuggestions, szBuffer, (int)iSuggestionsLength);
293 i = MIN(wcslen(pszSuggestions) + 1, iSuggestionsLength);
294 pszSuggestions += i;
295 iSuggestionsLength -= i;
296 }
297 RegCloseKey(hSubKey);
298 }
299 }
300 }
301
302
303 LRESULT CALLBACK AddressBarProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
304 {
305 WNDPROC oldwndproc;
306 static WCHAR s_szNode[256];
307 oldwndproc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA);
308
309 switch (uMsg)
310 {
311 case WM_KEYUP:
312 if (wParam == VK_RETURN)
313 {
314 GetWindowTextW(hwnd, s_szNode, COUNT_OF(s_szNode));
315 SelectNode(g_pChildWnd->hTreeWnd, s_szNode);
316 }
317 break;
318 default:
319 break;
320 }
321 return CallWindowProcW(oldwndproc, hwnd, uMsg, wParam, lParam);
322 }
323
324 static VOID
325 UpdateAddress(HTREEITEM hItem, HKEY hRootKey, LPCWSTR pszPath)
326 {
327 LPCWSTR keyPath, rootName;
328 LPWSTR fullPath;
329
330 /* Wipe the listview, the status bar and the address bar if the root key was selected */
331 if (TreeView_GetParent(g_pChildWnd->hTreeWnd, hItem) == NULL)
332 {
333 ListView_DeleteAllItems(g_pChildWnd->hListWnd);
334 SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)NULL);
335 SendMessageW(g_pChildWnd->hAddressBarWnd, WM_SETTEXT, 0, (LPARAM)NULL);
336 return;
337 }
338
339 if (pszPath == NULL)
340 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, hItem, &hRootKey);
341 else
342 keyPath = pszPath;
343
344 if (keyPath)
345 {
346 RefreshListView(g_pChildWnd->hListWnd, hRootKey, keyPath);
347 rootName = get_root_key_name(hRootKey);
348 fullPath = HeapAlloc(GetProcessHeap(), 0, (wcslen(rootName) + 1 + wcslen(keyPath) + 1) * sizeof(WCHAR));
349 if (fullPath)
350 {
351 /* set (correct) the address bar text */
352 if (keyPath[0] != L'\0')
353 swprintf(fullPath, L"%s\\%s", rootName, keyPath);
354 else
355 fullPath = wcscpy(fullPath, rootName);
356 SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)fullPath);
357 SendMessageW(g_pChildWnd->hAddressBarWnd, WM_SETTEXT, 0, (LPARAM)fullPath);
358 HeapFree(GetProcessHeap(), 0, fullPath);
359 /* disable hive manipulation items temporarily (enable only if necessary) */
360 EnableMenuItem(GetSubMenu(hMenuFrame,0), ID_REGISTRY_LOADHIVE, MF_BYCOMMAND | MF_GRAYED);
361 EnableMenuItem(GetSubMenu(hMenuFrame,0), ID_REGISTRY_UNLOADHIVE, MF_BYCOMMAND | MF_GRAYED);
362 /* compare the strings to see if we should enable/disable the "Load Hive" menus accordingly */
363 if (!(_wcsicmp(rootName, L"HKEY_LOCAL_MACHINE") &&
364 _wcsicmp(rootName, L"HKEY_USERS")))
365 {
366 /*
367 * enable the unload menu item if at the root, otherwise
368 * enable the load menu item if there is no slash in
369 * keyPath (ie. immediate child selected)
370 */
371 if(keyPath[0] == L'\0')
372 EnableMenuItem(GetSubMenu(hMenuFrame,0), ID_REGISTRY_LOADHIVE, MF_BYCOMMAND | MF_ENABLED);
373 else if(!wcschr(keyPath, L'\\'))
374 EnableMenuItem(GetSubMenu(hMenuFrame,0), ID_REGISTRY_UNLOADHIVE, MF_BYCOMMAND | MF_ENABLED);
375 }
376 }
377 }
378 }
379
380 /*******************************************************************************
381 *
382 * FUNCTION: ChildWndProc(HWND, unsigned, WORD, LONG)
383 *
384 * PURPOSE: Processes messages for the child windows.
385 *
386 * WM_COMMAND - process the application menu
387 * WM_PAINT - Paint the main window
388 * WM_DESTROY - post a quit message and return
389 *
390 */
391 LRESULT CALLBACK ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
392 {
393 BOOL Result;
394
395 switch (message)
396 {
397 case WM_CREATE:
398 {
399 WNDPROC oldproc;
400 HFONT hFont;
401 WCHAR buffer[MAX_PATH];
402
403 /* Load "My Computer" string */
404 LoadStringW(hInst, IDS_MY_COMPUTER, buffer, COUNT_OF(buffer));
405
406 g_pChildWnd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ChildWnd));
407 if (!g_pChildWnd) return 0;
408
409 wcsncpy(g_pChildWnd->szPath, buffer, MAX_PATH);
410 g_pChildWnd->nSplitPos = 250;
411 g_pChildWnd->hWnd = hWnd;
412 g_pChildWnd->hAddressBarWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL, WS_CHILD | WS_VISIBLE | WS_CHILDWINDOW | WS_TABSTOP,
413 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
414 hWnd, (HMENU)0, hInst, 0);
415 g_pChildWnd->hAddressBtnWnd = CreateWindowExW(0, L"Button", L"\x00BB", WS_CHILD | WS_VISIBLE | WS_CHILDWINDOW | WS_TABSTOP | BS_TEXT | BS_CENTER | BS_VCENTER | BS_FLAT | BS_DEFPUSHBUTTON,
416 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
417 hWnd, (HMENU)0, hInst, 0);
418 g_pChildWnd->hTreeWnd = CreateTreeView(hWnd, g_pChildWnd->szPath, (HMENU) TREE_WINDOW);
419 g_pChildWnd->hListWnd = CreateListView(hWnd, (HMENU) LIST_WINDOW/*, g_pChildWnd->szPath*/);
420 SetFocus(g_pChildWnd->hTreeWnd);
421
422 /* set the address bar and button font */
423 if ((g_pChildWnd->hAddressBarWnd) && (g_pChildWnd->hAddressBtnWnd))
424 {
425 hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
426 SendMessageW(g_pChildWnd->hAddressBarWnd,
427 WM_SETFONT,
428 (WPARAM)hFont,
429 0);
430 SendMessageW(g_pChildWnd->hAddressBtnWnd,
431 WM_SETFONT,
432 (WPARAM)hFont,
433 0);
434 }
435 /* Subclass the AddressBar */
436 oldproc = (WNDPROC)GetWindowLongPtr(g_pChildWnd->hAddressBarWnd, GWLP_WNDPROC);
437 SetWindowLongPtr(g_pChildWnd->hAddressBarWnd, GWLP_USERDATA, (DWORD_PTR)oldproc);
438 SetWindowLongPtr(g_pChildWnd->hAddressBarWnd, GWLP_WNDPROC, (DWORD_PTR)AddressBarProc);
439 break;
440 }
441 case WM_COMMAND:
442 if(HIWORD(wParam) == BN_CLICKED)
443 {
444 PostMessageW(g_pChildWnd->hAddressBarWnd, WM_KEYUP, VK_RETURN, 0);
445 }
446
447 if (!ChildWnd_CmdWndProc(hWnd, message, wParam, lParam))
448 {
449 goto def;
450 }
451 break;
452 case WM_PAINT:
453 OnPaint(hWnd);
454 return 0;
455 case WM_SETCURSOR:
456 if (LOWORD(lParam) == HTCLIENT)
457 {
458 POINT pt;
459 GetCursorPos(&pt);
460 ScreenToClient(hWnd, &pt);
461 if (pt.x>=g_pChildWnd->nSplitPos-SPLIT_WIDTH/2 && pt.x<g_pChildWnd->nSplitPos+SPLIT_WIDTH/2+1)
462 {
463 SetCursor(LoadCursorW(0, IDC_SIZEWE));
464 return TRUE;
465 }
466 }
467 goto def;
468 case WM_DESTROY:
469 DestroyListView(g_pChildWnd->hListWnd);
470 DestroyTreeView(g_pChildWnd->hTreeWnd);
471 DestroyMainMenu();
472 HeapFree(GetProcessHeap(), 0, g_pChildWnd);
473 g_pChildWnd = NULL;
474 PostQuitMessage(0);
475 break;
476 case WM_LBUTTONDOWN:
477 {
478 RECT rt;
479 int x = (short)LOWORD(lParam);
480 GetClientRect(hWnd, &rt);
481 if (x>=g_pChildWnd->nSplitPos-SPLIT_WIDTH/2 && x<g_pChildWnd->nSplitPos+SPLIT_WIDTH/2+1)
482 {
483 last_split = g_pChildWnd->nSplitPos;
484 draw_splitbar(hWnd, last_split);
485 SetCapture(hWnd);
486 }
487 break;
488 }
489
490 case WM_LBUTTONUP:
491 case WM_RBUTTONDOWN:
492 if (GetCapture() == hWnd)
493 {
494 finish_splitbar(hWnd, LOWORD(lParam));
495 }
496 break;
497
498 case WM_CAPTURECHANGED:
499 if (GetCapture()==hWnd && last_split>=0)
500 draw_splitbar(hWnd, last_split);
501 break;
502
503 case WM_KEYDOWN:
504 if (wParam == VK_ESCAPE)
505 if (GetCapture() == hWnd)
506 {
507 RECT rt;
508 draw_splitbar(hWnd, last_split);
509 GetClientRect(hWnd, &rt);
510 ResizeWnd(rt.right, rt.bottom);
511 last_split = -1;
512 ReleaseCapture();
513 SetCursor(LoadCursorW(0, IDC_ARROW));
514 }
515 break;
516
517 case WM_MOUSEMOVE:
518 if (GetCapture() == hWnd)
519 {
520 HDC hdc;
521 RECT rt;
522 HGDIOBJ OldObj;
523 int x = LOWORD(lParam);
524 if(!SizingPattern)
525 {
526 const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
527 SizingPattern = CreateBitmap(8, 8, 1, 1, Pattern);
528 }
529 if(!SizingBrush)
530 {
531 SizingBrush = CreatePatternBrush(SizingPattern);
532 }
533
534 GetClientRect(hWnd, &rt);
535 x = (SHORT) min(max(x, SPLIT_MIN), rt.right - SPLIT_MIN);
536 if(last_split != x)
537 {
538 rt.left = last_split-SPLIT_WIDTH/2;
539 rt.right = last_split+SPLIT_WIDTH/2+1;
540 hdc = GetDC(hWnd);
541 OldObj = SelectObject(hdc, SizingBrush);
542 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
543 last_split = x;
544 rt.left = x-SPLIT_WIDTH/2;
545 rt.right = x+SPLIT_WIDTH/2+1;
546 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
547 SelectObject(hdc, OldObj);
548 ReleaseDC(hWnd, hdc);
549 }
550 }
551 break;
552
553 case WM_SETFOCUS:
554 if (g_pChildWnd != NULL)
555 {
556 SetFocus(g_pChildWnd->nFocusPanel? g_pChildWnd->hListWnd: g_pChildWnd->hTreeWnd);
557 }
558 break;
559
560 case WM_TIMER:
561 break;
562
563 case WM_NOTIFY:
564 if ((int)wParam == TREE_WINDOW && g_pChildWnd != NULL)
565 {
566 switch (((LPNMHDR)lParam)->code)
567 {
568 case TVN_ITEMEXPANDING:
569 return !OnTreeExpanding(g_pChildWnd->hTreeWnd, (NMTREEVIEW*)lParam);
570 case TVN_SELCHANGED:
571 {
572 NMTREEVIEW* pnmtv = (NMTREEVIEW*)lParam;
573 /* Get the parent of the current item */
574 HTREEITEM hParentItem = TreeView_GetParent(g_pChildWnd->hTreeWnd, pnmtv->itemNew.hItem);
575
576 UpdateAddress(pnmtv->itemNew.hItem, NULL, NULL);
577
578 /*
579 * Disable Delete/Rename menu options for 'My Computer' (first item so doesn't have any parent)
580 * and HKEY_* keys (their parent is 'My Computer' and the previous remark applies).
581 */
582 if (!hParentItem || !TreeView_GetParent(g_pChildWnd->hTreeWnd, hParentItem))
583 {
584 EnableMenuItem(hMenuFrame , ID_EDIT_DELETE, MF_BYCOMMAND | MF_GRAYED);
585 EnableMenuItem(hMenuFrame , ID_EDIT_RENAME, MF_BYCOMMAND | MF_GRAYED);
586 EnableMenuItem(hPopupMenus, ID_TREE_DELETE, MF_BYCOMMAND | MF_GRAYED);
587 EnableMenuItem(hPopupMenus, ID_TREE_RENAME, MF_BYCOMMAND | MF_GRAYED);
588 }
589 else
590 {
591 EnableMenuItem(hMenuFrame , ID_EDIT_DELETE, MF_BYCOMMAND | MF_ENABLED);
592 EnableMenuItem(hMenuFrame , ID_EDIT_RENAME, MF_BYCOMMAND | MF_ENABLED);
593 EnableMenuItem(hPopupMenus, ID_TREE_DELETE, MF_BYCOMMAND | MF_ENABLED);
594 EnableMenuItem(hPopupMenus, ID_TREE_RENAME, MF_BYCOMMAND | MF_ENABLED);
595 }
596
597 break;
598 }
599 case NM_SETFOCUS:
600 g_pChildWnd->nFocusPanel = 0;
601 break;
602 case TVN_BEGINLABELEDIT:
603 {
604 LPNMTVDISPINFO ptvdi;
605 /* cancel label edit for rootkeys */
606 ptvdi = (LPNMTVDISPINFO) lParam;
607 if (!TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem) ||
608 !TreeView_GetParent(g_pChildWnd->hTreeWnd, TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem)))
609 return TRUE;
610 break;
611 }
612 case TVN_ENDLABELEDIT:
613 {
614 LPCWSTR keyPath;
615 HKEY hRootKey;
616 HKEY hKey = NULL;
617 LPNMTVDISPINFO ptvdi;
618 LONG lResult = TRUE;
619 WCHAR szBuffer[MAX_PATH];
620
621 ptvdi = (LPNMTVDISPINFO) lParam;
622 if (ptvdi->item.pszText)
623 {
624 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem), &hRootKey);
625 _snwprintf(szBuffer, COUNT_OF(szBuffer), L"%s\\%s", keyPath, ptvdi->item.pszText);
626 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, ptvdi->item.hItem, &hRootKey);
627 if (RegOpenKeyExW(hRootKey, szBuffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
628 {
629 lResult = FALSE;
630 RegCloseKey(hKey);
631 TreeView_EditLabel(g_pChildWnd->hTreeWnd, ptvdi->item.hItem);
632 }
633 else
634 {
635 if (RenameKey(hRootKey, keyPath, ptvdi->item.pszText) != ERROR_SUCCESS)
636 lResult = FALSE;
637 else
638 UpdateAddress(ptvdi->item.hItem, hRootKey, szBuffer);
639 }
640 return lResult;
641 }
642 }
643 default:
644 return 0;
645 }
646 }
647 else
648 {
649 if ((int)wParam == LIST_WINDOW && g_pChildWnd != NULL)
650 {
651 switch (((LPNMHDR)lParam)->code)
652 {
653 case NM_SETFOCUS:
654 g_pChildWnd->nFocusPanel = 1;
655 break;
656 default:
657 if(!ListWndNotifyProc(g_pChildWnd->hListWnd, wParam, lParam, &Result))
658 {
659 goto def;
660 }
661 return Result;
662 break;
663 }
664 }
665 }
666 break;
667
668 case WM_CONTEXTMENU:
669 {
670 POINT pt;
671 if((HWND)wParam == g_pChildWnd->hListWnd)
672 {
673 int i, cnt;
674 BOOL IsDefault;
675 pt.x = (short) LOWORD(lParam);
676 pt.y = (short) HIWORD(lParam);
677 cnt = ListView_GetSelectedCount(g_pChildWnd->hListWnd);
678 i = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_FOCUSED | LVNI_SELECTED);
679 if (pt.x == -1 && pt.y == -1)
680 {
681 RECT rc;
682 if (i != -1)
683 {
684 rc.left = LVIR_BOUNDS;
685 SendMessageW(g_pChildWnd->hListWnd, LVM_GETITEMRECT, i, (LPARAM) &rc);
686 pt.x = rc.left + 8;
687 pt.y = rc.top + 8;
688 }
689 else
690 pt.x = pt.y = 0;
691 ClientToScreen(g_pChildWnd->hListWnd, &pt);
692 }
693 if(i == -1)
694 {
695 TrackPopupMenu(GetSubMenu(hPopupMenus, PM_NEW), TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL);
696 }
697 else
698 {
699 HMENU mnu = GetSubMenu(hPopupMenus, PM_MODIFYVALUE);
700 SetMenuDefaultItem(mnu, ID_EDIT_MODIFY, MF_BYCOMMAND);
701 IsDefault = IsDefaultValue(g_pChildWnd->hListWnd, i);
702 if(cnt == 1)
703 EnableMenuItem(mnu, ID_EDIT_RENAME, MF_BYCOMMAND | (IsDefault ? MF_DISABLED | MF_GRAYED : MF_ENABLED));
704 else
705 EnableMenuItem(mnu, ID_EDIT_RENAME, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
706 EnableMenuItem(mnu, ID_EDIT_MODIFY, MF_BYCOMMAND | (cnt == 1 ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
707 EnableMenuItem(mnu, ID_EDIT_MODIFY_BIN, MF_BYCOMMAND | (cnt == 1 ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
708
709 TrackPopupMenu(mnu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL);
710 }
711 }
712 else if ((HWND)wParam == g_pChildWnd->hTreeWnd)
713 {
714 TVHITTESTINFO hti;
715 HMENU hContextMenu;
716 TVITEMW item;
717 MENUITEMINFOW mii;
718 WCHAR resource[256];
719 WCHAR buffer[256];
720 LPWSTR s;
721 LPCWSTR keyPath;
722 HKEY hRootKey;
723 int iLastPos;
724 WORD wID;
725
726 pt.x = (short) LOWORD(lParam);
727 pt.y = (short) HIWORD(lParam);
728
729 if (pt.x == -1 && pt.y == -1)
730 {
731 RECT rc;
732 hti.hItem = TreeView_GetSelection(g_pChildWnd->hTreeWnd);
733 if (hti.hItem != NULL)
734 {
735 TreeView_GetItemRect(g_pChildWnd->hTreeWnd, hti.hItem, &rc, TRUE);
736 pt.x = rc.left + 8;
737 pt.y = rc.top + 8;
738 ClientToScreen(g_pChildWnd->hTreeWnd, &pt);
739 hti.flags = TVHT_ONITEM;
740 }
741 else
742 hti.flags = 0;
743 }
744 else
745 {
746 hti.pt.x = pt.x;
747 hti.pt.y = pt.y;
748 ScreenToClient(g_pChildWnd->hTreeWnd, &hti.pt);
749 TreeView_HitTest(g_pChildWnd->hTreeWnd, &hti);
750 }
751
752 if (hti.flags & TVHT_ONITEM)
753 {
754 hContextMenu = GetSubMenu(hPopupMenus, PM_TREECONTEXT);
755 TreeView_SelectItem(g_pChildWnd->hTreeWnd, hti.hItem);
756
757 memset(&item, 0, sizeof(item));
758 item.mask = TVIF_STATE | TVIF_CHILDREN;
759 item.hItem = hti.hItem;
760 TreeView_GetItem(g_pChildWnd->hTreeWnd, &item);
761
762 /* Set the Expand/Collapse menu item appropriately */
763 LoadStringW(hInst, (item.state & TVIS_EXPANDED) ? IDS_COLLAPSE : IDS_EXPAND, buffer, COUNT_OF(buffer));
764 memset(&mii, 0, sizeof(mii));
765 mii.cbSize = sizeof(mii);
766 mii.fMask = MIIM_STRING | MIIM_STATE | MIIM_ID;
767 mii.fState = (item.cChildren > 0) ? MFS_DEFAULT : MFS_GRAYED;
768 mii.wID = (item.state & TVIS_EXPANDED) ? ID_TREE_COLLAPSEBRANCH : ID_TREE_EXPANDBRANCH;
769 mii.dwTypeData = (LPWSTR) buffer;
770 SetMenuItemInfo(hContextMenu, 0, TRUE, &mii);
771
772 /* Remove any existing suggestions */
773 memset(&mii, 0, sizeof(mii));
774 mii.cbSize = sizeof(mii);
775 mii.fMask = MIIM_ID;
776 GetMenuItemInfo(hContextMenu, GetMenuItemCount(hContextMenu) - 1, TRUE, &mii);
777 if ((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX))
778 {
779 do
780 {
781 iLastPos = GetMenuItemCount(hContextMenu) - 1;
782 GetMenuItemInfo(hContextMenu, iLastPos, TRUE, &mii);
783 RemoveMenu(hContextMenu, iLastPos, MF_BYPOSITION);
784 }
785 while((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX));
786 }
787
788 /* Come up with suggestions */
789 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, NULL, &hRootKey);
790 SuggestKeys(hRootKey, keyPath, Suggestions, COUNT_OF(Suggestions));
791 if (Suggestions[0])
792 {
793 AppendMenu(hContextMenu, MF_SEPARATOR, 0, NULL);
794
795 LoadStringW(hInst, IDS_GOTO_SUGGESTED_KEY, resource, COUNT_OF(resource));
796
797 s = Suggestions;
798 wID = ID_TREE_SUGGESTION_MIN;
799 while(*s && (wID <= ID_TREE_SUGGESTION_MAX))
800 {
801 _snwprintf(buffer, COUNT_OF(buffer), resource, s);
802
803 memset(&mii, 0, sizeof(mii));
804 mii.cbSize = sizeof(mii);
805 mii.fMask = MIIM_STRING | MIIM_ID;
806 mii.wID = wID++;
807 mii.dwTypeData = buffer;
808 InsertMenuItem(hContextMenu, GetMenuItemCount(hContextMenu), TRUE, &mii);
809
810 s += wcslen(s) + 1;
811 }
812 }
813 TrackPopupMenu(hContextMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, g_pChildWnd->hWnd, NULL);
814 }
815 }
816 break;
817 }
818
819 case WM_SIZE:
820 if (wParam != SIZE_MINIMIZED && g_pChildWnd != NULL)
821 {
822 ResizeWnd(LOWORD(lParam), HIWORD(lParam));
823 }
824 /* fall through */
825 default:
826 def:
827 return DefWindowProcW(hWnd, message, wParam, lParam);
828 }
829 return 0;
830 }