Updated treeview and listview functionality.
[reactos.git] / rosapps / regedit / treeview.c
1 /*
2 * ReactOS regedit
3 *
4 * treeview.c
5 *
6 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #ifdef _MSC_VER
24 #include "stdafx.h"
25 #else
26 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
27 #include <windows.h>
28 #include <commctrl.h>
29 #include <stdlib.h>
30 #include <malloc.h>
31 #include <memory.h>
32 #include <tchar.h>
33 #include <process.h>
34 #include <stdio.h>
35 #endif
36
37 #include <windowsx.h>
38 #include <assert.h>
39 #define ASSERT assert
40 #include "main.h"
41 #include "treeview.h"
42
43 #include "trace.h"
44
45
46 // Global variables and constants
47 // Image_Open, Image_Closed, and Image_Root - integer variables for
48 // indexes of the images.
49 // CX_BITMAP and CY_BITMAP - width and height of an icon.
50 // NUM_BITMAPS - number of bitmaps to add to the image list.
51 int Image_Open;
52 int Image_Closed;
53 int Image_Root;
54
55 #define CX_BITMAP 16
56 #define CY_BITMAP 16
57 #define NUM_BITMAPS 3
58
59
60 static HTREEITEM AddEntryToTree(HWND hwndTV, Entry* entry, LPTSTR label)
61 {
62 HTREEITEM hItem = 0;
63 TVITEM tvi;
64 TVINSERTSTRUCT tvins;
65 static HTREEITEM hPrev = (HTREEITEM)TVI_FIRST;
66 static HTREEITEM hPrevRootItem = NULL;
67 static HTREEITEM hPrevLev2Item = NULL;
68
69 //TRACE("AddEntryToTree(level:%u - %s)\n", entry->level, entry->data.cFileName);
70
71 tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_PARAM;
72 /*
73 // Set the text of the item.
74 tvi.pszText = entry->data.cFileName;
75 tvi.cchTextMax = lstrlen(entry->data.cFileName);
76 // Assume the item is not a parent item, so give it an image.
77 tvi.iImage = Image_Root;
78 tvi.iSelectedImage = Image_Root;
79 tvi.cChildren = 1;
80 // Save the heading level in the item's application-defined data area.
81 //tvi.lParam = (LPARAM)entry->level;
82 */
83 if (label != NULL) {
84 tvi.pszText = label;
85 tvi.cchTextMax = _tcslen(label);
86 } else {
87 tvi.pszText = LPSTR_TEXTCALLBACK;
88 tvi.cchTextMax = 0;
89 }
90 tvi.iImage = I_IMAGECALLBACK;
91 tvi.iSelectedImage = I_IMAGECALLBACK;
92 tvi.cChildren = I_CHILDRENCALLBACK;
93 // Save the entry pointer in the item's application-defined data area.
94 tvi.lParam = (LPARAM)entry;
95
96 tvins.item = tvi;
97 tvins.hInsertAfter = hPrev;
98
99 // Set the parent item based on the specified level.
100 if (entry->level == 0) {
101 tvins.hParent = TVI_ROOT;
102 } else if (entry->level == 1) {
103 tvins.hParent = hPrevRootItem;
104 } else {
105 tvins.hParent = hPrevLev2Item;
106 if (hPrevLev2Item) {
107 tvins.hParent = entry->up->hTreeItem;
108 }
109 }
110
111 // Add the item to the tree view control.
112 hPrev = (HTREEITEM)SendMessage(hwndTV, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
113
114 // Save the handle to the item.
115 if (entry->level == 0)
116 hPrevRootItem = hPrev;
117 else if (entry->level == 1)
118 hPrevLev2Item = hPrev;
119 hItem = hPrev;
120 return hItem;
121 }
122
123 static Entry* CreateEntry(Entry* pParentEntry, HKEY hKey, LPCTSTR szKeyName)
124 {
125 Entry* pEntry = NULL;
126
127 pEntry = malloc(sizeof(Entry));
128 memset(pEntry, 0, sizeof(Entry));
129 //pEntry->up = pParentEntry;
130 pEntry->level = 1;
131 pEntry->hKey = hKey;
132 _tcsncpy(pEntry->szName, szKeyName, MAX_NAME_LEN);
133 // pEntry->hTreeItem = AddEntryToTree(hwndTV, pEntry, szKeyName);
134 return pEntry;
135 }
136
137 static BOOL InitTreeViewItems(HWND hwndTV, Root* pRoot/*LPCTSTR pHostName*/)
138 {
139 // HKEY hKey;
140 // LONG errCode;
141 Entry* pEntry = &pRoot->entry;
142 HTREEITEM hRootItem;
143
144 // TCHAR* pHostName = _T("My Computer");
145 // HTREEITEM hRootItem = AddItemToTree(hwndTV, pHostName, 1);
146 // pEntry = malloc(sizeof(Entry));
147 // memset(pEntry, 0, sizeof(Entry));
148
149 pEntry->level = 0;
150 pEntry->hTreeItem = AddEntryToTree(hwndTV, pEntry, pRoot->path);
151 hRootItem = pEntry->hTreeItem;
152
153 pEntry = CreateEntry(&pRoot->entry, HKEY_CLASSES_ROOT, _T("HKEY_CLASSES_ROOT"));
154 pEntry->hTreeItem = AddEntryToTree(hwndTV, pEntry, NULL);
155 pEntry = CreateEntry(&pRoot->entry, HKEY_CURRENT_USER, _T("HKEY_CURRENT_USER"));
156 pEntry->hTreeItem = AddEntryToTree(hwndTV, pEntry, NULL);
157 pEntry = CreateEntry(&pRoot->entry, HKEY_LOCAL_MACHINE, _T("HKEY_LOCAL_MACHINE"));
158 pEntry->hTreeItem = AddEntryToTree(hwndTV, pEntry, NULL);
159 pEntry = CreateEntry(&pRoot->entry, HKEY_USERS, _T("HKEY_USERS"));
160 pEntry->hTreeItem = AddEntryToTree(hwndTV, pEntry, NULL);
161 pEntry = CreateEntry(&pRoot->entry, HKEY_CURRENT_CONFIG, _T("HKEY_CURRENT_CONFIG"));
162 pEntry->hTreeItem = AddEntryToTree(hwndTV, pEntry, NULL);
163 return TRUE;
164 }
165
166 // InitTreeViewImageLists - creates an image list, adds three bitmaps
167 // to it, and associates the image list with a tree view control.
168 // Returns TRUE if successful, or FALSE otherwise.
169 // hwndTV - handle to the tree view control.
170
171 static BOOL InitTreeViewImageLists(HWND hwndTV)
172 {
173 HIMAGELIST himl; // handle to image list
174 HBITMAP hbmp; // handle to bitmap
175
176 // Create the image list.
177 if ((himl = ImageList_Create(CX_BITMAP, CY_BITMAP,
178 FALSE, NUM_BITMAPS, 0)) == NULL)
179 return FALSE;
180
181 // Add the open file, closed file, and document bitmaps.
182 hbmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_OPEN_FILE));
183 Image_Open = ImageList_Add(himl, hbmp, (HBITMAP) NULL);
184 DeleteObject(hbmp);
185
186 hbmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_CLOSED_FILE));
187 Image_Closed = ImageList_Add(himl, hbmp, (HBITMAP) NULL);
188 DeleteObject(hbmp);
189
190 hbmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_ROOT));
191 Image_Root = ImageList_Add(himl, hbmp, (HBITMAP) NULL);
192 DeleteObject(hbmp);
193
194 // Fail if not all of the images were added.
195 if (ImageList_GetImageCount(himl) < 3)
196 return FALSE;
197
198 // Associate the image list with the tree view control.
199 TreeView_SetImageList(hwndTV, himl, TVSIL_NORMAL);
200
201 return TRUE;
202 }
203
204 #ifndef _MSC_VER
205 #define NMTVDISPINFO TV_DISPINFO
206 #define NMTVDISPINFO TV_DISPINFO
207 #endif
208
209 static void OnGetDispInfo(NMTVDISPINFO* ptvdi)
210 {
211 Entry* pEntry = (Entry*)ptvdi->item.lParam;
212 ASSERT(pEntry);
213
214 if (ptvdi->item.mask & TVIF_CHILDREN ) {
215 ptvdi->item.cChildren = 5;
216 }
217 if (ptvdi->item.mask & TVIF_IMAGE) {
218 ptvdi->item.iImage = Image_Root;
219 }
220 if (ptvdi->item.mask & TVIF_SELECTEDIMAGE) {
221 ptvdi->item.iSelectedImage = Image_Closed;
222 }
223 if (ptvdi->item.mask & TVIF_TEXT) {
224 /*
225 ptvdi->item.pszText = _T("Unknown");
226 ptvdi->item.cchTextMax = _tcslen(ptvdi->item.pszText);
227 if (pEntry->bKey == TRUE) {
228 DWORD nSubKeys;
229 DWORD MaxSubKeyLen;
230 DWORD MaxClassLen;
231 DWORD ValueCount;
232 DWORD MaxValueNameLen;
233 DWORD MaxValueLen;
234 DWORD SecurityDescriptorLen;
235
236 HKEY hKey = pEntry->hKey;
237 LONG result = RegQueryInfoKey(pEntry->hKey, Class, &cClass, 0,
238 &nSubKeys, &MaxSubKeyLen, &MaxClassLen, &ValueCount,
239 &MaxValueNameLen, &MaxValueLen, &SecurityDescriptorLen,
240 &LastWriteTime);
241 if (result == ERROR_SUCCESS) {
242 ptvdi->item.pszText = Class;
243 ptvdi->item.cchTextMax = cClass;
244 }
245 }
246 */
247 ptvdi->item.pszText = pEntry->szName;
248 ptvdi->item.cchTextMax = lstrlen(pEntry->szName);
249 }
250 }
251
252 static BOOL OnExpand(int flag, HTREEITEM* pti)
253 {
254 TRACE(_T("TreeWndProc(...) OnExpand()\n"));
255 //TRACE("OnExpand(...) entry name: %s\n", entry->data.cFileName);
256 /*
257 TVE_COLLAPSE Collapses the list.
258 TVE_COLLAPSERESET Collapses the list and removes the child items. The TVIS_EXPANDEDONCE state flag is reset. This flag must be used with the TVE_COLLAPSE flag.
259 TVE_EXPAND Expands the list.
260 TVE_EXPANDPARTIAL Version 4.70. Partially expands the list. In this state, the child items are visible and the parent item's plus symbol is displayed. This flag must be used in combination with the TVE_EXPAND flag.
261 TVE_TOGGLE Collapses the list if it is expanded or expands it if it is collapsed.
262 */
263 return TRUE;
264 }
265
266 static BOOL OnExpanding(HWND hWnd, NMTREEVIEW* pnmtv)
267 {
268 static int expanding;
269 HKEY hKey;
270 LONG errCode;
271
272 Entry* entry = (Entry*)pnmtv->itemNew.lParam;
273 TRACE(_T("TreeWndProc(...) OnExpanding() entry: %p\n"), entry);
274 if (expanding) return FALSE;
275 expanding = TRUE;
276 if (entry) {
277 errCode = RegOpenKeyEx(entry->hKey, NULL, 0, KEY_READ, &hKey);
278 if (errCode == ERROR_SUCCESS) {
279 TCHAR Name[MAX_NAME_LEN];
280 DWORD cName = MAX_NAME_LEN;
281 FILETIME LastWriteTime;
282 DWORD dwIndex = 0L;
283 while (RegEnumKeyEx(hKey, dwIndex, Name, &cName, NULL, NULL, NULL, &LastWriteTime) == ERROR_SUCCESS) {
284 Entry* pEntry = CreateEntry(entry, hKey, Name);
285 pEntry->up = entry;
286 pEntry->hKey = hKey;
287 pEntry->bKey = TRUE;
288 pEntry->level = 2;
289 pEntry->hTreeItem = AddEntryToTree(hWnd, pEntry, NULL);
290 cName = MAX_NAME_LEN;
291 ++dwIndex;
292 }
293 RegCloseKey(hKey);
294 }
295 }
296 expanding = FALSE;
297 return TRUE;
298 }
299
300 /*
301 static BOOL OnSelChanged(NMTREEVIEW* pnmtv)
302 {
303 LPARAM parm = pnmtv->itemNew.lParam;
304 ChildWnd* child = (ChildWnd*)pnmtv->itemNew.lParam;
305 return TRUE;
306 }
307 */
308
309 ////////////////////////////////////////////////////////////////////////////////
310 static WNDPROC g_orgTreeWndProc;
311
312 static LRESULT CALLBACK TreeWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
313 {
314 // ChildWnd* child = (ChildWnd*)GetWindowLong(GetParent(hWnd), GWL_USERDATA);
315 // ASSERT(child);
316
317 switch (message) {
318 case WM_NOTIFY:
319 switch (((LPNMHDR)lParam)->code) {
320 case TVM_EXPAND:
321 //return OnExpand((int)wParam, (HTREEITEM*)lParam);
322 OnExpand((int)wParam, (HTREEITEM*)lParam);
323 break;
324 case TVN_GETDISPINFO:
325 OnGetDispInfo((NMTVDISPINFO*)lParam);
326 break;
327 case TVN_ITEMEXPANDING:
328 return OnExpanding(hWnd, (NMTREEVIEW*)lParam);
329 break;
330 // case TVN_SELCHANGED:
331 // return OnSelChanged((NMTREEVIEW*)lParam);
332 // break;
333 #if 0
334 case TVN_SINGLEEXPAND:
335 TRACE("TreeWndProc(...) TVN_SINGLEEXPAND\n");
336 //lpnmtv = (LPNMTREEVIEW)lParam;
337 //return TVNRET_DEFAULT;
338 // return TVNRET_SKIPOLD; // Skip default processing of the item being unselected.
339 // return TVNRET_SKIPNEW; // Skip default processing of the item being selected.
340 break;
341 #endif
342 }
343 // return 0;
344 break;
345 case WM_KEYDOWN:
346 if (wParam == VK_TAB) {
347 //SetFocus(child->nFocusPanel ? child->left.hWnd: child->right.hWnd);
348 }
349 break;
350 }
351 return CallWindowProc(g_orgTreeWndProc, hWnd, message, wParam, lParam);
352 }
353
354 // CreateTreeView - creates a tree view control.
355 // Returns the handle to the new control if successful, or NULL otherwise.
356 // hwndParent - handle to the control's parent window.
357
358 HWND CreateTreeView(HWND hwndParent, int id, Root* pRoot)
359 {
360 RECT rcClient;
361 HWND hwndTV;
362 // Entry* entry = ;
363
364 // Get the dimensions of the parent window's client area, and create the tree view control.
365 GetClientRect(hwndParent, &rcClient);
366 hwndTV = CreateWindowEx(0, WC_TREEVIEW, _T("Tree View"),
367 WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT,
368 0, 0, rcClient.right, rcClient.bottom,
369 hwndParent, (HMENU)id, hInst, NULL);
370 // Initialize the image list, and add items to the control.
371 if (!InitTreeViewImageLists(hwndTV) || !InitTreeViewItems(hwndTV, pRoot)) {
372 DestroyWindow(hwndTV);
373 return NULL;
374 }
375 SetWindowLong(hwndTV, GWL_USERDATA, (LPARAM)0);
376 g_orgTreeWndProc = SubclassWindow(hwndTV, TreeWndProc);
377 //SendMessage(hwndTV, WM_SETFONT, (WPARAM)Globals.hFont, FALSE);
378 return hwndTV;
379 }
380