| /* |
| * Regedit child window |
| * |
| * Copyright (C) 2002 Robert Dickenson <robd@reactos.org> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */ |
| #include <windows.h> |
| #include <commctrl.h> |
| #include <stdio.h> |
| |
| #include "main.h" |
| #include "regproc.h" |
| |
| #include "wine/debug.h" |
| #include "wine/unicode.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(regedit); |
| |
| ChildWnd* g_pChildWnd; |
| static int last_split; |
| |
| static const WCHAR wszLastKey[] = {'L','a','s','t','K','e','y',0}; |
| static const WCHAR wszKeyName[] = {'S','o','f','t','w','a','r','e','\\', |
| 'M','i','c','r','o','s','o','f','t','\\', |
| 'W','i','n','d','o','w','s','\\', |
| 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', |
| 'A','p','p','l','e','t','s','\\','R','e','g','e','d','i','t',0}; |
| |
| /******************************************************************************* |
| * Local module support methods |
| */ |
| |
| static LPCWSTR GetRootKeyName(HKEY hRootKey) |
| { |
| if(hRootKey == HKEY_CLASSES_ROOT) |
| return reg_class_namesW[INDEX_HKEY_CLASSES_ROOT]; |
| if(hRootKey == HKEY_CURRENT_USER) |
| return reg_class_namesW[INDEX_HKEY_CURRENT_USER]; |
| if(hRootKey == HKEY_LOCAL_MACHINE) |
| return reg_class_namesW[INDEX_HKEY_LOCAL_MACHINE]; |
| if(hRootKey == HKEY_USERS) |
| return reg_class_namesW[INDEX_HKEY_USERS]; |
| if(hRootKey == HKEY_CURRENT_CONFIG) |
| return reg_class_namesW[INDEX_HKEY_CURRENT_CONFIG]; |
| if(hRootKey == HKEY_DYN_DATA) |
| return reg_class_namesW[INDEX_HKEY_DYN_DATA]; |
| else |
| { |
| static const WCHAR unknown_key[] = {'U','N','K','N','O','W','N',' ','H','K','E','Y',',',' ', |
| 'P','L','E','A','S','E',' ','R','E','P','O','R','T',0}; |
| return unknown_key; |
| } |
| } |
| |
| static void draw_splitbar(HWND hWnd, int x) |
| { |
| RECT rt; |
| HDC hdc = GetDC(hWnd); |
| |
| GetClientRect(hWnd, &rt); |
| rt.left = x - SPLIT_WIDTH/2; |
| rt.right = x + SPLIT_WIDTH/2+1; |
| InvertRect(hdc, &rt); |
| ReleaseDC(hWnd, hdc); |
| } |
| |
| static void ResizeWnd(int cx, int cy) |
| { |
| HDWP hdwp = BeginDeferWindowPos(2); |
| RECT rt = {0, 0, cx, cy}; |
| |
| cx = g_pChildWnd->nSplitPos + SPLIT_WIDTH/2; |
| DeferWindowPos(hdwp, g_pChildWnd->hTreeWnd, 0, rt.left, rt.top, g_pChildWnd->nSplitPos-SPLIT_WIDTH/2-rt.left, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE); |
| DeferWindowPos(hdwp, g_pChildWnd->hListWnd, 0, rt.left+cx , rt.top, rt.right-cx, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE); |
| EndDeferWindowPos(hdwp); |
| } |
| |
| static void OnPaint(HWND hWnd) |
| { |
| PAINTSTRUCT ps; |
| RECT rt; |
| |
| GetClientRect(hWnd, &rt); |
| BeginPaint(hWnd, &ps); |
| FillRect(ps.hdc, &rt, GetSysColorBrush(COLOR_BTNFACE)); |
| EndPaint(hWnd, &ps); |
| } |
| |
| static LPWSTR CombinePaths(LPCWSTR pPaths[], int nPaths) { |
| int i, len, pos; |
| LPWSTR combined; |
| for (i=0, len=0; i<nPaths; i++) { |
| if (pPaths[i] && *pPaths[i]) { |
| len += lstrlenW(pPaths[i])+1; |
| } |
| } |
| combined = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); |
| *combined = '\0'; |
| for (i=0, pos=0; i<nPaths; i++) { |
| if (pPaths[i] && *pPaths[i]) { |
| int llen = lstrlenW(pPaths[i]); |
| if (!*combined) |
| lstrcpyW(combined, pPaths[i]); |
| else { |
| combined[pos++] = '\\'; |
| lstrcpyW(combined+pos, pPaths[i]); |
| } |
| pos += llen; |
| } |
| } |
| return combined; |
| } |
| |
| static LPWSTR GetPathRoot(HWND hwndTV, HTREEITEM hItem, BOOL bFull) { |
| LPCWSTR parts[2] = {0,0}; |
| WCHAR text[260]; |
| HKEY hRootKey = NULL; |
| if (!hItem) |
| hItem = TreeView_GetSelection(hwndTV); |
| HeapFree(GetProcessHeap(), 0, GetItemPath(hwndTV, hItem, &hRootKey)); |
| if (!bFull && !hRootKey) |
| return NULL; |
| if (hRootKey) |
| parts[1] = GetRootKeyName(hRootKey); |
| if (bFull) { |
| DWORD dwSize = sizeof(text)/sizeof(WCHAR); |
| GetComputerNameW(text, &dwSize); |
| parts[0] = text; |
| } |
| return CombinePaths(parts, 2); |
| } |
| |
| LPWSTR GetItemFullPath(HWND hwndTV, HTREEITEM hItem, BOOL bFull) { |
| LPWSTR parts[2]; |
| LPWSTR ret; |
| HKEY hRootKey = NULL; |
| |
| parts[0] = GetPathRoot(hwndTV, hItem, bFull); |
| parts[1] = GetItemPath(hwndTV, hItem, &hRootKey); |
| ret = CombinePaths((LPCWSTR *)parts, 2); |
| HeapFree(GetProcessHeap(), 0, parts[0]); |
| HeapFree(GetProcessHeap(), 0, parts[1]); |
| return ret; |
| } |
| |
| static LPWSTR GetPathFullPath(HWND hwndTV, LPWSTR path) { |
| LPWSTR parts[2]; |
| LPWSTR ret; |
| |
| parts[0] = GetPathRoot(hwndTV, 0, TRUE); |
| parts[1] = path; |
| ret = CombinePaths((LPCWSTR*)parts, 2); |
| HeapFree(GetProcessHeap(), 0, parts[0]); |
| return ret; |
| } |
| |
| static void OnTreeSelectionChanged(HWND hwndTV, HWND hwndLV, HTREEITEM hItem, BOOL bRefreshLV) |
| { |
| if (bRefreshLV) { |
| LPWSTR keyPath; |
| HKEY hRootKey = NULL; |
| keyPath = GetItemPath(hwndTV, hItem, &hRootKey); |
| RefreshListView(hwndLV, hRootKey, keyPath, NULL); |
| HeapFree(GetProcessHeap(), 0, keyPath); |
| } |
| UpdateStatusBar(); |
| } |
| |
| /******************************************************************************* |
| * finish_splitbar [internal] |
| * |
| * make the splitbar invisible and resize the windows |
| * (helper for ChildWndProc) |
| */ |
| static void finish_splitbar(HWND hWnd, int x) |
| { |
| RECT rt; |
| |
| draw_splitbar(hWnd, last_split); |
| last_split = -1; |
| GetClientRect(hWnd, &rt); |
| g_pChildWnd->nSplitPos = x; |
| ResizeWnd(rt.right, rt.bottom); |
| ReleaseCapture(); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG) |
| * |
| * PURPOSE: Processes WM_COMMAND messages for the main frame window. |
| * |
| */ |
| |
| static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
| { |
| switch (LOWORD(wParam)) { |
| /* Parse the menu selections: */ |
| case ID_REGISTRY_EXIT: |
| DestroyWindow(hWnd); |
| break; |
| case ID_VIEW_REFRESH: |
| WINE_TRACE("Is this ever called or is it just dead code?\n"); |
| /* TODO */ |
| break; |
| case ID_SWITCH_PANELS: |
| g_pChildWnd->nFocusPanel = !g_pChildWnd->nFocusPanel; |
| SetFocus(g_pChildWnd->nFocusPanel? g_pChildWnd->hListWnd: g_pChildWnd->hTreeWnd); |
| break; |
| default: |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| /******************************************************************************* |
| * get_last_key [internal] |
| * |
| * open last key |
| * |
| */ |
| static void get_last_key(HWND hwndTV) |
| { |
| HKEY hkey; |
| WCHAR wszVal[KEY_MAX_LEN]; |
| DWORD dwSize = sizeof(wszVal); |
| |
| if (RegCreateKeyExW(HKEY_CURRENT_USER, wszKeyName, 0, NULL, 0, KEY_READ, NULL, &hkey, NULL) == ERROR_SUCCESS) |
| { |
| if (RegQueryValueExW(hkey, wszLastKey, NULL, NULL, (LPBYTE)wszVal, &dwSize) == ERROR_SUCCESS) |
| SendMessageW(hwndTV, TVM_SELECTITEM, TVGN_CARET, (LPARAM)FindPathInTree(hwndTV, wszVal)); |
| |
| RegCloseKey(hkey); |
| } |
| } |
| |
| /******************************************************************************* |
| * set_last_key [internal] |
| * |
| * save last key |
| * |
| */ |
| static void set_last_key(HWND hwndTV) |
| { |
| HKEY hkey; |
| WCHAR *wszVal; |
| |
| if (RegCreateKeyExW(HKEY_CURRENT_USER, wszKeyName, 0, NULL, 0, KEY_WRITE, NULL, &hkey, NULL) == ERROR_SUCCESS) |
| { |
| wszVal = GetItemFullPath(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd), FALSE); |
| RegSetValueExW(hkey, wszLastKey, 0, REG_SZ, (LPBYTE)wszVal, (lstrlenW(wszVal) + 1) * sizeof(WCHAR)); |
| HeapFree(GetProcessHeap(), 0, wszVal); |
| RegCloseKey(hkey); |
| } |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: ChildWndProc(HWND, unsigned, WORD, LONG) |
| * |
| * PURPOSE: Processes messages for the child windows. |
| * |
| * WM_COMMAND - process the application menu |
| * WM_PAINT - Paint the main window |
| * WM_DESTROY - post a quit message and return |
| * |
| */ |
| LRESULT CALLBACK ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
| { |
| switch (message) { |
| case WM_CREATE: |
| g_pChildWnd = HeapAlloc(GetProcessHeap(), 0, sizeof(ChildWnd)); |
| if (!g_pChildWnd) return 0; |
| LoadStringW(hInst, IDS_REGISTRY_ROOT_NAME, g_pChildWnd->szPath, MAX_PATH); |
| g_pChildWnd->nSplitPos = 250; |
| g_pChildWnd->hWnd = hWnd; |
| g_pChildWnd->hTreeWnd = CreateTreeView(hWnd, g_pChildWnd->szPath, TREE_WINDOW); |
| g_pChildWnd->hListWnd = CreateListView(hWnd, LIST_WINDOW/*, g_pChildWnd->szPath*/); |
| g_pChildWnd->nFocusPanel = 1; |
| SetFocus(g_pChildWnd->hTreeWnd); |
| get_last_key(g_pChildWnd->hTreeWnd); |
| break; |
| case WM_COMMAND: |
| if (!_CmdWndProc(hWnd, message, wParam, lParam)) { |
| goto def; |
| } |
| break; |
| case WM_PAINT: |
| OnPaint(hWnd); |
| return 0; |
| case WM_SETCURSOR: |
| if (LOWORD(lParam) == HTCLIENT) { |
| POINT pt; |
| GetCursorPos(&pt); |
| ScreenToClient(hWnd, &pt); |
| if (pt.x>=g_pChildWnd->nSplitPos-SPLIT_WIDTH/2 && pt.x<g_pChildWnd->nSplitPos+SPLIT_WIDTH/2+1) { |
| SetCursor(LoadCursor(0, IDC_SIZEWE)); |
| return TRUE; |
| } |
| } |
| goto def; |
| case WM_DESTROY: |
| set_last_key(g_pChildWnd->hTreeWnd); |
| HeapFree(GetProcessHeap(), 0, g_pChildWnd); |
| g_pChildWnd = NULL; |
| PostQuitMessage(0); |
| break; |
| case WM_LBUTTONDOWN: { |
| RECT rt; |
| int x = (short)LOWORD(lParam); |
| GetClientRect(hWnd, &rt); |
| if (x>=g_pChildWnd->nSplitPos-SPLIT_WIDTH/2 && x<g_pChildWnd->nSplitPos+SPLIT_WIDTH/2+1) { |
| last_split = g_pChildWnd->nSplitPos; |
| draw_splitbar(hWnd, last_split); |
| SetCapture(hWnd); |
| } |
| break; |
| } |
| |
| /* WM_RBUTTONDOWN sets the splitbar the same way as WM_LBUTTONUP */ |
| case WM_LBUTTONUP: |
| case WM_RBUTTONDOWN: |
| if (GetCapture() == hWnd) { |
| finish_splitbar(hWnd, LOWORD(lParam)); |
| } |
| break; |
| |
| case WM_CAPTURECHANGED: |
| if (GetCapture()==hWnd && last_split>=0) |
| draw_splitbar(hWnd, last_split); |
| break; |
| |
| case WM_KEYDOWN: |
| if (wParam == VK_ESCAPE) |
| if (GetCapture() == hWnd) { |
| RECT rt; |
| draw_splitbar(hWnd, last_split); |
| GetClientRect(hWnd, &rt); |
| ResizeWnd(rt.right, rt.bottom); |
| last_split = -1; |
| ReleaseCapture(); |
| SetCursor(LoadCursor(0, IDC_ARROW)); |
| } |
| break; |
| |
| case WM_MOUSEMOVE: |
| if (GetCapture() == hWnd) { |
| RECT rt; |
| int x = LOWORD(lParam); |
| HDC hdc = GetDC(hWnd); |
| GetClientRect(hWnd, &rt); |
| rt.left = last_split-SPLIT_WIDTH/2; |
| rt.right = last_split+SPLIT_WIDTH/2+1; |
| InvertRect(hdc, &rt); |
| last_split = x; |
| rt.left = x-SPLIT_WIDTH/2; |
| rt.right = x+SPLIT_WIDTH/2+1; |
| InvertRect(hdc, &rt); |
| ReleaseDC(hWnd, hdc); |
| } |
| break; |
| |
| case WM_SETFOCUS: |
| if (g_pChildWnd != NULL) { |
| SetFocus(g_pChildWnd->nFocusPanel? g_pChildWnd->hListWnd: g_pChildWnd->hTreeWnd); |
| } |
| break; |
| |
| case WM_TIMER: |
| break; |
| |
| case WM_NOTIFY: |
| if (((int)wParam == TREE_WINDOW) && (g_pChildWnd != NULL)) { |
| switch (((LPNMHDR)lParam)->code) { |
| case TVN_ITEMEXPANDINGW: |
| return !OnTreeExpanding(g_pChildWnd->hTreeWnd, (NMTREEVIEW*)lParam); |
| case TVN_SELCHANGEDW: |
| OnTreeSelectionChanged(g_pChildWnd->hTreeWnd, g_pChildWnd->hListWnd, |
| ((NMTREEVIEWW *)lParam)->itemNew.hItem, TRUE); |
| break; |
| case NM_SETFOCUS: |
| g_pChildWnd->nFocusPanel = 0; |
| break; |
| case NM_RCLICK: { |
| POINT pt; |
| GetCursorPos(&pt); |
| TrackPopupMenu(GetSubMenu(hPopupMenus, PM_NEW), |
| TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL); |
| break; |
| } |
| case TVN_ENDLABELEDITW: { |
| HKEY hRootKey; |
| LPNMTVDISPINFOW dispInfo = (LPNMTVDISPINFOW)lParam; |
| LPWSTR path = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hRootKey); |
| BOOL res = RenameKey(hWnd, hRootKey, path, dispInfo->item.pszText); |
| if (res) { |
| TVITEMEXW item; |
| LPWSTR fullPath = GetPathFullPath(g_pChildWnd->hTreeWnd, |
| dispInfo->item.pszText); |
| item.mask = TVIF_HANDLE | TVIF_TEXT; |
| item.hItem = TreeView_GetSelection(g_pChildWnd->hTreeWnd); |
| item.pszText = dispInfo->item.pszText; |
| SendMessageW( g_pChildWnd->hTreeWnd, TVM_SETITEMW, 0, (LPARAM)&item ); |
| SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)fullPath); |
| HeapFree(GetProcessHeap(), 0, fullPath); |
| } |
| HeapFree(GetProcessHeap(), 0, path); |
| return res; |
| } |
| default: |
| return 0; /* goto def; */ |
| } |
| } else |
| if (((int)wParam == LIST_WINDOW) && (g_pChildWnd != NULL)) { |
| if (((LPNMHDR)lParam)->code == NM_SETFOCUS) { |
| g_pChildWnd->nFocusPanel = 1; |
| } else if (!SendMessageW(g_pChildWnd->hListWnd, WM_NOTIFY_REFLECT, wParam, lParam)) { |
| goto def; |
| } |
| } |
| break; |
| |
| case WM_SIZE: |
| if (wParam != SIZE_MINIMIZED && g_pChildWnd != NULL) { |
| ResizeWnd(LOWORD(lParam), HIWORD(lParam)); |
| } |
| /* fall through */ |
| default: def: |
| return DefWindowProc(hWnd, message, wParam, lParam); |
| } |
| return 0; |
| } |