Remove reference to old graphics directory
[wine/multimedia.git] / programs / regedit / listview.c
blob851942992b2f714eae1a82745ee2994061a9cb63
1 /*
2 * Regedit listviews
4 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
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.
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.
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
21 #include <windows.h>
22 #include <windowsx.h>
23 #include <commctrl.h>
24 #include <stdlib.h>
25 #include <tchar.h>
26 #include <process.h>
27 #include <stdio.h>
29 #include "main.h"
31 typedef struct tagLINE_INFO
33 DWORD dwValType;
34 LPTSTR name;
35 void* val;
36 size_t val_len;
37 } LINE_INFO;
39 /*******************************************************************************
40 * Global and Local Variables:
43 static WNDPROC g_orgListWndProc;
44 static DWORD g_columnToSort = ~0UL;
45 static BOOL g_invertSort = FALSE;
46 static LPTSTR g_valueName;
47 static LPTSTR g_currentPath;
48 static HKEY g_currentRootKey;
50 #define MAX_LIST_COLUMNS (IDS_LIST_COLUMN_LAST - IDS_LIST_COLUMN_FIRST + 1)
51 static int default_column_widths[MAX_LIST_COLUMNS] = { 200, 175, 400 };
52 static int column_alignment[MAX_LIST_COLUMNS] = { LVCFMT_LEFT, LVCFMT_LEFT, LVCFMT_LEFT };
54 LPTSTR get_item_text(HWND hwndLV, int item)
56 LPTSTR newStr, curStr;
57 int maxLen = 128;
59 curStr = HeapAlloc(GetProcessHeap(), 0, maxLen);
60 if (!curStr) return NULL;
61 do {
62 ListView_GetItemText(hwndLV, item, 0, curStr, maxLen);
63 if (_tcslen(curStr) < maxLen - 1) return curStr;
64 newStr = HeapReAlloc(GetProcessHeap(), 0, curStr, maxLen * 2);
65 if (!newStr) break;
66 curStr = newStr;
67 maxLen *= 2;
68 } while (TRUE);
69 HeapFree(GetProcessHeap(), 0, curStr);
70 return NULL;
73 LPCTSTR GetValueName(HWND hwndLV)
75 INT item;
77 if (g_valueName) HeapFree(GetProcessHeap(), 0, g_valueName);
78 g_valueName = NULL;
80 item = ListView_GetNextItem(hwndLV, -1, LVNI_FOCUSED);
81 if (item == -1) return NULL;
83 g_valueName = get_item_text(hwndLV, item);
85 return g_valueName;
88 /*******************************************************************************
89 * Local module support methods
91 static void AddEntryToList(HWND hwndLV, LPTSTR Name, DWORD dwValType, void* ValBuf, DWORD dwCount)
93 LINE_INFO* linfo;
94 LVITEM item;
95 int index;
97 linfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINE_INFO) + dwCount);
98 linfo->dwValType = dwValType;
99 linfo->val_len = dwCount;
100 memcpy(&linfo[1], ValBuf, dwCount);
101 linfo->name = _tcsdup(Name);
103 item.mask = LVIF_TEXT | LVIF_PARAM;
104 item.iItem = 0;/*idx; */
105 item.iSubItem = 0;
106 item.state = 0;
107 item.stateMask = 0;
108 item.pszText = Name;
109 item.cchTextMax = _tcslen(item.pszText);
110 if (item.cchTextMax == 0)
111 item.pszText = LPSTR_TEXTCALLBACK;
112 item.iImage = 0;
113 item.lParam = (LPARAM)linfo;
115 /* item.lParam = (LPARAM)ValBuf; */
116 #if (_WIN32_IE >= 0x0300)
117 item.iIndent = 0;
118 #endif
120 index = ListView_InsertItem(hwndLV, &item);
121 if (index != -1) {
122 /* LPTSTR pszText = NULL; */
123 LPTSTR pszText = _T("value");
124 switch (dwValType) {
125 case REG_SZ:
126 case REG_EXPAND_SZ:
127 ListView_SetItemText(hwndLV, index, 2, ValBuf);
128 break;
129 case REG_DWORD: {
130 TCHAR buf[64];
131 wsprintf(buf, _T("0x%08X (%d)"), *(DWORD*)ValBuf, *(DWORD*)ValBuf);
132 ListView_SetItemText(hwndLV, index, 2, buf);
134 /* lpsRes = convertHexToDWORDStr(lpbData, dwLen); */
135 break;
136 case REG_BINARY: {
137 unsigned int i;
138 LPBYTE pData = (LPBYTE)ValBuf;
139 LPTSTR strBinary = HeapAlloc(GetProcessHeap(), 0, dwCount * sizeof(TCHAR) * 3 + 1);
140 for (i = 0; i < dwCount; i++)
141 wsprintf( strBinary + i*3, _T("%02X "), pData[i] );
142 strBinary[dwCount * 3] = 0;
143 ListView_SetItemText(hwndLV, index, 2, strBinary);
144 HeapFree(GetProcessHeap(), 0, strBinary);
146 break;
147 default:
148 /* lpsRes = convertHexToHexCSV(lpbData, dwLen); */
149 ListView_SetItemText(hwndLV, index, 2, pszText);
150 break;
155 static BOOL CreateListColumns(HWND hWndListView)
157 TCHAR szText[50];
158 int index;
159 LV_COLUMN lvC;
161 /* Create columns. */
162 lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
163 lvC.pszText = szText;
165 /* Load the column labels from the resource file. */
166 for (index = 0; index < MAX_LIST_COLUMNS; index++) {
167 lvC.iSubItem = index;
168 lvC.cx = default_column_widths[index];
169 lvC.fmt = column_alignment[index];
170 LoadString(hInst, IDS_LIST_COLUMN_FIRST + index, szText, sizeof(szText)/sizeof(TCHAR));
171 if (ListView_InsertColumn(hWndListView, index, &lvC) == -1) return FALSE;
173 return TRUE;
176 /* OnGetDispInfo - processes the LVN_GETDISPINFO notification message. */
178 static void OnGetDispInfo(NMLVDISPINFO* plvdi)
180 static TCHAR buffer[200];
182 plvdi->item.pszText = NULL;
183 plvdi->item.cchTextMax = 0;
185 switch (plvdi->item.iSubItem) {
186 case 0:
187 plvdi->item.pszText = _T("(Default)");
188 break;
189 case 1:
190 switch (((LINE_INFO*)plvdi->item.lParam)->dwValType) {
191 case REG_SZ:
192 plvdi->item.pszText = _T("REG_SZ");
193 break;
194 case REG_EXPAND_SZ:
195 plvdi->item.pszText = _T("REG_EXPAND_SZ");
196 break;
197 case REG_BINARY:
198 plvdi->item.pszText = _T("REG_BINARY");
199 break;
200 case REG_DWORD:
201 plvdi->item.pszText = _T("REG_DWORD");
202 break;
203 case REG_DWORD_BIG_ENDIAN:
204 plvdi->item.pszText = _T("REG_DWORD_BIG_ENDIAN");
205 break;
206 case REG_MULTI_SZ:
207 plvdi->item.pszText = _T("REG_MULTI_SZ");
208 break;
209 case REG_LINK:
210 plvdi->item.pszText = _T("REG_LINK");
211 break;
212 case REG_RESOURCE_LIST:
213 plvdi->item.pszText = _T("REG_RESOURCE_LIST");
214 break;
215 case REG_NONE:
216 plvdi->item.pszText = _T("REG_NONE");
217 break;
218 default:
219 wsprintf(buffer, _T("unknown(%d)"), plvdi->item.lParam);
220 plvdi->item.pszText = buffer;
221 break;
223 break;
224 case 2:
225 plvdi->item.pszText = _T("(value not set)");
226 break;
227 case 3:
228 plvdi->item.pszText = _T("");
229 break;
233 static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
235 LINE_INFO*l, *r;
236 l = (LINE_INFO*)lParam1;
237 r = (LINE_INFO*)lParam2;
239 if (g_columnToSort == ~0UL)
240 g_columnToSort = 0;
242 if (g_columnToSort == 1 && l->dwValType != r->dwValType)
243 return g_invertSort ? (int)r->dwValType - (int)l->dwValType : (int)l->dwValType - (int)r->dwValType;
244 if (g_columnToSort == 2) {
245 /* FIXME: Sort on value */
247 return g_invertSort ? _tcscmp(r->name, l->name) : _tcscmp(l->name, r->name);
250 static void ListViewPopUpMenu(HWND hWnd, POINT pt)
254 HWND StartValueRename(HWND hwndLV)
256 int item;
258 item = ListView_GetNextItem(hwndLV, -1, LVNI_FOCUSED | LVNI_SELECTED);
259 if (item < 0) return 0;
260 return ListView_EditLabel(hwndLV, item);
263 static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
265 switch (LOWORD(wParam)) {
266 /* case ID_FILE_OPEN: */
267 /* break; */
268 default:
269 return FALSE;
271 return TRUE;
274 static LRESULT CALLBACK ListWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
276 switch (message) {
277 case WM_COMMAND:
278 if (!_CmdWndProc(hWnd, message, wParam, lParam)) {
279 return CallWindowProc(g_orgListWndProc, hWnd, message, wParam, lParam);
281 break;
282 case WM_NOTIFY:
283 switch (((LPNMHDR)lParam)->code) {
284 case LVN_GETDISPINFO:
285 OnGetDispInfo((NMLVDISPINFO*)lParam);
286 break;
287 case LVN_COLUMNCLICK:
288 if (g_columnToSort == ((LPNMLISTVIEW)lParam)->iSubItem)
289 g_invertSort = !g_invertSort;
290 else {
291 g_columnToSort = ((LPNMLISTVIEW)lParam)->iSubItem;
292 g_invertSort = FALSE;
295 ListView_SortItems(hWnd, CompareFunc, hWnd);
296 break;
297 case LVN_ENDLABELEDIT: {
298 LPNMLVDISPINFO dispInfo = (LPNMLVDISPINFO)lParam;
299 LPTSTR valueName = get_item_text(hWnd, dispInfo->item.iItem);
300 BOOL res = RenameValue(hWnd, g_currentRootKey, g_currentPath, valueName, dispInfo->item.pszText);
301 if (res) RefreshListView(hWnd, g_currentRootKey, g_currentPath);
302 HeapFree(GetProcessHeap(), 0, valueName);
303 return res;
305 case NM_DBLCLK: {
306 NMITEMACTIVATE* nmitem = (LPNMITEMACTIVATE)lParam;
307 LVHITTESTINFO info;
309 if (nmitem->hdr.hwndFrom != hWnd) break;
310 /* if (nmitem->hdr.idFrom != IDW_LISTVIEW) break; */
311 /* if (nmitem->hdr.code != ???) break; */
312 #ifdef _MSC_VER
313 switch (nmitem->uKeyFlags) {
314 case LVKF_ALT: /* The ALT key is pressed. */
315 /* properties dialog box ? */
316 break;
317 case LVKF_CONTROL: /* The CTRL key is pressed. */
318 /* run dialog box for providing parameters... */
319 break;
320 case LVKF_SHIFT: /* The SHIFT key is pressed. */
321 break;
323 #endif
324 info.pt.x = nmitem->ptAction.x;
325 info.pt.y = nmitem->ptAction.y;
326 if (ListView_HitTest(hWnd, &info) != -1) {
327 LVITEM item;
328 item.mask = LVIF_PARAM;
329 item.iItem = info.iItem;
330 if (ListView_GetItem(hWnd, &item)) {}
333 break;
335 case NM_RCLICK: {
336 int idx;
337 LV_HITTESTINFO lvH;
338 NM_LISTVIEW* pNm = (NM_LISTVIEW*)lParam;
339 lvH.pt.x = pNm->ptAction.x;
340 lvH.pt.y = pNm->ptAction.y;
341 idx = ListView_HitTest(hWnd, &lvH);
342 if (idx != -1) {
343 POINT pt;
344 GetCursorPos(&pt);
345 ListViewPopUpMenu(hWnd, pt);
346 return idx;
349 break;
351 default:
352 return CallWindowProc(g_orgListWndProc, hWnd, message, wParam, lParam);
354 break;
355 case WM_CONTEXTMENU: {
356 POINTS pt = MAKEPOINTS(lParam);
357 int cnt = ListView_GetNextItem(hWnd, -1, LVNI_FOCUSED | LVNI_SELECTED);
358 TrackPopupMenu(GetSubMenu(hPopupMenus, cnt == -1 ? PM_NEW : PM_MODIFYVALUE),
359 TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL);
360 break;
362 case WM_KEYDOWN:
363 if (wParam == VK_TAB) {
364 /*TODO: SetFocus(Globals.hDriveBar) */
365 /*SetFocus(child->nFocusPanel? child->left.hWnd: child->right.hWnd); */
367 /* fall thru... */
368 default:
369 return CallWindowProc(g_orgListWndProc, hWnd, message, wParam, lParam);
370 break;
372 return 0;
376 HWND CreateListView(HWND hwndParent, int id)
378 RECT rcClient;
379 HWND hwndLV;
381 /* Get the dimensions of the parent window's client area, and create the list view control. */
382 GetClientRect(hwndParent, &rcClient);
383 hwndLV = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, _T("List View"),
384 WS_VISIBLE | WS_CHILD | WS_TABSTOP | LVS_REPORT | LVS_EDITLABELS,
385 0, 0, rcClient.right, rcClient.bottom,
386 hwndParent, (HMENU)id, hInst, NULL);
387 if (!hwndLV) return NULL;
388 ListView_SetExtendedListViewStyle(hwndLV, LVS_EX_FULLROWSELECT);
390 /* Initialize the image list, and add items to the control. */
392 if (!InitListViewImageLists(hwndLV)) goto fail;
393 if (!InitListViewItems(hwndLV, szName)) goto fail;
395 if (!CreateListColumns(hwndLV)) goto fail;
396 g_orgListWndProc = SubclassWindow(hwndLV, ListWndProc);
397 return hwndLV;
398 fail:
399 DestroyWindow(hwndLV);
400 return NULL;
403 BOOL RefreshListView(HWND hwndLV, HKEY hKeyRoot, LPCTSTR keyPath)
405 BOOL result = FALSE;
406 DWORD max_sub_key_len;
407 DWORD max_val_name_len, valNameLen;
408 DWORD max_val_size, valSize;
409 DWORD val_count, index, valType;
410 TCHAR* valName = 0;
411 BYTE* valBuf = 0;
412 HKEY hKey = 0;
413 LONG errCode;
414 INT count, i;
415 LVITEM item;
417 if (!hwndLV) return FALSE;
419 SendMessage(hwndLV, WM_SETREDRAW, FALSE, 0);
421 errCode = RegOpenKeyEx(hKeyRoot, keyPath, 0, KEY_READ, &hKey);
422 if (errCode != ERROR_SUCCESS) goto done;
424 count = ListView_GetItemCount(hwndLV);
425 for (i = 0; i < count; i++) {
426 item.mask = LVIF_PARAM;
427 item.iItem = i;
428 ListView_GetItem(hwndLV, &item);
429 free(((LINE_INFO*)item.lParam)->name);
430 HeapFree(GetProcessHeap(), 0, (void*)item.lParam);
432 g_columnToSort = ~0UL;
433 ListView_DeleteAllItems(hwndLV);
435 /* get size information and resize the buffers if necessary */
436 errCode = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, &max_sub_key_len, NULL,
437 &val_count, &max_val_name_len, &max_val_size, NULL, NULL);
438 if (errCode != ERROR_SUCCESS) goto done;
440 /* account for the terminator char */
441 max_val_name_len++;
442 max_val_size++;
444 valName = HeapAlloc(GetProcessHeap(), 0, max_val_name_len * sizeof(TCHAR));
445 valBuf = HeapAlloc(GetProcessHeap(), 0, max_val_size);
446 /*if (RegQueryValueEx(hKey, NULL, NULL, &dwValType, ValBuf, &dwValSize) == ERROR_SUCCESS) { */
447 /* AddEntryToList(hwndLV, _T("(Default)"), dwValType, ValBuf, dwValSize); */
448 /*} */
449 /*dwValSize = max_val_size; */
450 for(index = 0; index < val_count; index++) {
451 valNameLen = max_val_name_len;
452 valSize = max_val_size;
453 valType = 0;
454 errCode = RegEnumValue(hKey, index, valName, &valNameLen, NULL, &valType, valBuf, &valSize);
455 if (errCode != ERROR_SUCCESS) goto done;
456 valBuf[valSize] = 0;
457 AddEntryToList(hwndLV, valName, valType, valBuf, valSize);
459 ListView_SortItems(hwndLV, CompareFunc, hwndLV);
461 g_currentRootKey = hKeyRoot;
462 if (keyPath != g_currentPath) {
463 HeapFree(GetProcessHeap(), 0, g_currentPath);
464 g_currentPath = HeapAlloc(GetProcessHeap(), 0, (lstrlen(keyPath) + 1) * sizeof(TCHAR));
465 if (!g_currentPath) goto done;
466 lstrcpy(g_currentPath, keyPath);
469 result = TRUE;
471 done:
472 HeapFree(GetProcessHeap(), 0, valBuf);
473 HeapFree(GetProcessHeap(), 0, valName);
474 SendMessage(hwndLV, WM_SETREDRAW, TRUE, 0);
475 if (hKey) RegCloseKey(hKey);
477 return result;