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