[RAPPS] CMainWindow: Make SelectedEnumType a member
[reactos.git] / base / applications / rapps / gui.cpp
1 /*
2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * FILE: base/applications/rapps/gui.cpp
5 * PURPOSE: GUI classes for RAPPS
6 * COPYRIGHT: Copyright 2015 David Quintana (gigaherz@gmail.com)
7 * Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org)
8 */
9 #include "rapps.h"
10
11 #include "rapps.h"
12 #include "rosui.h"
13 #include "crichedit.h"
14
15 #include <shlobj_undoc.h>
16 #include <shlguid_undoc.h>
17
18 #include <atlbase.h>
19 #include <atlcom.h>
20 #include <atlwin.h>
21 #include <wininet.h>
22 #include <shellutils.h>
23 #include <rosctrls.h>
24
25 #define SEARCH_TIMER_ID 'SR'
26 #define LISTVIEW_ICON_SIZE 24
27 #define TREEVIEW_ICON_SIZE 24
28
29 HWND hListView = NULL;
30
31 INT GetSystemColorDepth()
32 {
33 DEVMODEW pDevMode;
34 INT ColorDepth;
35
36 pDevMode.dmSize = sizeof(pDevMode);
37 pDevMode.dmDriverExtra = 0;
38
39 if (!EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &pDevMode))
40 {
41 /* TODO: Error message */
42 return ILC_COLOR;
43 }
44
45 switch (pDevMode.dmBitsPerPel)
46 {
47 case 32: ColorDepth = ILC_COLOR32; break;
48 case 24: ColorDepth = ILC_COLOR24; break;
49 case 16: ColorDepth = ILC_COLOR16; break;
50 case 8: ColorDepth = ILC_COLOR8; break;
51 case 4: ColorDepth = ILC_COLOR4; break;
52 default: ColorDepth = ILC_COLOR; break;
53 }
54
55 return ColorDepth;
56 }
57
58 class CAppRichEdit:
59 public CUiWindow<CRichEdit>
60 {
61 private:
62 VOID LoadAndInsertText(UINT uStringID,
63 const ATL::CStringW& szText,
64 DWORD StringFlags,
65 DWORD TextFlags)
66 {
67 ATL::CStringW szLoadedText;
68 if (!szText.IsEmpty() && szLoadedText.LoadStringW(uStringID))
69 {
70 InsertText(szLoadedText, StringFlags);
71 InsertText(szText, TextFlags);
72 }
73 }
74
75 VOID LoadAndInsertText(UINT uStringID,
76 DWORD StringFlags)
77 {
78 ATL::CStringW szLoadedText;
79 if (szLoadedText.LoadStringW(uStringID))
80 {
81 InsertText(L"\n", 0);
82 InsertText(szLoadedText, StringFlags);
83 InsertText(L"\n", 0);
84 }
85 }
86
87 VOID InsertVersionInfo(CAvailableApplicationInfo* Info)
88 {
89 if (Info->IsInstalled())
90 {
91 if (Info->HasInstalledVersion())
92 {
93 if (Info->HasUpdate())
94 LoadAndInsertText(IDS_STATUS_UPDATE_AVAILABLE, CFE_ITALIC);
95 else
96 LoadAndInsertText(IDS_STATUS_INSTALLED, CFE_ITALIC);
97
98 LoadAndInsertText(IDS_AINFO_VERSION, Info->m_szInstalledVersion, CFE_BOLD, 0);
99 }
100 else
101 {
102 LoadAndInsertText(IDS_STATUS_INSTALLED, CFE_ITALIC);
103 }
104 }
105 else
106 {
107 LoadAndInsertText(IDS_STATUS_NOTINSTALLED, CFE_ITALIC);
108 }
109
110 LoadAndInsertText(IDS_AINFO_AVAILABLEVERSION, Info->m_szVersion, CFE_BOLD, 0);
111 }
112
113 VOID InsertLicenseInfo(CAvailableApplicationInfo* Info)
114 {
115 ATL::CStringW szLicense;
116 switch (Info->m_LicenseType)
117 {
118 case LICENSE_OPENSOURCE:
119 szLicense.LoadStringW(IDS_LICENSE_OPENSOURCE);
120 break;
121 case LICENSE_FREEWARE:
122 szLicense.LoadStringW(IDS_LICENSE_FREEWARE);
123 break;
124 case LICENSE_TRIAL:
125 szLicense.LoadStringW(IDS_LICENSE_TRIAL);
126 break;
127 default:
128 LoadAndInsertText(IDS_AINFO_LICENSE, Info->m_szLicense, CFE_BOLD, 0);
129 return;
130 }
131
132 szLicense += L" (" + Info->m_szLicense + L")";
133 LoadAndInsertText(IDS_AINFO_LICENSE, szLicense, CFE_BOLD, 0);
134 }
135
136 VOID InsertLanguageInfo(CAvailableApplicationInfo* Info)
137 {
138 if (!Info->HasLanguageInfo())
139 {
140 return;
141 }
142
143 const INT nTranslations = Info->m_LanguageLCIDs.GetSize();
144 ATL::CStringW szLangInfo;
145 ATL::CStringW szLoadedTextAvailability;
146 ATL::CStringW szLoadedAInfoText;
147
148 szLoadedAInfoText.LoadStringW(IDS_AINFO_LANGUAGES);
149
150 if (Info->HasNativeLanguage())
151 {
152 szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_AVAILABLE_TRANSLATION);
153 if (nTranslations > 1)
154 {
155 ATL::CStringW buf;
156 buf.LoadStringW(IDS_LANGUAGE_MORE_PLACEHOLDER);
157 szLangInfo.Format(buf, nTranslations - 1);
158 }
159 else
160 {
161 szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE);
162 szLangInfo = L" (" + szLangInfo + L")";
163 }
164 }
165 else if (Info->HasEnglishLanguage())
166 {
167 szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_ENGLISH_TRANSLATION);
168 if (nTranslations > 1)
169 {
170 ATL::CStringW buf;
171 buf.LoadStringW(IDS_LANGUAGE_AVAILABLE_PLACEHOLDER);
172 szLangInfo.Format(buf, nTranslations - 1);
173 }
174 else
175 {
176 szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE);
177 szLangInfo = L" (" + szLangInfo + L")";
178 }
179 }
180 else
181 {
182 szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_NO_TRANSLATION);
183 }
184
185 InsertText(szLoadedAInfoText, CFE_BOLD);
186 InsertText(szLoadedTextAvailability, NULL);
187 InsertText(szLangInfo, CFE_ITALIC);
188 }
189
190 public:
191 BOOL ShowAvailableAppInfo(CAvailableApplicationInfo* Info)
192 {
193 if (!Info) return FALSE;
194
195 SetText(Info->m_szName, CFE_BOLD);
196 InsertVersionInfo(Info);
197 InsertLicenseInfo(Info);
198 InsertLanguageInfo(Info);
199
200 LoadAndInsertText(IDS_AINFO_SIZE, Info->m_szSize, CFE_BOLD, 0);
201 LoadAndInsertText(IDS_AINFO_URLSITE, Info->m_szUrlSite, CFE_BOLD, CFE_LINK);
202 LoadAndInsertText(IDS_AINFO_DESCRIPTION, Info->m_szDesc, CFE_BOLD, 0);
203 LoadAndInsertText(IDS_AINFO_URLDOWNLOAD, Info->m_szUrlDownload, CFE_BOLD, CFE_LINK);
204
205 return TRUE;
206 }
207
208 BOOL ShowInstalledAppInfo(PINSTALLED_INFO Info)
209 {
210 ATL::CStringW szText;
211 ATL::CStringW szInfo;
212
213 if (!Info || !Info->hSubKey)
214 return FALSE;
215
216 Info->GetApplicationString(L"DisplayName", szText);
217 SetText(szText, CFE_BOLD);
218 InsertText(L"\n", 0);
219
220 #define GET_INFO(a, b, c, d) \
221 if (Info->GetApplicationString(a, szInfo)) \
222 { \
223 LoadAndInsertText(b, szInfo, c, d); \
224 }
225
226 GET_INFO(L"DisplayVersion", IDS_INFO_VERSION, CFE_BOLD, 0);
227 GET_INFO(L"Publisher", IDS_INFO_PUBLISHER, CFE_BOLD, 0);
228 GET_INFO(L"RegOwner", IDS_INFO_REGOWNER, CFE_BOLD, 0);
229 GET_INFO(L"ProductID", IDS_INFO_PRODUCTID, CFE_BOLD, 0);
230 GET_INFO(L"HelpLink", IDS_INFO_HELPLINK, CFE_BOLD, CFM_LINK);
231 GET_INFO(L"HelpTelephone", IDS_INFO_HELPPHONE, CFE_BOLD, 0);
232 GET_INFO(L"Readme", IDS_INFO_README, CFE_BOLD, 0);
233 GET_INFO(L"Contact", IDS_INFO_CONTACT, CFE_BOLD, 0);
234 GET_INFO(L"URLUpdateInfo", IDS_INFO_UPDATEINFO, CFE_BOLD, CFM_LINK);
235 GET_INFO(L"URLInfoAbout", IDS_INFO_INFOABOUT, CFE_BOLD, CFM_LINK);
236 GET_INFO(L"Comments", IDS_INFO_COMMENTS, CFE_BOLD, 0);
237 GET_INFO(L"InstallDate", IDS_INFO_INSTALLDATE, CFE_BOLD, 0);
238 GET_INFO(L"InstallLocation", IDS_INFO_INSTLOCATION, CFE_BOLD, 0);
239 GET_INFO(L"InstallSource", IDS_INFO_INSTALLSRC, CFE_BOLD, 0);
240 GET_INFO(L"UninstallString", IDS_INFO_UNINSTALLSTR, CFE_BOLD, 0);
241 GET_INFO(L"InstallSource", IDS_INFO_INSTALLSRC, CFE_BOLD, 0);
242 GET_INFO(L"ModifyPath", IDS_INFO_MODIFYPATH, CFE_BOLD, 0);
243
244 return TRUE;
245 }
246
247 VOID SetWelcomeText()
248 {
249 ATL::CStringW szText;
250
251 szText.LoadStringW(IDS_WELCOME_TITLE);
252 SetText(szText, CFE_BOLD);
253
254 szText.LoadStringW(IDS_WELCOME_TEXT);
255 InsertText(szText, 0);
256
257 szText.LoadStringW(IDS_WELCOME_URL);
258 InsertText(szText, CFM_LINK);
259 }
260 };
261
262 class CMainToolbar :
263 public CUiWindow< CToolbar<> >
264 {
265 const INT m_iToolbarHeight;
266 DWORD m_dButtonsWidthMax;
267
268 WCHAR szInstallBtn[MAX_STR_LEN];
269 WCHAR szUninstallBtn[MAX_STR_LEN];
270 WCHAR szModifyBtn[MAX_STR_LEN];
271 WCHAR szSelectAll[MAX_STR_LEN];
272
273 VOID AddImageToImageList(HIMAGELIST hImageList, UINT ImageIndex)
274 {
275 HICON hImage;
276
277 if (!(hImage = (HICON) LoadImageW(hInst,
278 MAKEINTRESOURCE(ImageIndex),
279 IMAGE_ICON,
280 m_iToolbarHeight,
281 m_iToolbarHeight,
282 0)))
283 {
284 /* TODO: Error message */
285 }
286
287 ImageList_AddIcon(hImageList, hImage);
288 DeleteObject(hImage);
289 }
290
291 HIMAGELIST InitImageList()
292 {
293 HIMAGELIST hImageList;
294
295 /* Create the toolbar icon image list */
296 hImageList = ImageList_Create(m_iToolbarHeight,//GetSystemMetrics(SM_CXSMICON),
297 m_iToolbarHeight,//GetSystemMetrics(SM_CYSMICON),
298 ILC_MASK | GetSystemColorDepth(),
299 1, 1);
300 if (!hImageList)
301 {
302 /* TODO: Error message */
303 return NULL;
304 }
305
306 AddImageToImageList(hImageList, IDI_INSTALL);
307 AddImageToImageList(hImageList, IDI_UNINSTALL);
308 AddImageToImageList(hImageList, IDI_MODIFY);
309 AddImageToImageList(hImageList, IDI_CHECK_ALL);
310 AddImageToImageList(hImageList, IDI_REFRESH);
311 AddImageToImageList(hImageList, IDI_UPDATE_DB);
312 AddImageToImageList(hImageList, IDI_SETTINGS);
313 AddImageToImageList(hImageList, IDI_EXIT);
314
315 return hImageList;
316 }
317
318 public:
319 CMainToolbar() : m_iToolbarHeight(24)
320 {
321 }
322
323 VOID OnGetDispInfo(LPTOOLTIPTEXT lpttt)
324 {
325 UINT idButton = (UINT) lpttt->hdr.idFrom;
326
327 switch (idButton)
328 {
329 case ID_EXIT:
330 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_EXIT);
331 break;
332
333 case ID_INSTALL:
334 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_INSTALL);
335 break;
336
337 case ID_UNINSTALL:
338 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UNINSTALL);
339 break;
340
341 case ID_MODIFY:
342 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_MODIFY);
343 break;
344
345 case ID_SETTINGS:
346 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_SETTINGS);
347 break;
348
349 case ID_REFRESH:
350 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_REFRESH);
351 break;
352
353 case ID_RESETDB:
354 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UPDATE_DB);
355 break;
356 }
357 }
358
359 HWND Create(HWND hwndParent)
360 {
361 /* Create buttons */
362 TBBUTTON Buttons[] =
363 { /* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */
364 { 0, ID_INSTALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR) szInstallBtn },
365 { 1, ID_UNINSTALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR) szUninstallBtn },
366 { 2, ID_MODIFY, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR) szModifyBtn },
367 { 3, ID_CHECK_ALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR) szSelectAll },
368 { -1, 0, TBSTATE_ENABLED, BTNS_SEP, { 0 }, 0, 0 },
369 { 4, ID_REFRESH, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0 },
370 { 5, ID_RESETDB, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0 },
371 { -1, 0, TBSTATE_ENABLED, BTNS_SEP, { 0 }, 0, 0 },
372 { 6, ID_SETTINGS, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0 },
373 { 7, ID_EXIT, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0 },
374 };
375
376 LoadStringW(hInst, IDS_INSTALL, szInstallBtn, _countof(szInstallBtn));
377 LoadStringW(hInst, IDS_UNINSTALL, szUninstallBtn, _countof(szUninstallBtn));
378 LoadStringW(hInst, IDS_MODIFY, szModifyBtn, _countof(szModifyBtn));
379 LoadStringW(hInst, IDS_SELECT_ALL, szSelectAll, _countof(szSelectAll));
380
381 m_hWnd = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
382 WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_LIST,
383 0, 0, 0, 0,
384 hwndParent,
385 0, hInst, NULL);
386
387 if (!m_hWnd)
388 {
389 /* TODO: Show error message */
390 return FALSE;
391 }
392
393 SendMessageW(TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS);
394 SetButtonStructSize();
395
396 /* Set image list */
397 HIMAGELIST hImageList = InitImageList();
398
399 if (!hImageList)
400 {
401 /* TODO: Show error message */
402 return FALSE;
403 }
404
405 ImageList_Destroy(SetImageList(hImageList));
406
407 AddButtons(_countof(Buttons), Buttons);
408
409 /* Remember ideal width to use as a max width of buttons */
410 SIZE size;
411 GetIdealSize(FALSE, &size);
412 m_dButtonsWidthMax = size.cx;
413
414 return m_hWnd;
415 }
416
417 VOID HideButtonCaption()
418 {
419 DWORD dCurrentExStyle = (DWORD) SendMessageW(TB_GETEXTENDEDSTYLE, 0, 0);
420 SendMessageW(TB_SETEXTENDEDSTYLE, 0, dCurrentExStyle | TBSTYLE_EX_MIXEDBUTTONS);
421 }
422
423 VOID ShowButtonCaption()
424 {
425 DWORD dCurrentExStyle = (DWORD) SendMessageW(TB_GETEXTENDEDSTYLE, 0, 0);
426 SendMessageW(TB_SETEXTENDEDSTYLE, 0, dCurrentExStyle & ~TBSTYLE_EX_MIXEDBUTTONS);
427 }
428
429 DWORD GetMaxButtonsWidth() const
430 {
431 return m_dButtonsWidthMax;
432 }
433 };
434
435 class CAppsListView :
436 public CUiWindow<CListView>
437 {
438 struct SortContext
439 {
440 CAppsListView * lvw;
441 INT iSubItem;
442 };
443
444 BOOL bHasAllChecked;
445 BOOL bIsAscending;
446 BOOL bHasCheckboxes;
447
448 INT nLastHeaderID;
449
450 public:
451 CAppsListView() :
452 bHasAllChecked(FALSE),
453 bIsAscending(TRUE),
454 bHasCheckboxes(FALSE),
455 nLastHeaderID(-1)
456 {
457 }
458
459 VOID SetCheckboxesVisible(BOOL bIsVisible)
460 {
461 if (bIsVisible)
462 {
463 SetExtendedListViewStyle(LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
464 }
465 else
466 {
467 SetExtendedListViewStyle(LVS_EX_FULLROWSELECT);
468 }
469
470 bHasCheckboxes = bIsVisible;
471 }
472
473 VOID ColumnClick(LPNMLISTVIEW pnmv)
474 {
475 HWND hHeader;
476 HDITEMW hColumn;
477 INT nHeaderID = pnmv->iSubItem;
478
479 if ((GetWindowLongPtr(GWL_STYLE) & ~LVS_NOSORTHEADER) == 0)
480 return;
481
482 hHeader = (HWND) SendMessage(LVM_GETHEADER, 0, 0);
483 ZeroMemory(&hColumn, sizeof(hColumn));
484
485 /* If the sorting column changed, remove the sorting style from the old column */
486 if ((nLastHeaderID != -1) && (nLastHeaderID != nHeaderID))
487 {
488 hColumn.mask = HDI_FORMAT;
489 Header_GetItem(hHeader, nLastHeaderID, &hColumn);
490 hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
491 Header_SetItem(hHeader, nLastHeaderID, &hColumn);
492 }
493
494 /* Set the sorting style to the new column */
495 hColumn.mask = HDI_FORMAT;
496 Header_GetItem(hHeader, nHeaderID, &hColumn);
497
498 hColumn.fmt &= (bIsAscending ? ~HDF_SORTDOWN : ~HDF_SORTUP);
499 hColumn.fmt |= (bIsAscending ? HDF_SORTUP : HDF_SORTDOWN);
500 Header_SetItem(hHeader, nHeaderID, &hColumn);
501
502 /* Sort the list, using the current values of nHeaderID and bIsAscending */
503 SortContext ctx = {this, nHeaderID};
504 SortItems(s_CompareFunc, &ctx);
505
506 /* Save new values */
507 nLastHeaderID = nHeaderID;
508 bIsAscending = !bIsAscending;
509 }
510
511 PVOID GetLParam(INT Index)
512 {
513 INT ItemIndex;
514
515 if (Index == -1)
516 {
517 ItemIndex = (INT) SendMessage(LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
518 if (ItemIndex == -1)
519 return NULL;
520 }
521 else
522 {
523 ItemIndex = Index;
524 }
525
526 return (PVOID) GetItemData(ItemIndex);
527 }
528
529 BOOL AddColumn(INT Index, ATL::CStringW& Text, INT Width, INT Format)
530 {
531 return AddColumn(Index, const_cast<LPWSTR>(Text.GetString()), Width, Format);
532 }
533
534 BOOL AddColumn(INT Index, LPWSTR lpText, INT Width, INT Format)
535 {
536 LVCOLUMNW Column;
537
538 ZeroMemory(&Column, sizeof(Column));
539
540 Column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
541 Column.iSubItem = Index;
542 Column.pszText = lpText;
543 Column.cx = Width;
544 Column.fmt = Format;
545
546 return (InsertColumn(Index, &Column) == -1) ? FALSE : TRUE;
547 }
548
549 INT AddItem(INT ItemIndex, INT IconIndex, LPCWSTR lpText, LPARAM lParam)
550 {
551 LVITEMW Item;
552
553 ZeroMemory(&Item, sizeof(Item));
554
555 Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
556 Item.pszText = const_cast<LPWSTR>(lpText);
557 Item.lParam = lParam;
558 Item.iItem = ItemIndex;
559 Item.iImage = IconIndex;
560
561 return InsertItem(&Item);
562 }
563
564 static INT CALLBACK s_CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
565 {
566 SortContext * ctx = ((SortContext*) lParamSort);
567 return ctx->lvw->CompareFunc(lParam1, lParam2, ctx->iSubItem);
568 }
569
570 INT CompareFunc(LPARAM lParam1, LPARAM lParam2, INT iSubItem)
571 {
572 ATL::CStringW Item1, Item2;
573 LVFINDINFOW IndexInfo;
574 INT Index;
575
576 IndexInfo.flags = LVFI_PARAM;
577
578 IndexInfo.lParam = lParam1;
579 Index = FindItem(-1, &IndexInfo);
580 GetItemText(Index, iSubItem, Item1.GetBuffer(MAX_STR_LEN), MAX_STR_LEN);
581 Item1.ReleaseBuffer();
582
583 IndexInfo.lParam = lParam2;
584 Index = FindItem(-1, &IndexInfo);
585 GetItemText(Index, iSubItem, Item2.GetBuffer(MAX_STR_LEN), MAX_STR_LEN);
586 Item2.ReleaseBuffer();
587
588 return bIsAscending ? Item1.Compare(Item2) : Item2.Compare(Item1);
589 }
590
591 HWND Create(HWND hwndParent)
592 {
593 RECT r = {205, 28, 465, 250};
594 DWORD style = WS_CHILD | WS_VISIBLE | LVS_SORTASCENDING | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS;
595 HMENU menu = GetSubMenu(LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_APPLICATIONMENU)), 0);
596
597 HWND hwnd = CListView::Create(hwndParent, r, NULL, style, WS_EX_CLIENTEDGE, menu);
598
599 if (hwnd)
600 {
601 SetCheckboxesVisible(FALSE);
602 }
603
604 return hwnd;
605 }
606
607 BOOL GetCheckState(INT item)
608 {
609 return (BOOL) (GetItemState(item, LVIS_STATEIMAGEMASK) >> 12) - 1;
610 }
611
612 VOID SetCheckState(INT item, BOOL fCheck)
613 {
614 if (bHasCheckboxes)
615 {
616 SetItemState(item, INDEXTOSTATEIMAGEMASK((fCheck) ? 2 : 1), LVIS_STATEIMAGEMASK);
617 SetSelected(item, fCheck);
618 }
619 }
620
621 VOID SetSelected(INT item, BOOL value)
622 {
623 if (item < 0)
624 {
625 for (INT i = 0; i >= 0; i = GetNextItem(i, LVNI_ALL))
626 {
627 CAvailableApplicationInfo* pAppInfo = (CAvailableApplicationInfo*) GetItemData(i);
628 if (pAppInfo)
629 {
630 pAppInfo->m_IsSelected = value;
631 }
632 }
633 }
634 else
635 {
636 CAvailableApplicationInfo* pAppInfo = (CAvailableApplicationInfo*) GetItemData(item);
637 if (pAppInfo)
638 {
639 pAppInfo->m_IsSelected = value;
640 }
641 }
642 }
643
644 VOID CheckAll()
645 {
646 if (bHasCheckboxes)
647 {
648 bHasAllChecked = !bHasAllChecked;
649 SetCheckState(-1, bHasAllChecked);
650 }
651 }
652
653 ATL::CSimpleArray<CAvailableApplicationInfo> GetCheckedItems()
654 {
655 if (!bHasCheckboxes)
656 {
657 return ATL::CSimpleArray<CAvailableApplicationInfo>();
658 }
659
660 ATL::CSimpleArray<CAvailableApplicationInfo> list;
661 for (INT i = 0; i >= 0; i = GetNextItem(i, LVNI_ALL))
662 {
663 if (GetCheckState(i) != FALSE)
664 {
665 CAvailableApplicationInfo* pAppInfo = (CAvailableApplicationInfo*) GetItemData(i);
666 list.Add(*pAppInfo);
667 }
668 }
669 return list;
670 }
671
672 CAvailableApplicationInfo* GetSelectedData()
673 {
674 INT item = GetSelectionMark();
675 return (CAvailableApplicationInfo*) GetItemData(item);
676 }
677 };
678
679 class CSideTreeView :
680 public CUiWindow<CTreeView>
681 {
682 HIMAGELIST hImageTreeView;
683
684 public:
685 CSideTreeView() :
686 CUiWindow(),
687 hImageTreeView(ImageList_Create(TREEVIEW_ICON_SIZE, TREEVIEW_ICON_SIZE,
688 GetSystemColorDepth() | ILC_MASK,
689 0, 1))
690 {
691 }
692
693 HTREEITEM AddItem(HTREEITEM hParent, ATL::CStringW &Text, INT Image, INT SelectedImage, LPARAM lParam)
694 {
695 return CUiWindow<CTreeView>::AddItem(hParent, const_cast<LPWSTR>(Text.GetString()), Image, SelectedImage, lParam);
696 }
697
698 HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
699 {
700 ATL::CStringW szText;
701 INT Index;
702 HICON hIcon;
703
704 hIcon = (HICON) LoadImageW(hInst,
705 MAKEINTRESOURCE(IconIndex),
706 IMAGE_ICON,
707 TREEVIEW_ICON_SIZE,
708 TREEVIEW_ICON_SIZE,
709 LR_CREATEDIBSECTION);
710 if (hIcon)
711 {
712 Index = ImageList_AddIcon(hImageTreeView, hIcon);
713 DestroyIcon(hIcon);
714 }
715
716 szText.LoadStringW(TextIndex);
717 return AddItem(hRootItem, szText, Index, Index, TextIndex);
718 }
719
720 HIMAGELIST SetImageList()
721 {
722 return CUiWindow<CTreeView>::SetImageList(hImageTreeView, TVSIL_NORMAL);
723 }
724
725 VOID DestroyImageList()
726 {
727 if (hImageTreeView)
728 ImageList_Destroy(hImageTreeView);
729 }
730
731 ~CSideTreeView()
732 {
733 DestroyImageList();
734 }
735 };
736
737 class CSearchBar :
738 public CWindow
739 {
740 public:
741 const INT m_Width;
742 const INT m_Height;
743
744 CSearchBar() : m_Width(200), m_Height(22)
745 {
746 }
747
748 VOID SetText(LPCWSTR lpszText)
749 {
750 SendMessageW(SB_SETTEXT, SBT_NOBORDERS, (LPARAM) lpszText);
751 }
752
753 HWND Create(HWND hwndParent)
754 {
755 ATL::CStringW szBuf;
756 m_hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL,
757 WS_CHILD | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
758 0, 0, m_Width, m_Height,
759 hwndParent, (HMENU) NULL,
760 hInst, 0);
761
762 SendMessageW(WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0);
763 szBuf.LoadStringW(IDS_SEARCH_TEXT);
764 SetWindowTextW(szBuf);
765 return m_hWnd;
766 }
767
768 };
769
770 class CMainWindow :
771 public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>
772 {
773 CUiPanel* m_ClientPanel;
774 CUiSplitPanel* m_VSplitter;
775 CUiSplitPanel* m_HSplitter;
776
777 CMainToolbar* m_Toolbar;
778 CAppsListView* m_ListView;
779
780 CSideTreeView* m_TreeView;
781 CUiWindow<CStatusBar>* m_StatusBar;
782 CAppRichEdit* m_RichEdit;
783
784 CUiWindow<CSearchBar>* m_SearchBar;
785 CAvailableApps m_AvailableApps;
786
787 LPWSTR pLink;
788
789 INT nSelectedApps;
790
791 BOOL bSearchEnabled;
792 BOOL bUpdating;
793
794 ATL::CStringW szSearchPattern;
795 INT SelectedEnumType;
796
797 public:
798 CMainWindow() :
799 m_ClientPanel(NULL),
800 pLink(NULL),
801 bSearchEnabled(FALSE),
802 SelectedEnumType(ENUM_ALL_INSTALLED)
803 {
804 }
805
806 private:
807 VOID InitApplicationsList()
808 {
809 ATL::CStringW szText;
810
811 /* Add columns to ListView */
812 szText.LoadStringW(IDS_APP_NAME);
813 m_ListView->AddColumn(0, szText, 250, LVCFMT_LEFT);
814
815 szText.LoadStringW(IDS_APP_INST_VERSION);
816 m_ListView->AddColumn(1, szText, 90, LVCFMT_RIGHT);
817
818 szText.LoadStringW(IDS_APP_DESCRIPTION);
819 m_ListView->AddColumn(3, szText, 300, LVCFMT_LEFT);
820
821 // Unnesesary since the list updates on every TreeView selection
822 // UpdateApplicationsList(ENUM_ALL_COMPONENTS);
823 }
824
825 HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
826 {
827 return m_TreeView->AddCategory(hRootItem, TextIndex, IconIndex);
828 }
829
830 VOID InitCategoriesList()
831 {
832 HTREEITEM hRootItemInstalled, hRootItemAvailable;
833
834 hRootItemInstalled = AddCategory(TVI_ROOT, IDS_INSTALLED, IDI_CATEGORY);
835 AddCategory(hRootItemInstalled, IDS_APPLICATIONS, IDI_APPS);
836 AddCategory(hRootItemInstalled, IDS_UPDATES, IDI_APPUPD);
837
838 AddCategory(TVI_ROOT, IDS_SELECTEDFORINST, IDI_SELECTEDFORINST);
839
840 hRootItemAvailable = AddCategory(TVI_ROOT, IDS_AVAILABLEFORINST, IDI_CATEGORY);
841 AddCategory(hRootItemAvailable, IDS_CAT_AUDIO, IDI_CAT_AUDIO);
842 AddCategory(hRootItemAvailable, IDS_CAT_VIDEO, IDI_CAT_VIDEO);
843 AddCategory(hRootItemAvailable, IDS_CAT_GRAPHICS, IDI_CAT_GRAPHICS);
844 AddCategory(hRootItemAvailable, IDS_CAT_GAMES, IDI_CAT_GAMES);
845 AddCategory(hRootItemAvailable, IDS_CAT_INTERNET, IDI_CAT_INTERNET);
846 AddCategory(hRootItemAvailable, IDS_CAT_OFFICE, IDI_CAT_OFFICE);
847 AddCategory(hRootItemAvailable, IDS_CAT_DEVEL, IDI_CAT_DEVEL);
848 AddCategory(hRootItemAvailable, IDS_CAT_EDU, IDI_CAT_EDU);
849 AddCategory(hRootItemAvailable, IDS_CAT_ENGINEER, IDI_CAT_ENGINEER);
850 AddCategory(hRootItemAvailable, IDS_CAT_FINANCE, IDI_CAT_FINANCE);
851 AddCategory(hRootItemAvailable, IDS_CAT_SCIENCE, IDI_CAT_SCIENCE);
852 AddCategory(hRootItemAvailable, IDS_CAT_TOOLS, IDI_CAT_TOOLS);
853 AddCategory(hRootItemAvailable, IDS_CAT_DRIVERS, IDI_CAT_DRIVERS);
854 AddCategory(hRootItemAvailable, IDS_CAT_LIBS, IDI_CAT_LIBS);
855 AddCategory(hRootItemAvailable, IDS_CAT_THEMES, IDI_CAT_THEMES);
856 AddCategory(hRootItemAvailable, IDS_CAT_OTHER, IDI_CAT_OTHER);
857
858 m_TreeView->SetImageList();
859 m_TreeView->Expand(hRootItemInstalled, TVE_EXPAND);
860 m_TreeView->Expand(hRootItemAvailable, TVE_EXPAND);
861 m_TreeView->SelectItem(hRootItemAvailable);
862 }
863
864 BOOL CreateStatusBar()
865 {
866 m_StatusBar = new CUiWindow<CStatusBar>();
867 m_StatusBar->m_VerticalAlignment = UiAlign_RightBtm;
868 m_StatusBar->m_HorizontalAlignment = UiAlign_Stretch;
869 m_ClientPanel->Children().Append(m_StatusBar);
870
871 return m_StatusBar->Create(m_hWnd, (HMENU) IDC_STATUSBAR) != NULL;
872 }
873
874 BOOL CreateToolbar()
875 {
876 m_Toolbar = new CMainToolbar();
877 m_Toolbar->m_VerticalAlignment = UiAlign_LeftTop;
878 m_Toolbar->m_HorizontalAlignment = UiAlign_Stretch;
879 m_ClientPanel->Children().Append(m_Toolbar);
880
881 return m_Toolbar->Create(m_hWnd) != NULL;
882 }
883
884 BOOL CreateTreeView()
885 {
886 m_TreeView = new CSideTreeView();
887 m_TreeView->m_VerticalAlignment = UiAlign_Stretch;
888 m_TreeView->m_HorizontalAlignment = UiAlign_Stretch;
889 m_VSplitter->First().Append(m_TreeView);
890
891 return m_TreeView->Create(m_hWnd) != NULL;
892 }
893
894 BOOL CreateListView()
895 {
896 m_ListView = new CAppsListView();
897 m_ListView->m_VerticalAlignment = UiAlign_Stretch;
898 m_ListView->m_HorizontalAlignment = UiAlign_Stretch;
899 m_HSplitter->First().Append(m_ListView);
900
901 hListView = m_ListView->Create(m_hWnd);
902 return hListView != NULL;
903 }
904
905 BOOL CreateRichEdit()
906 {
907 m_RichEdit = new CAppRichEdit();
908 m_RichEdit->m_VerticalAlignment = UiAlign_Stretch;
909 m_RichEdit->m_HorizontalAlignment = UiAlign_Stretch;
910 m_HSplitter->Second().Append(m_RichEdit);
911
912 return m_RichEdit->Create(m_hWnd) != NULL;
913 }
914
915 BOOL CreateVSplitter()
916 {
917 m_VSplitter = new CUiSplitPanel();
918 m_VSplitter->m_VerticalAlignment = UiAlign_Stretch;
919 m_VSplitter->m_HorizontalAlignment = UiAlign_Stretch;
920 m_VSplitter->m_DynamicFirst = FALSE;
921 m_VSplitter->m_Horizontal = FALSE;
922 m_VSplitter->m_MinFirst = 0;
923 m_VSplitter->m_MinSecond = 320;
924 m_VSplitter->m_Pos = 240;
925 m_ClientPanel->Children().Append(m_VSplitter);
926
927 return m_VSplitter->Create(m_hWnd) != NULL;
928 }
929
930 BOOL CreateHSplitter()
931 {
932 m_HSplitter = new CUiSplitPanel();
933 m_HSplitter->m_VerticalAlignment = UiAlign_Stretch;
934 m_HSplitter->m_HorizontalAlignment = UiAlign_Stretch;
935 m_HSplitter->m_DynamicFirst = TRUE;
936 m_HSplitter->m_Horizontal = TRUE;
937 m_HSplitter->m_Pos = INT_MAX; //set INT_MAX to use lowest possible position (m_MinSecond)
938 m_HSplitter->m_MinFirst = 10;
939 m_HSplitter->m_MinSecond = 140;
940 m_VSplitter->Second().Append(m_HSplitter);
941
942 return m_HSplitter->Create(m_hWnd) != NULL;
943 }
944
945 BOOL CreateSearchBar()
946 {
947 m_SearchBar = new CUiWindow<CSearchBar>();
948 m_SearchBar->m_VerticalAlignment = UiAlign_LeftTop;
949 m_SearchBar->m_HorizontalAlignment = UiAlign_RightBtm;
950 m_SearchBar->m_Margin.top = 4;
951 m_SearchBar->m_Margin.right = 6;
952
953 return m_SearchBar->Create(m_Toolbar->m_hWnd) != NULL;
954 }
955
956 BOOL CreateLayout()
957 {
958 BOOL b = TRUE;
959 bUpdating = TRUE;
960
961 m_ClientPanel = new CUiPanel();
962 m_ClientPanel->m_VerticalAlignment = UiAlign_Stretch;
963 m_ClientPanel->m_HorizontalAlignment = UiAlign_Stretch;
964
965 // Top level
966 b = b && CreateStatusBar();
967 b = b && CreateToolbar();
968 b = b && CreateSearchBar();
969 b = b && CreateVSplitter();
970
971 // Inside V Splitter
972 b = b && CreateHSplitter();
973 b = b && CreateTreeView();
974
975 // Inside H Splitter
976 b = b && CreateListView();
977 b = b && CreateRichEdit();
978
979 if (b)
980 {
981 RECT rTop;
982 RECT rBottom;
983
984 /* Size status bar */
985 m_StatusBar->SendMessageW(WM_SIZE, 0, 0);
986
987 /* Size tool bar */
988 m_Toolbar->AutoSize();
989
990 ::GetWindowRect(m_Toolbar->m_hWnd, &rTop);
991 ::GetWindowRect(m_StatusBar->m_hWnd, &rBottom);
992
993 m_VSplitter->m_Margin.top = rTop.bottom - rTop.top;
994 m_VSplitter->m_Margin.bottom = rBottom.bottom - rBottom.top;
995 }
996
997 bUpdating = FALSE;
998 return b;
999 }
1000
1001 BOOL InitControls()
1002 {
1003 if (CreateLayout())
1004 {
1005
1006 InitApplicationsList();
1007 InitCategoriesList();
1008
1009 nSelectedApps = 0;
1010 UpdateStatusBarText();
1011
1012 return TRUE;
1013 }
1014
1015 return FALSE;
1016 }
1017
1018 VOID ShowAppInfo(INT Index)
1019 {
1020 if (IsInstalledEnum(SelectedEnumType))
1021 {
1022 if (Index == -1)
1023 Index = m_ListView->GetSelectionMark();
1024
1025 PINSTALLED_INFO Info = (PINSTALLED_INFO) m_ListView->GetItemData(Index);
1026
1027 m_RichEdit->ShowInstalledAppInfo(Info);
1028 }
1029 else if (IsAvailableEnum(SelectedEnumType))
1030 {
1031 if (Index == -1)
1032 return;
1033
1034 CAvailableApplicationInfo* Info = (CAvailableApplicationInfo*) m_ListView->GetItemData(Index);
1035
1036 m_RichEdit->ShowAvailableAppInfo(Info);
1037 }
1038 }
1039
1040 VOID OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
1041 {
1042 if (wParam == SIZE_MINIMIZED)
1043 return;
1044
1045 /* Size status bar */
1046 m_StatusBar->SendMessage(WM_SIZE, 0, 0);
1047
1048 /* Size tool bar */
1049 m_Toolbar->AutoSize();
1050
1051 /* Automatically hide captions */
1052 DWORD dToolbarTreshold = m_Toolbar->GetMaxButtonsWidth();
1053 DWORD dSearchbarMargin = (LOWORD(lParam) - m_SearchBar->m_Width);
1054
1055 if (dSearchbarMargin > dToolbarTreshold)
1056 {
1057 m_Toolbar->ShowButtonCaption();
1058 }
1059 else if (dSearchbarMargin < dToolbarTreshold)
1060 {
1061 m_Toolbar->HideButtonCaption();
1062 }
1063
1064 RECT r = {0, 0, LOWORD(lParam), HIWORD(lParam)};
1065 HDWP hdwp = NULL;
1066 INT count = m_ClientPanel->CountSizableChildren();
1067
1068 hdwp = BeginDeferWindowPos(count);
1069 if (hdwp)
1070 {
1071 hdwp = m_ClientPanel->OnParentSize(r, hdwp);
1072 if (hdwp)
1073 {
1074 EndDeferWindowPos(hdwp);
1075 }
1076
1077 }
1078
1079 // TODO: Sub-layouts for children of children
1080 count = m_SearchBar->CountSizableChildren();
1081 hdwp = BeginDeferWindowPos(count);
1082 if (hdwp)
1083 {
1084 hdwp = m_SearchBar->OnParentSize(r, hdwp);
1085 if (hdwp)
1086 {
1087 EndDeferWindowPos(hdwp);
1088 }
1089 }
1090
1091 }
1092
1093 VOID RemoveSelectedAppFromRegistry()
1094 {
1095 PINSTALLED_INFO Info;
1096 WCHAR szFullName[MAX_PATH] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\";
1097 ATL::CStringW szMsgText, szMsgTitle;
1098 INT ItemIndex = m_ListView->GetNextItem(-1, LVNI_FOCUSED);
1099
1100 if (!IsInstalledEnum(SelectedEnumType))
1101 return;
1102
1103 Info = reinterpret_cast<PINSTALLED_INFO>(m_ListView->GetItemData(ItemIndex));
1104 if (!Info || !Info->hSubKey || (ItemIndex == -1))
1105 return;
1106
1107 if (!szMsgText.LoadStringW(IDS_APP_REG_REMOVE) ||
1108 !szMsgTitle.LoadStringW(IDS_INFORMATION))
1109 return;
1110
1111 if (MessageBoxW(szMsgText, szMsgTitle, MB_YESNO | MB_ICONQUESTION) == IDYES)
1112 {
1113 ATL::CStringW::CopyChars(szFullName,
1114 MAX_PATH,
1115 Info->szKeyName.GetString(),
1116 MAX_PATH - wcslen(szFullName));
1117
1118 if (RegDeleteKeyW(Info->hRootKey, szFullName) == ERROR_SUCCESS)
1119 {
1120 m_ListView->DeleteItem(ItemIndex);
1121 return;
1122 }
1123
1124 if (!szMsgText.LoadStringW(IDS_UNABLE_TO_REMOVE))
1125 return;
1126
1127 MessageBoxW(szMsgText.GetString(), NULL, MB_OK | MB_ICONERROR);
1128 }
1129 }
1130
1131 BOOL UninstallSelectedApp(BOOL bModify)
1132 {
1133 WCHAR szAppName[MAX_STR_LEN];
1134
1135 if (!IsInstalledEnum(SelectedEnumType))
1136 return FALSE;
1137
1138 INT ItemIndex = m_ListView->GetNextItem(-1, LVNI_FOCUSED);
1139 if (ItemIndex == -1)
1140 return FALSE;
1141
1142 m_ListView->GetItemText(ItemIndex, 0, szAppName, _countof(szAppName));
1143 WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_REMOVE, szAppName);
1144
1145 PINSTALLED_INFO ItemInfo = (PINSTALLED_INFO)m_ListView->GetItemData(ItemIndex);
1146 return UninstallApplication(ItemInfo, bModify);
1147 }
1148 BOOL ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT& theResult, DWORD dwMapId)
1149 {
1150 theResult = 0;
1151 switch (Msg)
1152 {
1153 case WM_CREATE:
1154 if (!InitControls())
1155 ::PostMessageW(hwnd, WM_CLOSE, 0, 0);
1156 break;
1157
1158 case WM_DESTROY:
1159 {
1160 ShowWindow(SW_HIDE);
1161 SaveSettings(hwnd);
1162
1163 FreeLogs();
1164 m_AvailableApps.FreeCachedEntries();
1165
1166 if (IsInstalledEnum(SelectedEnumType))
1167 FreeInstalledAppList();
1168
1169 delete m_ClientPanel;
1170
1171 PostQuitMessage(0);
1172 return 0;
1173 }
1174
1175 case WM_COMMAND:
1176 OnCommand(wParam, lParam);
1177 break;
1178
1179 case WM_NOTIFY:
1180 {
1181 LPNMHDR data = (LPNMHDR) lParam;
1182
1183 switch (data->code)
1184 {
1185 case TVN_SELCHANGED:
1186 {
1187 if (data->hwndFrom == m_TreeView->m_hWnd)
1188 {
1189 switch (((LPNMTREEVIEW) lParam)->itemNew.lParam)
1190 {
1191 case IDS_INSTALLED:
1192 UpdateApplicationsList(ENUM_ALL_INSTALLED);
1193 break;
1194
1195 case IDS_APPLICATIONS:
1196 UpdateApplicationsList(ENUM_INSTALLED_APPLICATIONS);
1197 break;
1198
1199 case IDS_UPDATES:
1200 UpdateApplicationsList(ENUM_UPDATES);
1201 break;
1202
1203 case IDS_AVAILABLEFORINST:
1204 UpdateApplicationsList(ENUM_ALL_AVAILABLE);
1205 break;
1206
1207 case IDS_CAT_AUDIO:
1208 UpdateApplicationsList(ENUM_CAT_AUDIO);
1209 break;
1210
1211 case IDS_CAT_DEVEL:
1212 UpdateApplicationsList(ENUM_CAT_DEVEL);
1213 break;
1214
1215 case IDS_CAT_DRIVERS:
1216 UpdateApplicationsList(ENUM_CAT_DRIVERS);
1217 break;
1218
1219 case IDS_CAT_EDU:
1220 UpdateApplicationsList(ENUM_CAT_EDU);
1221 break;
1222
1223 case IDS_CAT_ENGINEER:
1224 UpdateApplicationsList(ENUM_CAT_ENGINEER);
1225 break;
1226
1227 case IDS_CAT_FINANCE:
1228 UpdateApplicationsList(ENUM_CAT_FINANCE);
1229 break;
1230
1231 case IDS_CAT_GAMES:
1232 UpdateApplicationsList(ENUM_CAT_GAMES);
1233 break;
1234
1235 case IDS_CAT_GRAPHICS:
1236 UpdateApplicationsList(ENUM_CAT_GRAPHICS);
1237 break;
1238
1239 case IDS_CAT_INTERNET:
1240 UpdateApplicationsList(ENUM_CAT_INTERNET);
1241 break;
1242
1243 case IDS_CAT_LIBS:
1244 UpdateApplicationsList(ENUM_CAT_LIBS);
1245 break;
1246
1247 case IDS_CAT_OFFICE:
1248 UpdateApplicationsList(ENUM_CAT_OFFICE);
1249 break;
1250
1251 case IDS_CAT_OTHER:
1252 UpdateApplicationsList(ENUM_CAT_OTHER);
1253 break;
1254
1255 case IDS_CAT_SCIENCE:
1256 UpdateApplicationsList(ENUM_CAT_SCIENCE);
1257 break;
1258
1259 case IDS_CAT_TOOLS:
1260 UpdateApplicationsList(ENUM_CAT_TOOLS);
1261 break;
1262
1263 case IDS_CAT_VIDEO:
1264 UpdateApplicationsList(ENUM_CAT_VIDEO);
1265 break;
1266
1267 case IDS_CAT_THEMES:
1268 UpdateApplicationsList(ENUM_CAT_THEMES);
1269 break;
1270
1271 case IDS_SELECTEDFORINST:
1272 UpdateApplicationsList(ENUM_CAT_SELECTED);
1273 break;
1274 }
1275 }
1276
1277 HMENU mainMenu = ::GetMenu(hwnd);
1278 HMENU lvwMenu = ::GetMenu(m_ListView->m_hWnd);
1279
1280 /* Disable/enable items based on treeview selection */
1281 if (IsSelectedNodeInstalled())
1282 {
1283 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_ENABLED);
1284 EnableMenuItem(mainMenu, ID_INSTALL, MF_GRAYED);
1285 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_ENABLED);
1286 EnableMenuItem(mainMenu, ID_MODIFY, MF_ENABLED);
1287
1288 EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_ENABLED);
1289 EnableMenuItem(lvwMenu, ID_INSTALL, MF_GRAYED);
1290 EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_ENABLED);
1291 EnableMenuItem(lvwMenu, ID_MODIFY, MF_ENABLED);
1292
1293 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, TRUE);
1294 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, FALSE);
1295 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, TRUE);
1296 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, TRUE);
1297 }
1298 else
1299 {
1300 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_GRAYED);
1301 EnableMenuItem(mainMenu, ID_INSTALL, MF_ENABLED);
1302 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_GRAYED);
1303 EnableMenuItem(mainMenu, ID_MODIFY, MF_GRAYED);
1304
1305 EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_GRAYED);
1306 EnableMenuItem(lvwMenu, ID_INSTALL, MF_ENABLED);
1307 EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_GRAYED);
1308 EnableMenuItem(lvwMenu, ID_MODIFY, MF_GRAYED);
1309
1310 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, FALSE);
1311 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, TRUE);
1312 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, FALSE);
1313 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, FALSE);
1314 }
1315 }
1316 break;
1317
1318 case LVN_ITEMCHANGED:
1319 {
1320 LPNMLISTVIEW pnic = (LPNMLISTVIEW) lParam;
1321
1322 if (pnic->hdr.hwndFrom == m_ListView->m_hWnd)
1323 {
1324 /* Check if this is a valid item
1325 * (technically, it can be also an unselect) */
1326 INT ItemIndex = pnic->iItem;
1327 if (ItemIndex == -1 ||
1328 ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
1329 {
1330 break;
1331 }
1332
1333 /* Check if the focus has been moved to another item */
1334 if ((pnic->uChanged & LVIF_STATE) &&
1335 (pnic->uNewState & LVIS_FOCUSED) &&
1336 !(pnic->uOldState & LVIS_FOCUSED))
1337 {
1338 ShowAppInfo(ItemIndex);
1339 }
1340 /* Check if the item is checked */
1341 if ((pnic->uNewState & LVIS_STATEIMAGEMASK) && !bUpdating)
1342 {
1343 BOOL checked = m_ListView->GetCheckState(pnic->iItem);
1344 /* FIXME: HAX!
1345 - preventing decremention below zero as a safeguard for ReactOS
1346 In ReactOS this action is triggered whenever user changes *selection*, but should be only when *checkbox* state toggled
1347 Maybe LVIS_STATEIMAGEMASK is set incorrectly
1348 */
1349 nSelectedApps +=
1350 (checked)
1351 ? 1
1352 : ((nSelectedApps > 0)
1353 ? -1
1354 : 0);
1355
1356 /* Update item's selection status */
1357 m_ListView->SetSelected(pnic->iItem, checked);
1358
1359 UpdateStatusBarText();
1360 }
1361 }
1362 }
1363 break;
1364
1365 case LVN_COLUMNCLICK:
1366 {
1367 LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
1368
1369 m_ListView->ColumnClick(pnmv);
1370 }
1371 break;
1372
1373 case NM_CLICK:
1374 {
1375 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1376 {
1377 ShowAppInfo(-1);
1378 }
1379 }
1380 break;
1381
1382 case NM_DBLCLK:
1383 {
1384 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1385 {
1386 /* this won't do anything if the program is already installed */
1387 SendMessageW(hwnd, WM_COMMAND, ID_INSTALL, 0);
1388 }
1389 }
1390 break;
1391
1392 case NM_RCLICK:
1393 {
1394 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1395 {
1396 ShowPopupMenu(m_ListView->m_hWnd, 0, ID_INSTALL);
1397 }
1398 }
1399 break;
1400
1401 case EN_LINK:
1402 OnLink((ENLINK*) lParam);
1403 break;
1404
1405 case TTN_GETDISPINFO:
1406 m_Toolbar->OnGetDispInfo((LPTOOLTIPTEXT) lParam);
1407 break;
1408 }
1409 }
1410 break;
1411
1412 case WM_SIZE:
1413 OnSize(hwnd, wParam, lParam);
1414 break;
1415
1416 case WM_SIZING:
1417 {
1418 LPRECT pRect = (LPRECT) lParam;
1419
1420 if (pRect->right - pRect->left < 565)
1421 pRect->right = pRect->left + 565;
1422
1423 if (pRect->bottom - pRect->top < 300)
1424 pRect->bottom = pRect->top + 300;
1425
1426 return TRUE;
1427 }
1428
1429 case WM_SYSCOLORCHANGE:
1430 {
1431 /* Forward WM_SYSCOLORCHANGE to common controls */
1432 m_ListView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1433 m_TreeView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1434 m_Toolbar->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1435 m_ListView->SendMessageW(EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_BTNFACE));
1436 }
1437 break;
1438
1439 case WM_TIMER:
1440 if (wParam == SEARCH_TIMER_ID)
1441 {
1442 ::KillTimer(hwnd, SEARCH_TIMER_ID);
1443 if (bSearchEnabled)
1444 UpdateApplicationsList(-1);
1445 }
1446 break;
1447 }
1448
1449 return FALSE;
1450 }
1451
1452 virtual VOID OnLink(ENLINK *Link)
1453 {
1454 switch (Link->msg)
1455 {
1456 case WM_LBUTTONUP:
1457 case WM_RBUTTONUP:
1458 {
1459 if (pLink) HeapFree(GetProcessHeap(), 0, pLink);
1460
1461 pLink = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
1462 (max(Link->chrg.cpMin, Link->chrg.cpMax) -
1463 min(Link->chrg.cpMin, Link->chrg.cpMax) + 1) * sizeof(WCHAR));
1464 if (!pLink)
1465 {
1466 /* TODO: Error message */
1467 return;
1468 }
1469
1470 m_RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin, Link->chrg.cpMax);
1471 m_RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM) pLink);
1472
1473 ShowPopupMenu(m_RichEdit->m_hWnd, IDR_LINKMENU, -1);
1474 }
1475 break;
1476 }
1477 }
1478
1479 BOOL IsSelectedNodeInstalled()
1480 {
1481 HTREEITEM hSelectedItem = m_TreeView->GetSelection();
1482 TV_ITEM tItem;
1483
1484 tItem.mask = TVIF_PARAM | TVIF_HANDLE;
1485 tItem.hItem = hSelectedItem;
1486 m_TreeView->GetItem(&tItem);
1487 switch (tItem.lParam)
1488 {
1489 case IDS_INSTALLED:
1490 case IDS_APPLICATIONS:
1491 case IDS_UPDATES:
1492 return TRUE;
1493 default:
1494 return FALSE;
1495 }
1496 }
1497
1498 VOID OnCommand(WPARAM wParam, LPARAM lParam)
1499 {
1500 WORD wCommand = LOWORD(wParam);
1501
1502 if (lParam == (LPARAM) m_SearchBar->m_hWnd)
1503 {
1504 ATL::CStringW szBuf;
1505
1506 switch (HIWORD(wParam))
1507 {
1508 case EN_SETFOCUS:
1509 {
1510 ATL::CStringW szWndText;
1511
1512 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1513 m_SearchBar->GetWindowTextW(szWndText);
1514 if (szBuf == szWndText)
1515 {
1516 bSearchEnabled = FALSE;
1517 m_SearchBar->SetWindowTextW(L"");
1518 }
1519 }
1520 break;
1521
1522 case EN_KILLFOCUS:
1523 {
1524 m_SearchBar->GetWindowTextW(szBuf);
1525 if (szBuf.IsEmpty())
1526 {
1527 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1528 bSearchEnabled = FALSE;
1529 m_SearchBar->SetWindowTextW(szBuf.GetString());
1530 }
1531 }
1532 break;
1533
1534 case EN_CHANGE:
1535 {
1536 ATL::CStringW szWndText;
1537
1538 if (!bSearchEnabled)
1539 {
1540 bSearchEnabled = TRUE;
1541 break;
1542 }
1543
1544 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1545 m_SearchBar->GetWindowTextW(szWndText);
1546 if (szBuf == szWndText)
1547 {
1548 szSearchPattern.Empty();
1549 }
1550 else
1551 {
1552 szSearchPattern = szWndText;
1553 }
1554
1555 DWORD dwDelay;
1556 SystemParametersInfoW(SPI_GETMENUSHOWDELAY, 0, &dwDelay, 0);
1557 SetTimer(SEARCH_TIMER_ID, dwDelay);
1558 }
1559 break;
1560 }
1561
1562 return;
1563 }
1564
1565 switch (wCommand)
1566 {
1567 case ID_OPEN_LINK:
1568 ShellExecuteW(m_hWnd, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
1569 HeapFree(GetProcessHeap(), 0, pLink);
1570 break;
1571
1572 case ID_COPY_LINK:
1573 CopyTextToClipboard(pLink);
1574 HeapFree(GetProcessHeap(), 0, pLink);
1575 break;
1576
1577 case ID_SETTINGS:
1578 CreateSettingsDlg(m_hWnd);
1579 break;
1580
1581 case ID_EXIT:
1582 PostMessageW(WM_CLOSE, 0, 0);
1583 break;
1584
1585 case ID_SEARCH:
1586 ::SetFocus(m_SearchBar->m_hWnd);
1587 break;
1588
1589 case ID_INSTALL:
1590 if (IsAvailableEnum(SelectedEnumType))
1591 {
1592 if (nSelectedApps > 0)
1593 {
1594 DownloadListOfApplications(m_AvailableApps.GetSelected(), FALSE);
1595 UpdateApplicationsList(-1);
1596 m_ListView->SetSelected(-1, FALSE);
1597 }
1598 else if (DownloadApplication(m_ListView->GetSelectedData(), FALSE))
1599 {
1600 UpdateApplicationsList(-1);
1601 }
1602
1603 }
1604 break;
1605
1606 case ID_UNINSTALL:
1607 if (UninstallSelectedApp(FALSE))
1608 UpdateApplicationsList(-1);
1609 break;
1610
1611 case ID_MODIFY:
1612 if (UninstallSelectedApp(TRUE))
1613 UpdateApplicationsList(-1);
1614 break;
1615
1616 case ID_REGREMOVE:
1617 RemoveSelectedAppFromRegistry();
1618 break;
1619
1620 case ID_REFRESH:
1621 UpdateApplicationsList(-1);
1622 break;
1623
1624 case ID_RESETDB:
1625 CAvailableApps::ForceUpdateAppsDB();
1626 UpdateApplicationsList(-1);
1627 break;
1628
1629 case ID_HELP:
1630 MessageBoxW(L"Help not implemented yet", NULL, MB_OK);
1631 break;
1632
1633 case ID_ABOUT:
1634 ShowAboutDialog();
1635 break;
1636
1637 case ID_CHECK_ALL:
1638 m_ListView->CheckAll();
1639 break;
1640 }
1641 }
1642
1643 VOID FreeInstalledAppList()
1644 {
1645 INT Count = m_ListView->GetItemCount() - 1;
1646 PINSTALLED_INFO Info;
1647
1648 while (Count >= 0)
1649 {
1650 Info = (PINSTALLED_INFO) ListViewGetlParam(Count);
1651 if (Info)
1652 {
1653 RegCloseKey(Info->hSubKey);
1654 delete Info;
1655 }
1656 Count--;
1657 }
1658 }
1659
1660 static BOOL SearchPatternMatch(LPCWSTR szHaystack, LPCWSTR szNeedle)
1661 {
1662 if (!*szNeedle)
1663 return TRUE;
1664 /* TODO: Improve pattern search beyond a simple case-insensitive substring search. */
1665 return StrStrIW(szHaystack, szNeedle) != NULL;
1666 }
1667
1668 BOOL CALLBACK EnumInstalledAppProc(INT ItemIndex, ATL::CStringW &m_szName, PINSTALLED_INFO Info)
1669 {
1670 PINSTALLED_INFO ItemInfo;
1671 ATL::CStringW szText;
1672 INT Index;
1673
1674 if (!SearchPatternMatch(m_szName.GetString(), szSearchPattern))
1675 {
1676 RegCloseKey(Info->hSubKey);
1677 return TRUE;
1678 }
1679
1680 ItemInfo = new INSTALLED_INFO(*Info);
1681 if (!ItemInfo)
1682 {
1683 RegCloseKey(Info->hSubKey);
1684 return FALSE;
1685 }
1686
1687 Index = m_ListView->AddItem(ItemIndex, 0, m_szName.GetString(), (LPARAM) ItemInfo);
1688
1689 /* Get version info */
1690 ItemInfo->GetApplicationString(L"DisplayVersion", szText);
1691 m_ListView->SetItemText(Index, 1, szText.GetString());
1692
1693 /* Get comments */
1694 ItemInfo->GetApplicationString(L"Comments", szText);
1695 m_ListView->SetItemText(Index, 2, szText.GetString());
1696
1697 return TRUE;
1698 }
1699
1700 BOOL EnumAvailableAppProc(CAvailableApplicationInfo* Info, LPCWSTR szFolderPath)
1701 {
1702 INT Index;
1703 HICON hIcon = NULL;
1704
1705 HIMAGELIST hImageListView = ListView_GetImageList(hListView, LVSIL_SMALL);
1706
1707 if (!SearchPatternMatch(Info->m_szName.GetString(), szSearchPattern) &&
1708 !SearchPatternMatch(Info->m_szDesc.GetString(), szSearchPattern))
1709 {
1710 return TRUE;
1711 }
1712
1713 /* Load icon from file */
1714 ATL::CStringW szIconPath;
1715 szIconPath.Format(L"%lsicons\\%ls.ico", szFolderPath, Info->m_szName.GetString());
1716 hIcon = (HICON) LoadImageW(NULL,
1717 szIconPath.GetString(),
1718 IMAGE_ICON,
1719 LISTVIEW_ICON_SIZE,
1720 LISTVIEW_ICON_SIZE,
1721 LR_LOADFROMFILE);
1722
1723 if (!hIcon || GetLastError() != ERROR_SUCCESS)
1724 {
1725 /* Load default icon */
1726 hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1727 }
1728
1729 Index = ImageList_AddIcon(hImageListView, hIcon);
1730 DestroyIcon(hIcon);
1731
1732 Index = m_ListView->AddItem(Info->m_Category, Index, Info->m_szName.GetString(), (LPARAM) Info);
1733 m_ListView->SetImageList(hImageListView, LVSIL_SMALL);
1734 m_ListView->SetItemText(Index, 1, Info->m_szVersion.GetString());
1735 m_ListView->SetItemText(Index, 2, Info->m_szDesc.GetString());
1736 m_ListView->SetCheckState(Index, Info->m_IsSelected);
1737
1738 return TRUE;
1739 }
1740
1741 static BOOL CALLBACK s_EnumInstalledAppProc(INT ItemIndex, ATL::CStringW &m_szName, PINSTALLED_INFO Info, PVOID param)
1742 {
1743 CMainWindow* pThis = (CMainWindow*)param;
1744 return pThis->EnumInstalledAppProc(ItemIndex, m_szName, Info);
1745 }
1746
1747 static BOOL CALLBACK s_EnumAvailableAppProc(CAvailableApplicationInfo* Info, LPCWSTR szFolderPath, PVOID param)
1748 {
1749 CMainWindow* pThis = (CMainWindow*)param;
1750 return pThis->EnumAvailableAppProc(Info, szFolderPath);
1751 }
1752
1753 VOID UpdateStatusBarText()
1754 {
1755 if (m_StatusBar)
1756 {
1757 ATL::CStringW szBuffer;
1758
1759 szBuffer.Format(IDS_APPS_COUNT, m_ListView->GetItemCount(), nSelectedApps);
1760 m_StatusBar->SetText(szBuffer);
1761 }
1762 }
1763
1764 VOID UpdateApplicationsList(INT EnumType)
1765 {
1766 ATL::CStringW szBuffer1, szBuffer2;
1767 HIMAGELIST hImageListView;
1768 BOOL bWasInInstalled = IsInstalledEnum(SelectedEnumType);
1769
1770 bUpdating = TRUE;
1771 m_ListView->SetRedraw(FALSE);
1772
1773 if (EnumType < 0)
1774 {
1775 EnumType = SelectedEnumType;
1776 }
1777
1778 //if previous one was INSTALLED purge the list
1779 //TODO: make the Installed category a separate class to avoid doing this
1780 if (bWasInInstalled)
1781 {
1782 FreeInstalledAppList();
1783 }
1784
1785 m_ListView->DeleteAllItems();
1786
1787 // Create new ImageList
1788 hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
1789 LISTVIEW_ICON_SIZE,
1790 GetSystemColorDepth() | ILC_MASK,
1791 0, 1);
1792 HIMAGELIST hImageListBuf = m_ListView->SetImageList(hImageListView, LVSIL_SMALL);
1793 if (hImageListBuf)
1794 {
1795 ImageList_Destroy(hImageListBuf);
1796 }
1797
1798 if (IsInstalledEnum(EnumType))
1799 {
1800 if (!bWasInInstalled)
1801 {
1802 m_ListView->SetCheckboxesVisible(FALSE);
1803 }
1804
1805 HICON hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1806 ImageList_AddIcon(hImageListView, hIcon);
1807 DestroyIcon(hIcon);
1808
1809 // Enum installed applications and updates
1810 EnumInstalledApplications(EnumType, TRUE, s_EnumInstalledAppProc, this);
1811 EnumInstalledApplications(EnumType, FALSE, s_EnumInstalledAppProc, this);
1812 }
1813 else if (IsAvailableEnum(EnumType))
1814 {
1815 if (bWasInInstalled)
1816 {
1817 m_ListView->SetCheckboxesVisible(TRUE);
1818 }
1819
1820 // Enum available applications
1821 m_AvailableApps.Enum(EnumType, s_EnumAvailableAppProc, this);
1822 }
1823
1824 SelectedEnumType = EnumType;
1825 UpdateStatusBarText();
1826 m_RichEdit->SetWelcomeText();
1827
1828 // Set automatic column width for program names if the list is not empty
1829 if (m_ListView->GetItemCount() > 0)
1830 {
1831 ListView_SetColumnWidth(m_ListView->GetWindow(), 0, LVSCW_AUTOSIZE);
1832 }
1833
1834 bUpdating = FALSE;
1835 m_ListView->SetRedraw(TRUE);
1836 }
1837
1838 public:
1839 static ATL::CWndClassInfo& GetWndClassInfo()
1840 {
1841 DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
1842 static ATL::CWndClassInfo wc =
1843 {
1844 {
1845 sizeof(WNDCLASSEX),
1846 csStyle,
1847 StartWindowProc,
1848 0,
1849 0,
1850 NULL,
1851 LoadIconW(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCEW(IDI_MAIN)),
1852 LoadCursorW(NULL, IDC_ARROW),
1853 (HBRUSH) (COLOR_BTNFACE + 1),
1854 MAKEINTRESOURCEW(IDR_MAINMENU),
1855 L"RAppsWnd",
1856 NULL
1857 },
1858 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
1859 };
1860 return wc;
1861 }
1862
1863 HWND Create()
1864 {
1865 ATL::CStringW szWindowName;
1866 szWindowName.LoadStringW(IDS_APPTITLE);
1867
1868 RECT r = {
1869 (SettingsInfo.bSaveWndPos ? SettingsInfo.Left : CW_USEDEFAULT),
1870 (SettingsInfo.bSaveWndPos ? SettingsInfo.Top : CW_USEDEFAULT),
1871 (SettingsInfo.bSaveWndPos ? SettingsInfo.Width : 680),
1872 (SettingsInfo.bSaveWndPos ? SettingsInfo.Height : 450)
1873 };
1874 r.right += r.left;
1875 r.bottom += r.top;
1876
1877 return CWindowImpl::Create(NULL, r, szWindowName.GetString(), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE);
1878 }
1879
1880 CStatusBar * GetStatusBar()
1881 {
1882 return m_StatusBar;
1883 }
1884
1885 CAppsListView * GetListView()
1886 {
1887 return m_ListView;
1888 }
1889
1890 CRichEdit * GetRichEdit()
1891 {
1892 return m_RichEdit;
1893 }
1894
1895 CAvailableApps * GetAvailableApps()
1896 {
1897 return &m_AvailableApps;
1898 }
1899 };
1900
1901 // global interface
1902 CMainWindow * g_MainWindow;
1903
1904 HWND CreateMainWindow()
1905 {
1906 g_MainWindow = new CMainWindow();
1907 return g_MainWindow->Create();
1908 }
1909
1910 DWORD_PTR ListViewGetlParam(INT item)
1911 {
1912 if (item < 0)
1913 {
1914 item = g_MainWindow->GetListView()->GetSelectionMark();
1915 }
1916 return g_MainWindow->GetListView()->GetItemData(item);
1917 }
1918
1919 VOID SetStatusBarText(LPCWSTR szText)
1920 {
1921 g_MainWindow->GetStatusBar()->SetText(szText);
1922 }
1923
1924 INT ListViewAddItem(INT ItemIndex, INT IconIndex, LPWSTR lpName, LPARAM lParam)
1925 {
1926 return g_MainWindow->GetListView()->AddItem(ItemIndex, IconIndex, lpName, lParam);
1927 }
1928
1929 VOID NewRichEditText(LPCWSTR szText, DWORD flags)
1930 {
1931 g_MainWindow->GetRichEdit()->SetText(szText, flags);
1932 }
1933
1934 VOID InsertRichEditText(LPCWSTR szText, DWORD flags)
1935 {
1936 g_MainWindow->GetRichEdit()->InsertText(szText, flags);
1937 }
1938
1939 CAvailableApps* GetAvailableApps()
1940 {
1941 return g_MainWindow->GetAvailableApps();
1942 }
1943
1944 // ATL version of functions above
1945 VOID SetStatusBarText(const ATL::CStringW& szText)
1946 {
1947 SetStatusBarText(szText.GetString());
1948 }
1949
1950 INT ListViewAddItem(INT ItemIndex, INT IconIndex, const ATL::CStringW& Name, LPARAM lParam)
1951 {
1952 return ListViewAddItem(ItemIndex, IconIndex, const_cast<LPWSTR>(Name.GetString()), lParam);
1953 }
1954
1955 VOID NewRichEditText(const ATL::CStringW& szText, DWORD flags)
1956 {
1957 NewRichEditText(szText.GetString(), flags);
1958 }
1959
1960 VOID InsertRichEditText(const ATL::CStringW& szText, DWORD flags)
1961 {
1962 InsertRichEditText(szText.GetString(), flags);
1963 }
1964
1965 VOID ShowMainWindow(INT nShowCmd)
1966 {
1967 HACCEL KeyBrd;
1968 MSG Msg;
1969
1970 hMainWnd = CreateMainWindow();
1971
1972 if (hMainWnd)
1973 {
1974 /* Maximize it if we must */
1975 ShowWindow(hMainWnd, ((SettingsInfo.bSaveWndPos && SettingsInfo.Maximized) ? SW_MAXIMIZE : nShowCmd));
1976 UpdateWindow(hMainWnd);
1977
1978 /* Load the menu hotkeys */
1979 KeyBrd = LoadAcceleratorsW(NULL, MAKEINTRESOURCEW(HOTKEYS));
1980
1981 /* Message Loop */
1982 while (GetMessageW(&Msg, NULL, 0, 0))
1983 {
1984 if (!TranslateAcceleratorW(hMainWnd, KeyBrd, &Msg))
1985 {
1986 TranslateMessage(&Msg);
1987 DispatchMessageW(&Msg);
1988 }
1989 }
1990 }
1991 }