[MSCONFIG_NEW]
[reactos.git] / reactos / base / applications / msconfig_new / toolspage.cpp
1 /*
2 * PROJECT: ReactOS Applications
3 * LICENSE: LGPL - See COPYING in the top level directory
4 * FILE: base/applications/msconfig_new/toolspage.cpp
5 * PURPOSE: Tools page message handler
6 * COPYRIGHT: Copyright 2005-2006 Christoph von Wittich <Christoph@ApiViewer.de>
7 * Copyright 2011-2012 Hermes BELUSCA - MAITO <hermes.belusca@sfr.fr>
8 */
9
10 #include "precomp.h"
11 #include "xmldomparser.hpp"
12 #include "utils.h"
13 #include "listviewfuncs.h"
14
15 static HWND hToolsPage = NULL;
16 static HWND hToolsListCtrl = NULL;
17 static int iSortedColumn = 0;
18
19 struct TOOL
20 {
21 TOOL(const _bstr_t& Command,
22 const _bstr_t& DefParam,
23 const _bstr_t& AdvParam) :
24 m_Command(Command),
25 m_DefParam(DefParam),
26 m_AdvParam(AdvParam)
27 { }
28
29 ~TOOL(void)
30 { }
31
32 DWORD Run(BOOL bUseAdvParams)
33 {
34 return RunCommand(m_Command, bUseAdvParams ? m_AdvParam : m_DefParam, SW_SHOW);
35 }
36
37 _bstr_t m_Command;
38 _bstr_t m_DefParam;
39 _bstr_t m_AdvParam;
40 };
41
42 static void AddTool(IXMLDOMElement*, BOOL);
43
44 static HRESULT
45 ParseToolsList(IXMLDOMDocument* pXMLDom, BOOL bIsStandard)
46 {
47 static const _bstr_t XMLFileTag(L"MSCONFIGTOOLFILE");
48 static const _bstr_t XMLToolsTag(L"MSCONFIGTOOLS");
49
50 HRESULT hr = S_OK;
51
52 IXMLDOMNode *pIterator = NULL, *pTmp = NULL;
53 IXMLDOMElement* pEl = NULL;
54 DOMNodeType type;
55 _bstr_t tagName;
56
57 if (!pXMLDom)
58 return E_POINTER; // E_INVALIDARG
59
60 pXMLDom->get_documentElement(&pEl);
61
62 pEl->get_tagName(&tagName.GetBSTR());
63 _wcsupr(tagName);
64 if (tagName == XMLFileTag)
65 {
66 pEl->get_firstChild(&pIterator); SAFE_RELEASE(pEl);
67 while (pIterator)
68 {
69 pIterator->get_nodeType(&type);
70 if (type == NODE_ELEMENT)
71 {
72 pIterator->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pEl) /* IID_PPV_ARGS(&pEl) */);
73
74 pEl->get_tagName(&tagName.GetBSTR());
75 _wcsupr(tagName);
76 if (tagName == XMLToolsTag)
77 {
78 pEl->get_firstChild(&pIterator); SAFE_RELEASE(pEl);
79 while (pIterator)
80 {
81 pIterator->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pEl) /* IID_PPV_ARGS(&pEl) */);
82 AddTool(pEl, bIsStandard);
83 SAFE_RELEASE(pEl);
84
85 pIterator->get_nextSibling(&pTmp);
86 SAFE_RELEASE(pIterator); pIterator = pTmp;
87 }
88 // SAFE_RELEASE(pIterator);
89
90 break;
91 }
92
93 SAFE_RELEASE(pEl);
94 }
95
96 pIterator->get_nextSibling(&pTmp);
97 SAFE_RELEASE(pIterator); pIterator = pTmp;
98 }
99 // SAFE_RELEASE(pIterator);
100 }
101 else if (tagName == XMLToolsTag)
102 {
103 pEl->get_firstChild(&pIterator); SAFE_RELEASE(pEl);
104 while (pIterator)
105 {
106 pIterator->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pEl) /* IID_PPV_ARGS(&pEl) */);
107 AddTool(pEl, bIsStandard);
108 SAFE_RELEASE(pEl);
109
110 pIterator->get_nextSibling(&pTmp);
111 SAFE_RELEASE(pIterator); pIterator = pTmp;
112 }
113 // SAFE_RELEASE(pIterator);
114 }
115
116 SAFE_RELEASE(pEl);
117
118 return hr;
119 }
120
121 static void
122 AddItem(BOOL bIsStandard, const _bstr_t& name, const _bstr_t& descr, TOOL* tool)
123 {
124 LPTSTR lpszStandard;
125 LVITEM item = {};
126
127 assert(tool);
128
129 item.mask = LVIF_TEXT | LVIF_PARAM;
130 item.lParam = (LPARAM)tool;
131
132 item.pszText = (LPWSTR)name;
133 item.iSubItem = 0;
134 // item.iItem = ListView_GetItemCount(hToolsListCtrl);
135
136 ListView_InsertItem(hToolsListCtrl, &item);
137
138 if (bIsStandard)
139 {
140 lpszStandard = LoadResourceString(hInst, IDS_YES);
141 ListView_SetItemText(hToolsListCtrl, item.iItem, 1, lpszStandard);
142 MemFree(lpszStandard);
143 }
144 else
145 {
146 lpszStandard = LoadResourceString(hInst, IDS_NO);
147 ListView_SetItemText(hToolsListCtrl, item.iItem, 1, lpszStandard);
148 MemFree(lpszStandard);
149 }
150
151 ListView_SetItemText(hToolsListCtrl, item.iItem, 2, (LPWSTR)descr);
152 }
153
154 static void
155 AddTool(IXMLDOMElement* pXMLTool, BOOL bIsStandard)
156 {
157 TOOL* tool;
158 _variant_t varLocID, varName, varPath,
159 varDefOpt, varAdvOpt, varHelp;
160
161 assert(pXMLTool);
162
163 pXMLTool->getAttribute(_bstr_t(L"_locID") , &varLocID );
164 pXMLTool->getAttribute(_bstr_t(L"NAME") , &varName );
165 pXMLTool->getAttribute(_bstr_t(L"PATH") , &varPath );
166 pXMLTool->getAttribute(_bstr_t(L"DEFAULT_OPT"), &varDefOpt);
167 pXMLTool->getAttribute(_bstr_t(L"ADV_OPT") , &varAdvOpt);
168 pXMLTool->getAttribute(_bstr_t(L"HELP") , &varHelp );
169
170 // TODO: check if the tool really exists... ??
171
172 tool = new TOOL(_bstr_t(varPath), _bstr_t(varDefOpt), _bstr_t(varAdvOpt));
173 AddItem(bIsStandard, _bstr_t(varName), _bstr_t(varHelp), tool);
174 }
175
176 static void
177 FillListView(void)
178 {
179 IXMLDOMDocument* pXMLDom = NULL;
180
181 if (!SUCCEEDED(InitXMLDOMParser()))
182 return;
183
184 if (SUCCEEDED(CreateAndInitXMLDOMDocument(&pXMLDom)))
185 {
186 // Load the internal tools list.
187 if (LoadXMLDocumentFromResource(pXMLDom, L"MSCFGTL.XML"))
188 ParseToolsList(pXMLDom, TRUE);
189
190 // Try to load the user-provided tools list. If it doesn't exist,
191 // then the second list-view's column "Standard" tool is removed.
192 if (LoadXMLDocumentFromFile(pXMLDom, L"MSCFGTLC.XML", TRUE))
193 ParseToolsList(pXMLDom, FALSE);
194 else
195 ListView_DeleteColumn(hToolsListCtrl, 1);
196 }
197
198 SAFE_RELEASE(pXMLDom);
199 UninitXMLDOMParser();
200 }
201
202 static size_t
203 BuildCommandLine(LPWSTR lpszDest, LPCWSTR lpszCmdLine, LPCWSTR lpszParam, size_t bufSize)
204 {
205 size_t numOfChars = 0; // The null character is counted in ExpandEnvironmentStrings(...).
206 // TODO: Take into account the "plus one" for numOfChars for ANSI version (see MSDN for more details).
207
208 if (lpszCmdLine && *lpszCmdLine)
209 {
210 numOfChars += ExpandEnvironmentStringsW(lpszCmdLine, NULL, 0);
211 if (lpszDest)
212 ExpandEnvironmentStringsW(lpszCmdLine, lpszDest, (DWORD)bufSize); // TODO: size_t to DWORD conversion !
213
214 if (lpszParam && *lpszParam)
215 {
216 ++numOfChars;
217 if (lpszDest)
218 wcscat(lpszDest, L" ");
219 }
220 }
221
222 if (lpszParam && *lpszParam)
223 {
224 numOfChars += wcslen(lpszParam);
225 if (lpszDest)
226 wcscat(lpszDest, lpszParam);
227 }
228
229 return numOfChars;
230 }
231
232 #define Button_IsEnabled(hwndCtl) IsWindowEnabled((hwndCtl))
233
234 static void Update_States(int iSelectedItem)
235 {
236 TOOL* tool;
237 LVITEM item = {};
238
239 assert(hToolsPage);
240
241 item.mask = LVIF_PARAM;
242 item.iItem = iSelectedItem;
243
244 if (ListView_GetItem(hToolsListCtrl, &item)) // (item.iItem > -1) // TODO: corriger ailleurs ce genre de code...
245 {
246 LPTSTR lpszCmdLine = NULL;
247 size_t numOfChars = 0;
248 tool = reinterpret_cast<TOOL*>(item.lParam);
249
250 ListView_EnsureVisible(hToolsListCtrl, item.iItem, FALSE);
251
252 Button_Enable(GetDlgItem(hToolsPage, IDC_BTN_RUN), TRUE);
253
254 if (!*(wchar_t*)tool->m_AdvParam)
255 {
256 ShowWindow(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT), SW_HIDE);
257 Button_Enable(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT), FALSE);
258 }
259 else
260 {
261 Button_Enable(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT), TRUE);
262 ShowWindow(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT), SW_NORMAL);
263 }
264
265 if ( (Button_IsEnabled(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT))) &&
266 (Button_GetCheck(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT)) == BST_CHECKED) )
267 {
268 numOfChars = BuildCommandLine(NULL, tool->m_Command, tool->m_AdvParam, 0);
269 lpszCmdLine = new WCHAR[numOfChars];
270 BuildCommandLine(lpszCmdLine, tool->m_Command, tool->m_AdvParam, numOfChars);
271 }
272 else
273 {
274 numOfChars = BuildCommandLine(NULL, tool->m_Command, tool->m_DefParam, 0);
275 lpszCmdLine = new WCHAR[numOfChars];
276 BuildCommandLine(lpszCmdLine, tool->m_Command, tool->m_DefParam, numOfChars);
277 }
278
279 SendDlgItemMessage(hToolsPage, IDC_TOOLS_CMDLINE, WM_SETTEXT, 0, (LPARAM)lpszCmdLine);
280
281 delete[] lpszCmdLine;
282 }
283 else
284 {
285 ShowWindow(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT), SW_HIDE);
286 Button_Enable(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT), FALSE);
287 Button_Enable(GetDlgItem(hToolsPage, IDC_BTN_RUN), FALSE);
288 }
289 }
290
291 static BOOL RunSelectedTool(VOID)
292 {
293 BOOL Success = FALSE;
294 BOOL bUseAdvParams;
295
296 LVITEM item = {};
297 item.mask = LVIF_PARAM;
298 item.iItem = ListView_GetSelectionMark(hToolsListCtrl);
299 ListView_GetItem(hToolsListCtrl, &item);
300
301 if (ListView_GetItem(hToolsListCtrl, &item)) // (item.iItem > -1) // TODO: corriger ailleurs ce genre de code...
302 {
303 if ( (Button_IsEnabled(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT))) &&
304 (Button_GetCheck(GetDlgItem(hToolsPage, IDC_CBX_TOOLS_ADVOPT)) == BST_CHECKED) )
305 bUseAdvParams = TRUE;
306 else
307 bUseAdvParams = FALSE;
308
309 // Values greater (strictly) than 32 indicate success (see MSDN documentation for ShellExecute(...) API).
310 Success = (reinterpret_cast<TOOL*>(item.lParam)->Run(bUseAdvParams) > 32);
311 }
312
313 return Success;
314 }
315
316 extern "C" {
317
318 INT_PTR CALLBACK
319 ToolsPageWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
320 {
321 switch (message)
322 {
323 case WM_INITDIALOG:
324 {
325 hToolsPage = hDlg;
326 hToolsListCtrl = GetDlgItem(hToolsPage, IDC_TOOLS_LIST);
327
328 //
329 // Initialize the styles.
330 //
331 DWORD dwStyle = ListView_GetExtendedListViewStyle(hToolsListCtrl);
332 ListView_SetExtendedListViewStyle(hToolsListCtrl, dwStyle | LVS_EX_FULLROWSELECT);
333 /** SetWindowTheme(hToolsListCtrl, _T("Explorer"), NULL); // TODO: activate this only if Windows >= XP **/
334
335 //
336 // Initialize the application page's controls.
337 //
338 LVCOLUMN column = {};
339
340 // First column : Tool's name.
341 column.mask = LVCF_TEXT | LVCF_WIDTH;
342 column.pszText = LoadResourceString(hInst, IDS_TOOLS_COLUMN_NAME);
343 column.cx = 150;
344 ListView_InsertColumn(hToolsListCtrl, 0, &column);
345 MemFree(column.pszText);
346
347 // Second column : Whether the tool is a standard one or not.
348 column.mask = LVCF_TEXT | LVCF_WIDTH;
349 column.pszText = LoadResourceString(hInst, IDS_TOOLS_COLUMN_STANDARD);
350 column.cx = 60;
351 ListView_InsertColumn(hToolsListCtrl, 1, &column);
352 MemFree(column.pszText);
353
354 // Third column : Description.
355 column.mask = LVCF_TEXT | LVCF_WIDTH;
356 column.pszText = LoadResourceString(hInst, IDS_TOOLS_COLUMN_DESCR);
357 column.cx = 500;
358 ListView_InsertColumn(hToolsListCtrl, 2, &column);
359 MemFree(column.pszText);
360
361 //
362 // Populate and sort the list.
363 //
364 FillListView();
365 ListView_Sort(hToolsListCtrl, 0);
366
367 // Force an update in case of an empty list (giving focus on it when empty won't emit a LVN_ITEMCHANGED message).
368 Update_States(-1 /* Wrong index to initialize all the controls with their default state (i.e. disabled) */);
369
370 PropSheet_UnChanged(GetParent(hToolsPage), hToolsPage);
371
372 return TRUE;
373 }
374
375 case WM_DESTROY:
376 {
377 LVITEM lvitem = {};
378 lvitem.mask = LVIF_PARAM;
379 lvitem.iItem = -1; // From the beginning.
380
381 while ((lvitem.iItem = ListView_GetNextItem(hToolsListCtrl, lvitem.iItem, LVNI_ALL)) != -1)
382 {
383 // ListView_Update(); // Updates a list-view item.
384 // ListView_FindItem(); // peut être intéressant pour faire de la recherche itérative à partir du nom (ou partie du...) de l'item.
385
386 ListView_GetItem(hToolsListCtrl, &lvitem);
387
388 delete reinterpret_cast<TOOL*>(lvitem.lParam);
389 lvitem.lParam = NULL;
390 }
391 ListView_DeleteAllItems(hToolsListCtrl);
392
393 return 0;
394 }
395
396 case WM_COMMAND:
397 {
398 switch (LOWORD(wParam))
399 {
400 case IDC_BTN_RUN:
401 {
402 RunSelectedTool();
403 return TRUE;
404 }
405
406 case IDC_CBX_TOOLS_ADVOPT:
407 {
408 Update_States(ListView_GetSelectionMark(hToolsListCtrl));
409 return TRUE;
410 }
411
412 default:
413 return FALSE;
414 }
415 return FALSE;
416 }
417
418 case WM_NOTIFY:
419 {
420 if (((LPNMHDR)lParam)->hwndFrom == hToolsListCtrl)
421 {
422 switch (((LPNMHDR)lParam)->code)
423 {
424 case LVN_ITEMCHANGED:
425 {
426 if ( (((LPNMLISTVIEW)lParam)->uChanged & LVIF_STATE) && /* The state has changed */
427 (((LPNMLISTVIEW)lParam)->uNewState & LVIS_SELECTED) /* The item has been (de)selected */ )
428 {
429 Update_States(((LPNMLISTVIEW)lParam)->iItem);
430 }
431
432 return TRUE;
433 }
434
435 case NM_DBLCLK:
436 case NM_RDBLCLK:
437 {
438 RunSelectedTool();
439 return TRUE;
440 }
441
442 case LVN_COLUMNCLICK:
443 {
444 int iSortingColumn = ((LPNMLISTVIEW)lParam)->iSubItem;
445
446 ListView_SortEx(hToolsListCtrl, iSortingColumn, iSortedColumn);
447 iSortedColumn = iSortingColumn;
448
449 return TRUE;
450 }
451
452 default:
453 break;
454 }
455 }
456 else
457 {
458 switch (((LPNMHDR)lParam)->code)
459 {
460 case PSN_APPLY:
461 {
462 // Since there are nothing to modify, applying modifications
463 // cannot return any error.
464 SetWindowLongPtr(hToolsPage, DWLP_MSGRESULT, PSNRET_NOERROR);
465 PropSheet_UnChanged(GetParent(hToolsPage), hToolsPage);
466 return TRUE;
467 }
468
469 case PSN_HELP:
470 {
471 MessageBoxW(hToolsPage, L"Help not implemented yet!", L"Help", MB_ICONINFORMATION | MB_OK);
472 return TRUE;
473 }
474
475 case PSN_KILLACTIVE: // Is going to lose activation.
476 {
477 // Changes are always valid of course.
478 SetWindowLongPtr(hToolsPage, DWLP_MSGRESULT, FALSE);
479 return TRUE;
480 }
481
482 case PSN_QUERYCANCEL:
483 {
484 // Allows cancellation since there are nothing to cancel...
485 SetWindowLongPtr(hToolsPage, DWLP_MSGRESULT, FALSE);
486 return TRUE;
487 }
488
489 case PSN_QUERYINITIALFOCUS:
490 {
491 // Give the focus on and select the first item.
492 ListView_SetItemState(hToolsListCtrl, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
493
494 SetWindowLongPtr(hToolsPage, DWLP_MSGRESULT, (LONG_PTR)hToolsListCtrl);
495 return TRUE;
496 }
497
498 //
499 // DO NOT TOUCH THESE NEXT MESSAGES, THEY ARE OK LIKE THIS...
500 //
501 case PSN_RESET: // Perform final cleaning, called before WM_DESTROY.
502 return TRUE;
503
504 case PSN_SETACTIVE: // Is going to gain activation.
505 {
506 SetWindowLongPtr(hToolsPage, DWLP_MSGRESULT, 0);
507 return TRUE;
508 }
509
510 default:
511 break;
512 }
513 }
514
515 return FALSE;
516 }
517
518 default:
519 return FALSE;
520 }
521
522 // return FALSE;
523 }
524
525 }
526
527 /* EOF */