1 /*
2  * PROJECT:     ReactOS API Test GUI
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:
5  * PURPOSE:     browse dialog implementation
6  * COPYRIGHT:   Copyright 2008 Ged Murphy <gedmurphy@reactos.org>
7  *
8  */
9 
10 #include <precomp.h>
11 
12 #define EXE_SEARCH_DIR L"\\Debug\\testexes\\*"
13 #define IL_MAIN 0
14 #define IL_TEST 1
15 
16 #define HAS_NO_CHILD 0
17 #define HAS_CHILD 1
18 
19 
20 static INT
GetNumberOfExesInFolder(LPWSTR lpFolder)21 GetNumberOfExesInFolder(LPWSTR lpFolder)
22 {
23     HANDLE hFind;
24     WIN32_FIND_DATAW findFileData;
25     INT numFiles = 0;
26 
27     hFind = FindFirstFileW(lpFolder,
28                            &findFileData);
29     if (hFind == INVALID_HANDLE_VALUE)
30     {
31         DisplayError(GetLastError());
32         return 0;
33     }
34 
35     do
36     {
37         if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
38         {
39             numFiles++;
40         }
41     } while (FindNextFile(hFind, &findFileData) != 0);
42 
43     return numFiles;
44 }
45 
46 static INT
GetListOfTestExes(PMAIN_WND_INFO pInfo)47 GetListOfTestExes(PMAIN_WND_INFO pInfo)
48 {
49     HANDLE hFind;
50     WIN32_FIND_DATAW findFileData;
51     WCHAR szExePath[MAX_PATH];
52     LPWSTR ptr;
53     INT numFiles = 0;
54     INT len;
55 
56     len = GetCurrentDirectoryW(MAX_PATH, szExePath);
57     if (!len) return 0;
58 
59     wcsncat(szExePath, EXE_SEARCH_DIR, MAX_PATH - (len + 1));
60 
61     numFiles = GetNumberOfExesInFolder(szExePath);
62     if (!numFiles) return 0;
63 
64     pInfo->lpExeList = HeapAlloc(GetProcessHeap(),
65                                  0,
66                                  numFiles * (MAX_PATH * sizeof(WCHAR)));
67     if (!pInfo->lpExeList)
68         return 0;
69 
70     hFind = FindFirstFileW(szExePath,
71                            &findFileData);
72     if (hFind == INVALID_HANDLE_VALUE)
73     {
74         DisplayError(GetLastError());
75         HeapFree(GetProcessHeap(), 0, pInfo->lpExeList);
76         return 0;
77     }
78 
79     /* remove the glob */
80     ptr = wcschr(szExePath, L'*');
81     if (ptr)
82         *ptr = L'\0';
83 
84     /* don't modify our base pointer */
85     ptr = pInfo->lpExeList;
86 
87     do
88     {
89         if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
90         {
91             /* set the path */
92             wcscpy(ptr, szExePath);
93 
94             /* tag the file onto the path */
95             len = MAX_PATH - (wcslen(ptr) + 1);
96             wcsncat(ptr, findFileData.cFileName, len);
97 
98             /* move the pointer along by MAX_PATH */
99             ptr += MAX_PATH;
100         }
101     } while (FindNextFile(hFind, &findFileData) != 0);
102 
103     return numFiles;
104 }
105 
106 static BOOL
NodeHasChild(PMAIN_WND_INFO pInfo,HTREEITEM hItem)107 NodeHasChild(PMAIN_WND_INFO pInfo,
108              HTREEITEM hItem)
109 {
110     TV_ITEM tvItem;
111 
112     tvItem.hItem = hItem;
113     tvItem.mask = TVIF_CHILDREN;
114 
115     (void)TreeView_GetItem(pInfo->hBrowseTV, &tvItem);
116 
117     return (tvItem.cChildren == 1);
118 }
119 
120 static VOID
FreeItemTag(PMAIN_WND_INFO pInfo,HTREEITEM hItem)121 FreeItemTag(PMAIN_WND_INFO pInfo,
122             HTREEITEM hItem)
123 {
124     TV_ITEM tvItem;
125 
126     tvItem.hItem = hItem;
127     tvItem.mask = TVIF_PARAM;
128 
129     (void)TreeView_GetItem(pInfo->hBrowseTV, &tvItem);
130 
131     HeapFree(GetProcessHeap(),
132              0,
133              (PTEST_ITEM)tvItem.lParam);
134 }
135 
136 static VOID
TraverseTreeView(PMAIN_WND_INFO pInfo,HTREEITEM hItem)137 TraverseTreeView(PMAIN_WND_INFO pInfo,
138                  HTREEITEM hItem)
139 {
140     while (NodeHasChild(pInfo, hItem))
141     {
142         HTREEITEM hChildItem;
143 
144         FreeItemTag(pInfo, hItem);
145 
146         hChildItem = TreeView_GetChild(pInfo->hBrowseTV,
147                                        hItem);
148 
149         TraverseTreeView(pInfo,
150                          hChildItem);
151 
152         hItem = TreeView_GetNextSibling(pInfo->hBrowseTV,
153                                         hItem);
154     }
155 
156     if (hItem)
157     {
158         /* loop the child items and free the tags */
159         while (TRUE)
160         {
161             HTREEITEM hOldItem;
162 
163             FreeItemTag(pInfo, hItem);
164             hOldItem = hItem;
165             hItem = TreeView_GetNextSibling(pInfo->hBrowseTV,
166                                             hItem);
167             if (hItem == NULL)
168             {
169                 hItem = hOldItem;
170                 break;
171             }
172         }
173 
174         hItem = TreeView_GetParent(pInfo->hBrowseTV,
175                                    hItem);
176     }
177 }
178 
179 static HTREEITEM
InsertIntoTreeView(HWND hTreeView,HTREEITEM hRoot,LPWSTR lpLabel,LPARAM Tag,INT Image,INT Child)180 InsertIntoTreeView(HWND hTreeView,
181                    HTREEITEM hRoot,
182                    LPWSTR lpLabel,
183                    LPARAM Tag,
184                    INT Image,
185                    INT Child)
186 {
187     TV_ITEM tvi;
188     TV_INSERTSTRUCT tvins;
189 
190     ZeroMemory(&tvi, sizeof(tvi));
191     ZeroMemory(&tvins, sizeof(tvins));
192 
193     tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_CHILDREN | TVIF_SELECTEDIMAGE;
194     tvi.pszText = lpLabel;
195     tvi.cchTextMax = lstrlen(lpLabel);
196     tvi.lParam = Tag;
197     tvi.iImage = Image;
198     tvi.iSelectedImage = Image;
199     tvi.cChildren = Child;
200 
201     tvins.item = tvi;
202     tvins.hParent = hRoot;
203 
204     return TreeView_InsertItem(hTreeView, &tvins);
205 }
206 
207 static PTEST_ITEM
BuildTestItemData(LPWSTR lpName,LPWSTR lpRunCmd)208 BuildTestItemData(LPWSTR lpName,
209                   LPWSTR lpRunCmd)
210 {
211     PTEST_ITEM pItem;
212 
213     pItem = (PTEST_ITEM)HeapAlloc(GetProcessHeap(),
214                                   0,
215                                   sizeof(TEST_ITEM));
216     if (pItem)
217     {
218         if (lpName)
219         {
220             wcsncpy(pItem->szName, lpName, MAX_PATH);
221         }
222         if (lpRunCmd)
223         {
224             wcsncpy(pItem->szRunCmd, lpRunCmd, MAX_RUN_CMD);
225         }
226     }
227 
228     return pItem;
229 }
230 
231 static VOID
PopulateTreeView(PMAIN_WND_INFO pInfo)232 PopulateTreeView(PMAIN_WND_INFO pInfo)
233 {
234     HTREEITEM hRoot;
235     HIMAGELIST hImgList;
236     PTEST_ITEM pTestItem;
237     LPWSTR lpExePath;
238     LPWSTR lpTestName;
239     INT i;
240 
241     pInfo->hBrowseTV = GetDlgItem(pInfo->hBrowseDlg, IDC_TREEVIEW);
242 
243     (void)TreeView_DeleteAllItems(pInfo->hBrowseTV);
244 
245     hImgList = InitImageList(IDI_ICON,
246                              IDI_TESTS,
247                              16,
248                              16);
249     if (!hImgList) return;
250 
251     (void)TreeView_SetImageList(pInfo->hBrowseTV,
252                                 hImgList,
253                                 TVSIL_NORMAL);
254 
255     pTestItem = BuildTestItemData(L"Full", L"runall");
256 
257     /* insert the root item into the tree */
258     hRoot = InsertIntoTreeView(pInfo->hBrowseTV,
259                                NULL,
260                                L"Full",
261                                (LPARAM)pTestItem,
262                                IL_MAIN,
263                                HAS_CHILD);
264 
265     for (i = 0; i < pInfo->numExes; i++)
266     {
267         HTREEITEM hParent;
268         LPWSTR lpStr;
269 
270         lpExePath = pInfo->lpExeList + (MAX_PATH * i);
271 
272         lpTestName = wcsrchr(lpExePath, L'\\');
273         if (lpTestName)
274         {
275             lpTestName++;
276 
277             lpStr = wcschr(lpTestName, L'_');
278             if (lpStr)
279             {
280                 //FIXME: Query the test name from the exe directly
281 
282                 pTestItem = BuildTestItemData(lpTestName, lpExePath);
283 
284                 hParent = InsertIntoTreeView(pInfo->hBrowseTV,
285                                              hRoot,
286                                              lpTestName,
287                                              (LPARAM)pTestItem,
288                                              IL_TEST,
289                                              HAS_CHILD);
290             }
291         }
292     }
293 
294     if (hRoot)
295     {
296         TreeView_Expand(pInfo->hBrowseTV,
297                         hRoot,
298                         TVE_EXPAND);
299     }
300 }
301 
302 static VOID
PopulateTestList(PMAIN_WND_INFO pInfo)303 PopulateTestList(PMAIN_WND_INFO pInfo)
304 {
305     pInfo->numExes = GetListOfTestExes(pInfo);
306     if (pInfo->numExes)
307     {
308         PopulateTreeView(pInfo);
309     }
310 }
311 
312 static BOOL
OnInitBrowseDialog(HWND hDlg,LPARAM lParam)313 OnInitBrowseDialog(HWND hDlg,
314                    LPARAM lParam)
315 {
316     PMAIN_WND_INFO pInfo;
317 
318     pInfo = (PMAIN_WND_INFO)lParam;
319 
320     pInfo->hBrowseDlg = hDlg;
321 
322     SetWindowLongPtr(hDlg,
323                      GWLP_USERDATA,
324                      (LONG_PTR)pInfo);
325 
326     PopulateTestList(pInfo);
327 
328     return TRUE;
329 }
330 
331 BOOL CALLBACK
BrowseDlgProc(HWND hDlg,UINT Message,WPARAM wParam,LPARAM lParam)332 BrowseDlgProc(HWND hDlg,
333               UINT Message,
334               WPARAM wParam,
335               LPARAM lParam)
336 {
337     PMAIN_WND_INFO pInfo;
338 
339     /* Get the window context */
340     pInfo = (PMAIN_WND_INFO)GetWindowLongPtr(hDlg,
341                                              GWLP_USERDATA);
342     if (pInfo == NULL && Message != WM_INITDIALOG)
343     {
344         goto HandleDefaultMessage;
345     }
346 
347     switch(Message)
348     {
349         case WM_INITDIALOG:
350             return OnInitBrowseDialog(hDlg, lParam);
351 
352         case WM_COMMAND:
353         {
354             switch (LOWORD(wParam))
355             {
356                 case IDOK:
357                 {
358                     TV_ITEM tvItem;
359 
360                     tvItem.hItem = TreeView_GetSelection(pInfo->hBrowseTV);
361                     tvItem.mask = TVIF_PARAM;
362 
363                     if (TreeView_GetItem(pInfo->hBrowseTV, &tvItem))
364                     {
365                         PTEST_ITEM pItem;
366 
367                         pItem = (PTEST_ITEM)tvItem.lParam;
368                         if (pItem)
369                             CopyMemory(&pInfo->SelectedTest, pItem, sizeof(TEST_ITEM));
370 
371                         EndDialog(hDlg,
372                                   LOWORD(wParam));
373                     }
374                     else
375                     {
376                         DisplayMessage(L"Please select an item");
377                     }
378 
379                     return TRUE;
380                 }
381 
382                 case IDCANCEL:
383                 {
384                     HeapFree(GetProcessHeap(), 0, pInfo->lpExeList);
385                     pInfo->lpExeList = NULL;
386 
387                     EndDialog(hDlg,
388                               LOWORD(wParam));
389 
390                     return TRUE;
391                 }
392             }
393 
394             break;
395         }
396 
397         case WM_DESTROY:
398         {
399             HTREEITEM hItem = TreeView_GetRoot(pInfo->hBrowseTV);
400 
401             TraverseTreeView(pInfo, hItem);
402 
403             pInfo->hBrowseDlg = NULL;
404 
405             break;
406         }
407 
408 HandleDefaultMessage:
409         default:
410             return FALSE;
411     }
412 
413     return FALSE;
414 }
415