Regedit fix and enhancement
[reactos.git] / reactos / subsys / system / 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */
22 #include <windows.h>
23 #include <commctrl.h>
24 #include <tchar.h>
25 #include <stdio.h>
26
27 #include "main.h"
28 #include "regproc.h"
29
30 ChildWnd* g_pChildWnd;
31 HBITMAP SizingPattern = 0;
32 HBRUSH SizingBrush = 0;
33 static TCHAR Suggestions[256];
34
35 /*******************************************************************************
36 * Local module support methods
37 */
38
39 static LPCTSTR get_root_key_name(HKEY hRootKey)
40 {
41 if (hRootKey == HKEY_CLASSES_ROOT) return _T("HKEY_CLASSES_ROOT");
42 if (hRootKey == HKEY_CURRENT_USER) return _T("HKEY_CURRENT_USER");
43 if (hRootKey == HKEY_LOCAL_MACHINE) return _T("HKEY_LOCAL_MACHINE");
44 if (hRootKey == HKEY_USERS) return _T("HKEY_USERS");
45 if (hRootKey == HKEY_CURRENT_CONFIG) return _T("HKEY_CURRENT_CONFIG");
46 if (hRootKey == HKEY_DYN_DATA) return _T("HKEY_DYN_DATA");
47 return _T("UKNOWN HKEY, PLEASE REPORT");
48 }
49
50 static void draw_splitbar(HWND hWnd, int x)
51 {
52 RECT rt;
53 HGDIOBJ OldObj;
54 HDC hdc = GetDC(hWnd);
55
56 if(!SizingPattern)
57 {
58 const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
59 SizingPattern = CreateBitmap(8, 8, 1, 1, Pattern);
60 }
61 if(!SizingBrush)
62 {
63 SizingBrush = CreatePatternBrush(SizingPattern);
64 }
65 GetClientRect(hWnd, &rt);
66 rt.left = x - SPLIT_WIDTH/2;
67 rt.right = x + SPLIT_WIDTH/2+1;
68 OldObj = SelectObject(hdc, SizingBrush);
69 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
70 SelectObject(hdc, OldObj);
71 ReleaseDC(hWnd, hdc);
72 }
73
74 static void ResizeWnd(ChildWnd* pChildWnd, int cx, int cy)
75 {
76 HDWP hdwp = BeginDeferWindowPos(2);
77 RECT rt = {0, 0, cx, cy};
78
79 cx = pChildWnd->nSplitPos + SPLIT_WIDTH/2;
80 DeferWindowPos(hdwp, pChildWnd->hTreeWnd, 0, rt.left, rt.top, pChildWnd->nSplitPos-SPLIT_WIDTH/2-rt.left, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
81 DeferWindowPos(hdwp, pChildWnd->hListWnd, 0, rt.left+cx , rt.top, rt.right-cx, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
82 EndDeferWindowPos(hdwp);
83 }
84
85 static void OnPaint(HWND hWnd)
86 {
87 PAINTSTRUCT ps;
88 RECT rt;
89 HDC hdc;
90
91 GetClientRect(hWnd, &rt);
92 hdc = BeginPaint(hWnd, &ps);
93 FillRect(ps.hdc, &rt, GetSysColorBrush(COLOR_BTNFACE));
94 EndPaint(hWnd, &ps);
95 }
96
97 /*******************************************************************************
98 *
99 * FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG)
100 *
101 * PURPOSE: Processes WM_COMMAND messages for the main frame window.
102 *
103 */
104
105 static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
106 {
107 ChildWnd* pChildWnd = g_pChildWnd;
108 HTREEITEM hSelection;
109 HKEY hRootKey;
110 LPCTSTR keyPath, s;
111 TCHAR szConfirmTitle[256];
112 TCHAR szConfirmText[256];
113 WORD wID = LOWORD(wParam);
114
115 switch (wID) {
116 /* Parse the menu selections: */
117 case ID_REGISTRY_EXIT:
118 DestroyWindow(hWnd);
119 break;
120 case ID_VIEW_REFRESH:
121 /* TODO */
122 break;
123 case ID_TREE_EXPANDBRANCH:
124 TreeView_Expand(pChildWnd->hTreeWnd, TreeView_GetSelection(pChildWnd->hTreeWnd), TVE_EXPAND);
125 break;
126 case ID_TREE_COLLAPSEBRANCH:
127 TreeView_Expand(pChildWnd->hTreeWnd, TreeView_GetSelection(pChildWnd->hTreeWnd), TVE_COLLAPSE);
128 break;
129 case ID_TREE_RENAME:
130 SetFocus(pChildWnd->hTreeWnd);
131 TreeView_EditLabel(pChildWnd->hTreeWnd, TreeView_GetSelection(pChildWnd->hTreeWnd));
132 break;
133 case ID_TREE_DELETE:
134 hSelection = TreeView_GetSelection(pChildWnd->hTreeWnd);
135 keyPath = GetItemPath(pChildWnd->hTreeWnd, hSelection, &hRootKey);
136
137 LoadString(hInst, IDS_QUERY_DELETE_KEY_CONFIRM, szConfirmTitle, sizeof(szConfirmTitle) / sizeof(szConfirmTitle[0]));
138 LoadString(hInst, IDS_QUERY_DELETE_KEY_ONE, szConfirmText, sizeof(szConfirmText) / sizeof(szConfirmText[0]));
139
140 if (MessageBox(pChildWnd->hWnd, szConfirmText, szConfirmTitle, MB_YESNO) == IDYES)
141 {
142 if (RegDeleteKeyRecursive(hRootKey, keyPath) == ERROR_SUCCESS)
143 TreeView_DeleteItem(pChildWnd->hTreeWnd, hSelection);
144 }
145 break;
146 case ID_EDIT_COPYKEYNAME:
147 hSelection = TreeView_GetSelection(pChildWnd->hTreeWnd);
148 keyPath = GetItemPath(pChildWnd->hTreeWnd, hSelection, &hRootKey);
149 CopyKeyName(hWnd, hRootKey, keyPath);
150 break;
151 case ID_EDIT_NEW_KEY:
152 CreateNewKey(pChildWnd->hTreeWnd, TreeView_GetSelection(pChildWnd->hTreeWnd));
153 break;
154 case ID_EDIT_NEW_STRINGVALUE:
155 case ID_EDIT_NEW_BINARYVALUE:
156 case ID_EDIT_NEW_DWORDVALUE:
157 SendMessage(hFrameWnd, WM_COMMAND, wParam, lParam);
158 break;
159 case ID_SWITCH_PANELS:
160 pChildWnd->nFocusPanel = !pChildWnd->nFocusPanel;
161 SetFocus(pChildWnd->nFocusPanel? pChildWnd->hListWnd: pChildWnd->hTreeWnd);
162 break;
163 default:
164 if ((wID >= ID_TREE_SUGGESTION_MIN) && (wID <= ID_TREE_SUGGESTION_MAX))
165 {
166 s = Suggestions;
167 while(wID > ID_TREE_SUGGESTION_MIN)
168 {
169 if (*s)
170 s += _tcslen(s) + 1;
171 wID--;
172 }
173 SelectNode(pChildWnd->hTreeWnd, s);
174 break;
175 }
176 return FALSE;
177 }
178 return TRUE;
179 }
180
181 /*******************************************************************************
182 *
183 * Key suggestion
184 */
185
186 #define MIN(a,b) ((a < b) ? (a) : (b))
187
188 static void SuggestKeys(HKEY hRootKey, LPCTSTR pszKeyPath, LPTSTR pszSuggestions,
189 size_t iSuggestionsLength)
190 {
191 TCHAR szBuffer[256];
192 TCHAR szLastFound[256];
193 size_t i;
194 HKEY hOtherKey, hSubKey;
195 BOOL bFound;
196
197 memset(pszSuggestions, 0, iSuggestionsLength * sizeof(*pszSuggestions));
198 iSuggestionsLength--;
199
200 /* Are we a root key in HKEY_CLASSES_ROOT? */
201 if ((hRootKey == HKEY_CLASSES_ROOT) && pszKeyPath[0] && !_tcschr(pszKeyPath, '\\'))
202 {
203 do
204 {
205 bFound = FALSE;
206
207 /* Check default key */
208 if (RegQueryStringValue(hRootKey, pszKeyPath, NULL,
209 szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0])) == ERROR_SUCCESS)
210 {
211 /* Sanity check this key; it cannot be empty, nor can it be a
212 * loop back */
213 if ((szBuffer[0] != '\0') && _tcsicmp(szBuffer, pszKeyPath))
214 {
215 if (RegOpenKey(hRootKey, szBuffer, &hOtherKey) == ERROR_SUCCESS)
216 {
217 lstrcpyn(pszSuggestions, TEXT("HKCR\\"), iSuggestionsLength);
218 i = _tcslen(pszSuggestions);
219 pszSuggestions += i;
220 iSuggestionsLength -= i;
221
222 lstrcpyn(pszSuggestions, szBuffer, iSuggestionsLength);
223 i = MIN(_tcslen(pszSuggestions) + 1, iSuggestionsLength);
224 pszSuggestions += i;
225 iSuggestionsLength -= i;
226 RegCloseKey(hOtherKey);
227
228 bFound = TRUE;
229 _tcscpy(szLastFound, szBuffer);
230 pszKeyPath = szLastFound;
231 }
232 }
233 }
234 }
235 while(bFound && (iSuggestionsLength > 0));
236
237 /* Check CLSID key */
238 if (RegOpenKey(hRootKey, pszKeyPath, &hSubKey) == ERROR_SUCCESS)
239 {
240 if (RegQueryStringValue(hSubKey, TEXT("CLSID"), NULL,
241 szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0])) == ERROR_SUCCESS)
242 {
243 lstrcpyn(pszSuggestions, TEXT("HKCR\\CLSID\\"), iSuggestionsLength);
244 i = _tcslen(pszSuggestions);
245 pszSuggestions += i;
246 iSuggestionsLength -= i;
247
248 lstrcpyn(pszSuggestions, szBuffer, iSuggestionsLength);
249 i = MIN(_tcslen(pszSuggestions) + 1, iSuggestionsLength);
250 pszSuggestions += i;
251 iSuggestionsLength -= i;
252 }
253 RegCloseKey(hSubKey);
254 }
255 }
256 }
257
258 /*******************************************************************************
259 *
260 * FUNCTION: ChildWndProc(HWND, unsigned, WORD, LONG)
261 *
262 * PURPOSE: Processes messages for the child windows.
263 *
264 * WM_COMMAND - process the application menu
265 * WM_PAINT - Paint the main window
266 * WM_DESTROY - post a quit message and return
267 *
268 */
269 LRESULT CALLBACK ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
270 {
271 static short last_split;
272 BOOL Result;
273 ChildWnd* pChildWnd = g_pChildWnd;
274
275 switch (message) {
276 case WM_CREATE:
277 {
278 TCHAR buffer[MAX_PATH];
279 /* load "My Computer" string */
280 LoadString(hInst, IDS_MY_COMPUTER, buffer, sizeof(buffer)/sizeof(TCHAR));
281
282 g_pChildWnd = pChildWnd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ChildWnd));
283
284 if (!pChildWnd) return 0;
285 _tcsncpy(pChildWnd->szPath, buffer, MAX_PATH);
286 pChildWnd->nSplitPos = 250;
287 pChildWnd->hWnd = hWnd;
288 pChildWnd->hTreeWnd = CreateTreeView(hWnd, pChildWnd->szPath, TREE_WINDOW);
289 pChildWnd->hListWnd = CreateListView(hWnd, LIST_WINDOW/*, pChildWnd->szPath*/);
290 SetFocus(pChildWnd->hTreeWnd);
291 break;
292 }
293 case WM_COMMAND:
294 if (!_CmdWndProc(hWnd, message, wParam, lParam)) {
295 goto def;
296 }
297 break;
298 case WM_PAINT:
299 OnPaint(hWnd);
300 return 0;
301 case WM_SETCURSOR:
302 if (LOWORD(lParam) == HTCLIENT) {
303 POINT pt;
304 GetCursorPos(&pt);
305 ScreenToClient(hWnd, &pt);
306 if (pt.x>=pChildWnd->nSplitPos-SPLIT_WIDTH/2 && pt.x<pChildWnd->nSplitPos+SPLIT_WIDTH/2+1) {
307 SetCursor(LoadCursor(0, IDC_SIZEWE));
308 return TRUE;
309 }
310 }
311 goto def;
312 case WM_DESTROY:
313 HeapFree(GetProcessHeap(), 0, pChildWnd);
314 pChildWnd = NULL;
315 PostQuitMessage(0);
316 break;
317 case WM_LBUTTONDOWN: {
318 RECT rt;
319 POINTS pt;
320 pt = MAKEPOINTS(lParam);
321 GetClientRect(hWnd, &rt);
322 if (pt.x>=pChildWnd->nSplitPos-SPLIT_WIDTH/2 && pt.x<pChildWnd->nSplitPos+SPLIT_WIDTH/2+1) {
323 last_split = pChildWnd->nSplitPos;
324 draw_splitbar(hWnd, last_split);
325 SetCapture(hWnd);
326 }
327 break;
328 }
329
330 case WM_LBUTTONUP:
331 if (GetCapture() == hWnd) {
332 RECT rt;
333 POINTS pt;
334 pt = MAKEPOINTS(lParam);
335 GetClientRect(hWnd, &rt);
336 pt.x = (SHORT) min(max(pt.x, SPLIT_MIN), rt.right - SPLIT_MIN);
337 draw_splitbar(hWnd, last_split);
338 last_split = -1;
339 pChildWnd->nSplitPos = pt.x;
340 ResizeWnd(pChildWnd, rt.right, rt.bottom);
341 ReleaseCapture();
342 }
343 break;
344
345 case WM_CAPTURECHANGED:
346 if (GetCapture()==hWnd && last_split>=0)
347 draw_splitbar(hWnd, last_split);
348 break;
349
350 case WM_KEYDOWN:
351 if (wParam == VK_ESCAPE)
352 if (GetCapture() == hWnd) {
353 RECT rt;
354 draw_splitbar(hWnd, last_split);
355 GetClientRect(hWnd, &rt);
356 ResizeWnd(pChildWnd, rt.right, rt.bottom);
357 last_split = -1;
358 ReleaseCapture();
359 SetCursor(LoadCursor(0, IDC_ARROW));
360 }
361 break;
362
363 case WM_MOUSEMOVE:
364 if (GetCapture() == hWnd) {
365 HDC hdc;
366 RECT rt;
367 HGDIOBJ OldObj;
368 POINTS pt;
369 if(!SizingPattern)
370 {
371 const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
372 SizingPattern = CreateBitmap(8, 8, 1, 1, Pattern);
373 }
374 if(!SizingBrush)
375 {
376 SizingBrush = CreatePatternBrush(SizingPattern);
377 }
378
379 pt = MAKEPOINTS(lParam);
380 GetClientRect(hWnd, &rt);
381 pt.x = (SHORT) min(max(pt.x, SPLIT_MIN), rt.right - SPLIT_MIN);
382 if(last_split != pt.x)
383 {
384 rt.left = last_split-SPLIT_WIDTH/2;
385 rt.right = last_split+SPLIT_WIDTH/2+1;
386 hdc = GetDC(hWnd);
387 OldObj = SelectObject(hdc, SizingBrush);
388 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
389 last_split = pt.x;
390 rt.left = pt.x-SPLIT_WIDTH/2;
391 rt.right = pt.x+SPLIT_WIDTH/2+1;
392 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, PATINVERT);
393 SelectObject(hdc, OldObj);
394 ReleaseDC(hWnd, hdc);
395 }
396 }
397 break;
398
399 case WM_SETFOCUS:
400 if (pChildWnd != NULL) {
401 SetFocus(pChildWnd->nFocusPanel? pChildWnd->hListWnd: pChildWnd->hTreeWnd);
402 }
403 break;
404
405 case WM_TIMER:
406 break;
407
408 case WM_NOTIFY:
409 if ((int)wParam == TREE_WINDOW) {
410 switch (((LPNMHDR)lParam)->code) {
411 case TVN_ITEMEXPANDING:
412 return !OnTreeExpanding(pChildWnd->hTreeWnd, (NMTREEVIEW*)lParam);
413 case TVN_SELCHANGED: {
414 LPCTSTR keyPath, rootName;
415 LPTSTR fullPath;
416 HKEY hRootKey;
417
418 keyPath = GetItemPath(pChildWnd->hTreeWnd, ((NMTREEVIEW*)lParam)->itemNew.hItem, &hRootKey);
419 if (keyPath) {
420 RefreshListView(pChildWnd->hListWnd, hRootKey, keyPath);
421 rootName = get_root_key_name(hRootKey);
422 fullPath = HeapAlloc(GetProcessHeap(), 0, (_tcslen(rootName) + 1 + _tcslen(keyPath) + 1) * sizeof(TCHAR));
423 if (fullPath) {
424 _stprintf(fullPath, _T("%s\\%s"), rootName, keyPath);
425 SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)fullPath);
426 HeapFree(GetProcessHeap(), 0, fullPath);
427
428 {
429 HKEY hKey;
430 TCHAR szBuffer[MAX_PATH];
431 _sntprintf(szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), _T("My Computer\\%s\\%s"), rootName, keyPath);
432
433 if (RegOpenKey(HKEY_CURRENT_USER,
434 _T("Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit"),
435 &hKey) == ERROR_SUCCESS)
436 {
437 RegSetValueEx(hKey, _T("LastKey"), 0, REG_SZ, (LPBYTE) szBuffer, _tcslen(szBuffer) * sizeof(szBuffer[0]));
438 RegCloseKey(hKey);
439 }
440 }
441 }
442 }
443 }
444 break;
445 case NM_SETFOCUS:
446 pChildWnd->nFocusPanel = 0;
447 break;
448 case TVN_ENDLABELEDIT:
449 {
450 LPCTSTR keyPath;
451 HKEY hRootKey;
452 LPNMTVDISPINFO ptvdi;
453 LONG lResult;
454
455 ptvdi = (LPNMTVDISPINFO) lParam;
456 if (ptvdi->item.pszText)
457 {
458 keyPath = GetItemPath(pChildWnd->hTreeWnd, ptvdi->item.hItem, &hRootKey);
459 lResult = RegRenameKey(hRootKey, keyPath, ptvdi->item.pszText);
460 return lResult == ERROR_SUCCESS;
461 }
462 }
463 default:
464 return 0;
465 }
466 } else
467 {
468 if ((int)wParam == LIST_WINDOW)
469 {
470 switch (((LPNMHDR)lParam)->code) {
471 case NM_SETFOCUS:
472 pChildWnd->nFocusPanel = 1;
473 break;
474 default:
475 if(!ListWndNotifyProc(pChildWnd->hListWnd, wParam, lParam, &Result))
476 {
477 goto def;
478 }
479 return Result;
480 break;
481 }
482 }
483 }
484 break;
485
486 case WM_CONTEXTMENU:
487 {
488 POINTS pt;
489 if((HWND)wParam == pChildWnd->hListWnd)
490 {
491 int i, cnt;
492 BOOL IsDefault;
493 pt = MAKEPOINTS(lParam);
494 cnt = ListView_GetSelectedCount(pChildWnd->hListWnd);
495 i = ListView_GetNextItem(pChildWnd->hListWnd, -1, LVNI_FOCUSED | LVNI_SELECTED);
496 if(i == -1)
497 {
498 TrackPopupMenu(GetSubMenu(hPopupMenus, PM_NEW), TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL);
499 }
500 else
501 {
502 HMENU mnu = GetSubMenu(hPopupMenus, PM_MODIFYVALUE);
503 SetMenuDefaultItem(mnu, ID_EDIT_MODIFY, MF_BYCOMMAND);
504 IsDefault = IsDefaultValue(pChildWnd->hListWnd, i);
505 if(cnt == 1)
506 EnableMenuItem(mnu, ID_EDIT_RENAME, MF_BYCOMMAND | (IsDefault ? MF_DISABLED | MF_GRAYED : MF_ENABLED));
507 else
508 EnableMenuItem(mnu, ID_EDIT_RENAME, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
509 EnableMenuItem(mnu, ID_EDIT_MODIFY, MF_BYCOMMAND | (cnt == 1 ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
510 EnableMenuItem(mnu, ID_EDIT_MODIFY_BIN, MF_BYCOMMAND | (cnt == 1 ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
511
512 TrackPopupMenu(mnu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL);
513 }
514 }
515 else if ((HWND)wParam == pChildWnd->hTreeWnd)
516 {
517 TVHITTESTINFO hti;
518 HMENU hContextMenu;
519 TVITEM item;
520 MENUITEMINFO mii;
521 TCHAR resource[256];
522 TCHAR buffer[256];
523 LPTSTR s;
524 LPCTSTR keyPath;
525 HKEY hRootKey;
526 int iLastPos;
527 WORD wID;
528
529 pt = MAKEPOINTS(lParam);
530 hti.pt.x = pt.x;
531 hti.pt.y = pt.y;
532 ScreenToClient(pChildWnd->hTreeWnd, &hti.pt);
533 TreeView_HitTest(pChildWnd->hTreeWnd, &hti);
534
535 if ((hti.flags & TVHT_ONITEM) != 0)
536 {
537 hContextMenu = GetSubMenu(hPopupMenus, PM_TREECONTEXT);
538 TreeView_SelectItem(pChildWnd->hTreeWnd, hti.hItem);
539
540 memset(&item, 0, sizeof(item));
541 item.mask = TVIF_STATE | TVIF_CHILDREN;
542 item.hItem = hti.hItem;
543 TreeView_GetItem(pChildWnd->hTreeWnd, &item);
544
545 /* Set the Expand/Collapse menu item appropriately */
546 LoadString(hInst, (item.state & TVIS_EXPANDED) ? IDS_COLLAPSE : IDS_EXPAND, buffer, sizeof(buffer) / sizeof(buffer[0]));
547 memset(&mii, 0, sizeof(mii));
548 mii.cbSize = sizeof(mii);
549 mii.fMask = MIIM_STRING | MIIM_STATE | MIIM_ID;
550 mii.fState = (item.cChildren > 0) ? MFS_DEFAULT : MFS_GRAYED;
551 mii.wID = (item.state & TVIS_EXPANDED) ? ID_TREE_COLLAPSEBRANCH : ID_TREE_EXPANDBRANCH;
552 mii.dwTypeData = (LPTSTR) buffer;
553 SetMenuItemInfo(hContextMenu, 0, TRUE, &mii);
554
555 /* Remove any existing suggestions */
556 memset(&mii, 0, sizeof(mii));
557 mii.cbSize = sizeof(mii);
558 mii.fMask = MIIM_ID;
559 GetMenuItemInfo(hContextMenu, GetMenuItemCount(hContextMenu) - 1, TRUE, &mii);
560 if ((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX))
561 {
562 do
563 {
564 iLastPos = GetMenuItemCount(hContextMenu) - 1;
565 GetMenuItemInfo(hContextMenu, iLastPos, TRUE, &mii);
566 RemoveMenu(hContextMenu, iLastPos, MF_BYPOSITION);
567 }
568 while((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX));
569 }
570
571 /* Come up with suggestions */
572 keyPath = GetItemPath(pChildWnd->hTreeWnd, NULL, &hRootKey);
573 SuggestKeys(hRootKey, keyPath, Suggestions, sizeof(Suggestions) / sizeof(Suggestions[0]));
574 if (Suggestions[0])
575 {
576 AppendMenu(hContextMenu, MF_SEPARATOR, 0, NULL);
577
578 LoadString(hInst, IDS_GOTO_SUGGESTED_KEY, resource, sizeof(resource) / sizeof(resource[0]));
579
580 s = Suggestions;
581 wID = ID_TREE_SUGGESTION_MIN;
582 while(*s && (wID <= ID_TREE_SUGGESTION_MAX))
583 {
584 _sntprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), resource, s);
585
586 memset(&mii, 0, sizeof(mii));
587 mii.cbSize = sizeof(mii);
588 mii.fMask = MIIM_STRING | MIIM_ID;
589 mii.wID = wID++;
590 mii.dwTypeData = buffer;
591 InsertMenuItem(hContextMenu, GetMenuItemCount(hContextMenu), TRUE, &mii);
592
593 s += _tcslen(s) + 1;
594 }
595 }
596
597 TrackPopupMenu(hContextMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, pChildWnd->hWnd, NULL);
598 }
599 }
600 break;
601 }
602
603 case WM_SIZE:
604 if (wParam != SIZE_MINIMIZED && pChildWnd != NULL) {
605 ResizeWnd(pChildWnd, LOWORD(lParam), HIWORD(lParam));
606 }
607 /* fall through */
608 default: def:
609 return DefWindowProc(hWnd, message, wParam, lParam);
610 }
611 return 0;
612 }