064ec4ee4634887e2e0d0ee57c49adb01375c14f
[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 LVITEMW Item;
515
516 if (Index == -1)
517 {
518 ItemIndex = (INT) SendMessage(LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
519 if (ItemIndex == -1)
520 return NULL;
521 }
522 else
523 {
524 ItemIndex = Index;
525 }
526
527 ZeroMemory(&Item, sizeof(Item));
528
529 Item.mask = LVIF_PARAM;
530 Item.iItem = ItemIndex;
531 if (!GetItem(&Item))
532 return NULL;
533
534 return (PVOID) Item.lParam;
535 }
536
537 BOOL AddColumn(INT Index, ATL::CStringW& Text, INT Width, INT Format)
538 {
539 return AddColumn(Index, const_cast<LPWSTR>(Text.GetString()), Width, Format);
540 }
541
542 BOOL AddColumn(INT Index, LPWSTR lpText, INT Width, INT Format)
543 {
544 LVCOLUMNW Column;
545
546 ZeroMemory(&Column, sizeof(Column));
547
548 Column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
549 Column.iSubItem = Index;
550 Column.pszText = lpText;
551 Column.cx = Width;
552 Column.fmt = Format;
553
554 return (InsertColumn(Index, &Column) == -1) ? FALSE : TRUE;
555 }
556
557 INT AddItem(INT ItemIndex, INT IconIndex, LPCWSTR lpText, LPARAM lParam)
558 {
559 LVITEMW Item;
560
561 ZeroMemory(&Item, sizeof(Item));
562
563 Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
564 Item.pszText = const_cast<LPWSTR>(lpText);
565 Item.lParam = lParam;
566 Item.iItem = ItemIndex;
567 Item.iImage = IconIndex;
568
569 return InsertItem(&Item);
570 }
571
572 static INT CALLBACK s_CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
573 {
574 SortContext * ctx = ((SortContext*) lParamSort);
575 return ctx->lvw->CompareFunc(lParam1, lParam2, ctx->iSubItem);
576 }
577
578 INT CompareFunc(LPARAM lParam1, LPARAM lParam2, INT iSubItem)
579 {
580 ATL::CStringW Item1, Item2;
581 LVFINDINFOW IndexInfo;
582 INT Index;
583
584 IndexInfo.flags = LVFI_PARAM;
585
586 IndexInfo.lParam = lParam1;
587 Index = FindItem(-1, &IndexInfo);
588 GetItemText(Index, iSubItem, Item1.GetBuffer(MAX_STR_LEN), MAX_STR_LEN);
589 Item1.ReleaseBuffer();
590
591 IndexInfo.lParam = lParam2;
592 Index = FindItem(-1, &IndexInfo);
593 GetItemText(Index, iSubItem, Item2.GetBuffer(MAX_STR_LEN), MAX_STR_LEN);
594 Item2.ReleaseBuffer();
595
596 return bIsAscending ? Item1.Compare(Item2) : Item2.Compare(Item1);
597 }
598
599 HWND Create(HWND hwndParent)
600 {
601 RECT r = {205, 28, 465, 250};
602 DWORD style = WS_CHILD | WS_VISIBLE | LVS_SORTASCENDING | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS;
603 HMENU menu = GetSubMenu(LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_APPLICATIONMENU)), 0);
604
605 HWND hwnd = CListView::Create(hwndParent, r, NULL, style, WS_EX_CLIENTEDGE, menu);
606
607 if (hwnd)
608 {
609 SetCheckboxesVisible(FALSE);
610 }
611
612 return hwnd;
613 }
614
615 BOOL GetCheckState(INT item)
616 {
617 return (BOOL) (GetItemState(item, LVIS_STATEIMAGEMASK) >> 12) - 1;
618 }
619
620 VOID SetCheckState(INT item, BOOL fCheck)
621 {
622 if (bHasCheckboxes)
623 {
624 SetItemState(item, INDEXTOSTATEIMAGEMASK((fCheck) ? 2 : 1), LVIS_STATEIMAGEMASK);
625 SetSelected(item, fCheck);
626 }
627 }
628
629 VOID SetSelected(INT item, BOOL value)
630 {
631 if (item < 0)
632 {
633 for (INT i = 0; i >= 0; i = GetNextItem(i, LVNI_ALL))
634 {
635 CAvailableApplicationInfo* pAppInfo = (CAvailableApplicationInfo*) GetItemData(i);
636 if (pAppInfo)
637 {
638 pAppInfo->m_IsSelected = value;
639 }
640 }
641 }
642 else
643 {
644 CAvailableApplicationInfo* pAppInfo = (CAvailableApplicationInfo*) GetItemData(item);
645 if (pAppInfo)
646 {
647 pAppInfo->m_IsSelected = value;
648 }
649 }
650 }
651
652 VOID CheckAll()
653 {
654 if (bHasCheckboxes)
655 {
656 bHasAllChecked = !bHasAllChecked;
657 SetCheckState(-1, bHasAllChecked);
658 }
659 }
660
661 ATL::CSimpleArray<CAvailableApplicationInfo> GetCheckedItems()
662 {
663 if (!bHasCheckboxes)
664 {
665 return ATL::CSimpleArray<CAvailableApplicationInfo>();
666 }
667
668 ATL::CSimpleArray<CAvailableApplicationInfo> list;
669 for (INT i = 0; i >= 0; i = GetNextItem(i, LVNI_ALL))
670 {
671 if (GetCheckState(i) != FALSE)
672 {
673 CAvailableApplicationInfo* pAppInfo = (CAvailableApplicationInfo*) GetItemData(i);
674 list.Add(*pAppInfo);
675 }
676 }
677 return list;
678 }
679
680 CAvailableApplicationInfo* GetSelectedData()
681 {
682 INT item = GetSelectionMark();
683 return (CAvailableApplicationInfo*) GetItemData(item);
684 }
685 };
686
687 class CSideTreeView :
688 public CUiWindow<CTreeView>
689 {
690 HIMAGELIST hImageTreeView;
691
692 public:
693 CSideTreeView() :
694 CUiWindow(),
695 hImageTreeView(ImageList_Create(TREEVIEW_ICON_SIZE, TREEVIEW_ICON_SIZE,
696 GetSystemColorDepth() | ILC_MASK,
697 0, 1))
698 {
699 }
700
701 HTREEITEM AddItem(HTREEITEM hParent, ATL::CStringW &Text, INT Image, INT SelectedImage, LPARAM lParam)
702 {
703 return CUiWindow<CTreeView>::AddItem(hParent, const_cast<LPWSTR>(Text.GetString()), Image, SelectedImage, lParam);
704 }
705
706 HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
707 {
708 ATL::CStringW szText;
709 INT Index;
710 HICON hIcon;
711
712 hIcon = (HICON) LoadImageW(hInst,
713 MAKEINTRESOURCE(IconIndex),
714 IMAGE_ICON,
715 TREEVIEW_ICON_SIZE,
716 TREEVIEW_ICON_SIZE,
717 LR_CREATEDIBSECTION);
718 if (hIcon)
719 {
720 Index = ImageList_AddIcon(hImageTreeView, hIcon);
721 DestroyIcon(hIcon);
722 }
723
724 szText.LoadStringW(TextIndex);
725 return AddItem(hRootItem, szText, Index, Index, TextIndex);
726 }
727
728 HIMAGELIST SetImageList()
729 {
730 return CUiWindow<CTreeView>::SetImageList(hImageTreeView, TVSIL_NORMAL);
731 }
732
733 VOID DestroyImageList()
734 {
735 if (hImageTreeView)
736 ImageList_Destroy(hImageTreeView);
737 }
738
739 ~CSideTreeView()
740 {
741 DestroyImageList();
742 }
743 };
744
745 class CSearchBar :
746 public CWindow
747 {
748 public:
749 const INT m_Width;
750 const INT m_Height;
751
752 CSearchBar() : m_Width(200), m_Height(22)
753 {
754 }
755
756 VOID SetText(LPCWSTR lpszText)
757 {
758 SendMessageW(SB_SETTEXT, SBT_NOBORDERS, (LPARAM) lpszText);
759 }
760
761 HWND Create(HWND hwndParent)
762 {
763 ATL::CStringW szBuf;
764 m_hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL,
765 WS_CHILD | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
766 0, 0, m_Width, m_Height,
767 hwndParent, (HMENU) NULL,
768 hInst, 0);
769
770 SendMessageW(WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0);
771 szBuf.LoadStringW(IDS_SEARCH_TEXT);
772 SetWindowTextW(szBuf);
773 return m_hWnd;
774 }
775
776 };
777
778 class CMainWindow :
779 public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>
780 {
781 CUiPanel* m_ClientPanel;
782 CUiSplitPanel* m_VSplitter;
783 CUiSplitPanel* m_HSplitter;
784
785 CMainToolbar* m_Toolbar;
786 CAppsListView* m_ListView;
787
788 CSideTreeView* m_TreeView;
789 CUiWindow<CStatusBar>* m_StatusBar;
790 CAppRichEdit* m_RichEdit;
791
792 CUiWindow<CSearchBar>* m_SearchBar;
793 CAvailableApps m_AvailableApps;
794
795 LPWSTR pLink;
796
797 INT nSelectedApps;
798
799 BOOL bSearchEnabled;
800 BOOL bUpdating;
801
802 public:
803 CMainWindow() :
804 m_ClientPanel(NULL),
805 pLink(NULL),
806 bSearchEnabled(FALSE)
807 {
808 }
809
810 private:
811 VOID InitApplicationsList()
812 {
813 ATL::CStringW szText;
814
815 /* Add columns to ListView */
816 szText.LoadStringW(IDS_APP_NAME);
817 m_ListView->AddColumn(0, szText, 250, LVCFMT_LEFT);
818
819 szText.LoadStringW(IDS_APP_INST_VERSION);
820 m_ListView->AddColumn(1, szText, 90, LVCFMT_RIGHT);
821
822 szText.LoadStringW(IDS_APP_DESCRIPTION);
823 m_ListView->AddColumn(3, szText, 300, LVCFMT_LEFT);
824
825 // Unnesesary since the list updates on every TreeView selection
826 // UpdateApplicationsList(ENUM_ALL_COMPONENTS);
827 }
828
829 HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
830 {
831 return m_TreeView->AddCategory(hRootItem, TextIndex, IconIndex);
832 }
833
834 VOID InitCategoriesList()
835 {
836 HTREEITEM hRootItemInstalled, hRootItemAvailable;
837
838 hRootItemInstalled = AddCategory(TVI_ROOT, IDS_INSTALLED, IDI_CATEGORY);
839 AddCategory(hRootItemInstalled, IDS_APPLICATIONS, IDI_APPS);
840 AddCategory(hRootItemInstalled, IDS_UPDATES, IDI_APPUPD);
841
842 AddCategory(TVI_ROOT, IDS_SELECTEDFORINST, IDI_SELECTEDFORINST);
843
844 hRootItemAvailable = AddCategory(TVI_ROOT, IDS_AVAILABLEFORINST, IDI_CATEGORY);
845 AddCategory(hRootItemAvailable, IDS_CAT_AUDIO, IDI_CAT_AUDIO);
846 AddCategory(hRootItemAvailable, IDS_CAT_VIDEO, IDI_CAT_VIDEO);
847 AddCategory(hRootItemAvailable, IDS_CAT_GRAPHICS, IDI_CAT_GRAPHICS);
848 AddCategory(hRootItemAvailable, IDS_CAT_GAMES, IDI_CAT_GAMES);
849 AddCategory(hRootItemAvailable, IDS_CAT_INTERNET, IDI_CAT_INTERNET);
850 AddCategory(hRootItemAvailable, IDS_CAT_OFFICE, IDI_CAT_OFFICE);
851 AddCategory(hRootItemAvailable, IDS_CAT_DEVEL, IDI_CAT_DEVEL);
852 AddCategory(hRootItemAvailable, IDS_CAT_EDU, IDI_CAT_EDU);
853 AddCategory(hRootItemAvailable, IDS_CAT_ENGINEER, IDI_CAT_ENGINEER);
854 AddCategory(hRootItemAvailable, IDS_CAT_FINANCE, IDI_CAT_FINANCE);
855 AddCategory(hRootItemAvailable, IDS_CAT_SCIENCE, IDI_CAT_SCIENCE);
856 AddCategory(hRootItemAvailable, IDS_CAT_TOOLS, IDI_CAT_TOOLS);
857 AddCategory(hRootItemAvailable, IDS_CAT_DRIVERS, IDI_CAT_DRIVERS);
858 AddCategory(hRootItemAvailable, IDS_CAT_LIBS, IDI_CAT_LIBS);
859 AddCategory(hRootItemAvailable, IDS_CAT_THEMES, IDI_CAT_THEMES);
860 AddCategory(hRootItemAvailable, IDS_CAT_OTHER, IDI_CAT_OTHER);
861
862 m_TreeView->SetImageList();
863 m_TreeView->Expand(hRootItemInstalled, TVE_EXPAND);
864 m_TreeView->Expand(hRootItemAvailable, TVE_EXPAND);
865 m_TreeView->SelectItem(hRootItemAvailable);
866 }
867
868 BOOL CreateStatusBar()
869 {
870 m_StatusBar = new CUiWindow<CStatusBar>();
871 m_StatusBar->m_VerticalAlignment = UiAlign_RightBtm;
872 m_StatusBar->m_HorizontalAlignment = UiAlign_Stretch;
873 m_ClientPanel->Children().Append(m_StatusBar);
874
875 return m_StatusBar->Create(m_hWnd, (HMENU) IDC_STATUSBAR) != NULL;
876 }
877
878 BOOL CreateToolbar()
879 {
880 m_Toolbar = new CMainToolbar();
881 m_Toolbar->m_VerticalAlignment = UiAlign_LeftTop;
882 m_Toolbar->m_HorizontalAlignment = UiAlign_Stretch;
883 m_ClientPanel->Children().Append(m_Toolbar);
884
885 return m_Toolbar->Create(m_hWnd) != NULL;
886 }
887
888 BOOL CreateTreeView()
889 {
890 m_TreeView = new CSideTreeView();
891 m_TreeView->m_VerticalAlignment = UiAlign_Stretch;
892 m_TreeView->m_HorizontalAlignment = UiAlign_Stretch;
893 m_VSplitter->First().Append(m_TreeView);
894
895 return m_TreeView->Create(m_hWnd) != NULL;
896 }
897
898 BOOL CreateListView()
899 {
900 m_ListView = new CAppsListView();
901 m_ListView->m_VerticalAlignment = UiAlign_Stretch;
902 m_ListView->m_HorizontalAlignment = UiAlign_Stretch;
903 m_HSplitter->First().Append(m_ListView);
904
905 hListView = m_ListView->Create(m_hWnd);
906 return hListView != NULL;
907 }
908
909 BOOL CreateRichEdit()
910 {
911 m_RichEdit = new CAppRichEdit();
912 m_RichEdit->m_VerticalAlignment = UiAlign_Stretch;
913 m_RichEdit->m_HorizontalAlignment = UiAlign_Stretch;
914 m_HSplitter->Second().Append(m_RichEdit);
915
916 return m_RichEdit->Create(m_hWnd) != NULL;
917 }
918
919 BOOL CreateVSplitter()
920 {
921 m_VSplitter = new CUiSplitPanel();
922 m_VSplitter->m_VerticalAlignment = UiAlign_Stretch;
923 m_VSplitter->m_HorizontalAlignment = UiAlign_Stretch;
924 m_VSplitter->m_DynamicFirst = FALSE;
925 m_VSplitter->m_Horizontal = FALSE;
926 m_VSplitter->m_MinFirst = 0;
927 m_VSplitter->m_MinSecond = 320;
928 m_VSplitter->m_Pos = 240;
929 m_ClientPanel->Children().Append(m_VSplitter);
930
931 return m_VSplitter->Create(m_hWnd) != NULL;
932 }
933
934 BOOL CreateHSplitter()
935 {
936 m_HSplitter = new CUiSplitPanel();
937 m_HSplitter->m_VerticalAlignment = UiAlign_Stretch;
938 m_HSplitter->m_HorizontalAlignment = UiAlign_Stretch;
939 m_HSplitter->m_DynamicFirst = TRUE;
940 m_HSplitter->m_Horizontal = TRUE;
941 m_HSplitter->m_Pos = INT_MAX; //set INT_MAX to use lowest possible position (m_MinSecond)
942 m_HSplitter->m_MinFirst = 10;
943 m_HSplitter->m_MinSecond = 140;
944 m_VSplitter->Second().Append(m_HSplitter);
945
946 return m_HSplitter->Create(m_hWnd) != NULL;
947 }
948
949 BOOL CreateSearchBar()
950 {
951 m_SearchBar = new CUiWindow<CSearchBar>();
952 m_SearchBar->m_VerticalAlignment = UiAlign_LeftTop;
953 m_SearchBar->m_HorizontalAlignment = UiAlign_RightBtm;
954 m_SearchBar->m_Margin.top = 4;
955 m_SearchBar->m_Margin.right = 6;
956
957 return m_SearchBar->Create(m_Toolbar->m_hWnd) != NULL;
958 }
959
960 BOOL CreateLayout()
961 {
962 BOOL b = TRUE;
963 bUpdating = TRUE;
964
965 m_ClientPanel = new CUiPanel();
966 m_ClientPanel->m_VerticalAlignment = UiAlign_Stretch;
967 m_ClientPanel->m_HorizontalAlignment = UiAlign_Stretch;
968
969 // Top level
970 b = b && CreateStatusBar();
971 b = b && CreateToolbar();
972 b = b && CreateSearchBar();
973 b = b && CreateVSplitter();
974
975 // Inside V Splitter
976 b = b && CreateHSplitter();
977 b = b && CreateTreeView();
978
979 // Inside H Splitter
980 b = b && CreateListView();
981 b = b && CreateRichEdit();
982
983 if (b)
984 {
985 RECT rTop;
986 RECT rBottom;
987
988 /* Size status bar */
989 m_StatusBar->SendMessageW(WM_SIZE, 0, 0);
990
991 /* Size tool bar */
992 m_Toolbar->AutoSize();
993
994 ::GetWindowRect(m_Toolbar->m_hWnd, &rTop);
995 ::GetWindowRect(m_StatusBar->m_hWnd, &rBottom);
996
997 m_VSplitter->m_Margin.top = rTop.bottom - rTop.top;
998 m_VSplitter->m_Margin.bottom = rBottom.bottom - rBottom.top;
999 }
1000
1001 bUpdating = FALSE;
1002 return b;
1003 }
1004
1005 BOOL InitControls()
1006 {
1007 if (CreateLayout())
1008 {
1009
1010 InitApplicationsList();
1011 InitCategoriesList();
1012
1013 nSelectedApps = 0;
1014 UpdateStatusBarText();
1015
1016 return TRUE;
1017 }
1018
1019 return FALSE;
1020 }
1021
1022 VOID ShowAppInfo(INT Index)
1023 {
1024 if (IsInstalledEnum(SelectedEnumType))
1025 {
1026 if (Index == -1)
1027 Index = m_ListView->GetSelectionMark();
1028
1029 PINSTALLED_INFO Info = (PINSTALLED_INFO) m_ListView->GetItemData(Index);
1030
1031 m_RichEdit->ShowInstalledAppInfo(Info);
1032 }
1033 else if (IsAvailableEnum(SelectedEnumType))
1034 {
1035 if (Index == -1)
1036 return;
1037
1038 CAvailableApplicationInfo* Info = (CAvailableApplicationInfo*) m_ListView->GetItemData(Index);
1039
1040 m_RichEdit->ShowAvailableAppInfo(Info);
1041 }
1042 }
1043
1044 VOID OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
1045 {
1046 if (wParam == SIZE_MINIMIZED)
1047 return;
1048
1049 /* Size status bar */
1050 m_StatusBar->SendMessage(WM_SIZE, 0, 0);
1051
1052 /* Size tool bar */
1053 m_Toolbar->AutoSize();
1054
1055 /* Automatically hide captions */
1056 DWORD dToolbarTreshold = m_Toolbar->GetMaxButtonsWidth();
1057 DWORD dSearchbarMargin = (LOWORD(lParam) - m_SearchBar->m_Width);
1058
1059 if (dSearchbarMargin > dToolbarTreshold)
1060 {
1061 m_Toolbar->ShowButtonCaption();
1062 }
1063 else if (dSearchbarMargin < dToolbarTreshold)
1064 {
1065 m_Toolbar->HideButtonCaption();
1066 }
1067
1068 RECT r = {0, 0, LOWORD(lParam), HIWORD(lParam)};
1069 HDWP hdwp = NULL;
1070 INT count = m_ClientPanel->CountSizableChildren();
1071
1072 hdwp = BeginDeferWindowPos(count);
1073 if (hdwp)
1074 {
1075 hdwp = m_ClientPanel->OnParentSize(r, hdwp);
1076 if (hdwp)
1077 {
1078 EndDeferWindowPos(hdwp);
1079 }
1080
1081 }
1082
1083 // TODO: Sub-layouts for children of children
1084 count = m_SearchBar->CountSizableChildren();
1085 hdwp = BeginDeferWindowPos(count);
1086 if (hdwp)
1087 {
1088 hdwp = m_SearchBar->OnParentSize(r, hdwp);
1089 if (hdwp)
1090 {
1091 EndDeferWindowPos(hdwp);
1092 }
1093 }
1094
1095 }
1096
1097 VOID RemoveSelectedAppFromRegistry()
1098 {
1099 PINSTALLED_INFO Info;
1100 WCHAR szFullName[MAX_PATH] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\";
1101 ATL::CStringW szMsgText, szMsgTitle;
1102 INT ItemIndex = m_ListView->GetNextItem(-1, LVNI_FOCUSED);
1103
1104 if (!IsInstalledEnum(SelectedEnumType))
1105 return;
1106
1107 Info = reinterpret_cast<PINSTALLED_INFO>(m_ListView->GetItemData(ItemIndex));
1108 if (!Info || !Info->hSubKey || (ItemIndex == -1))
1109 return;
1110
1111 if (!szMsgText.LoadStringW(IDS_APP_REG_REMOVE) ||
1112 !szMsgTitle.LoadStringW(IDS_INFORMATION))
1113 return;
1114
1115 if (MessageBoxW(szMsgText, szMsgTitle, MB_YESNO | MB_ICONQUESTION) == IDYES)
1116 {
1117 ATL::CStringW::CopyChars(szFullName,
1118 MAX_PATH,
1119 Info->szKeyName.GetString(),
1120 MAX_PATH - wcslen(szFullName));
1121
1122 if (RegDeleteKeyW(Info->hRootKey, szFullName) == ERROR_SUCCESS)
1123 {
1124 m_ListView->DeleteItem(ItemIndex);
1125 return;
1126 }
1127
1128 if (!szMsgText.LoadStringW(IDS_UNABLE_TO_REMOVE))
1129 return;
1130
1131 MessageBoxW(szMsgText.GetString(), NULL, MB_OK | MB_ICONERROR);
1132 }
1133 }
1134
1135 BOOL ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT& theResult, DWORD dwMapId)
1136 {
1137 theResult = 0;
1138 switch (Msg)
1139 {
1140 case WM_CREATE:
1141 if (!InitControls())
1142 ::PostMessageW(hwnd, WM_CLOSE, 0, 0);
1143 break;
1144
1145 case WM_DESTROY:
1146 {
1147 ShowWindow(SW_HIDE);
1148 SaveSettings(hwnd);
1149
1150 FreeLogs();
1151 m_AvailableApps.FreeCachedEntries();
1152
1153 if (IsInstalledEnum(SelectedEnumType))
1154 FreeInstalledAppList();
1155
1156 delete m_ClientPanel;
1157
1158 PostQuitMessage(0);
1159 return 0;
1160 }
1161
1162 case WM_COMMAND:
1163 OnCommand(wParam, lParam);
1164 break;
1165
1166 case WM_NOTIFY:
1167 {
1168 LPNMHDR data = (LPNMHDR) lParam;
1169
1170 switch (data->code)
1171 {
1172 case TVN_SELCHANGED:
1173 {
1174 if (data->hwndFrom == m_TreeView->m_hWnd)
1175 {
1176 switch (((LPNMTREEVIEW) lParam)->itemNew.lParam)
1177 {
1178 case IDS_INSTALLED:
1179 UpdateApplicationsList(ENUM_ALL_INSTALLED);
1180 break;
1181
1182 case IDS_APPLICATIONS:
1183 UpdateApplicationsList(ENUM_INSTALLED_APPLICATIONS);
1184 break;
1185
1186 case IDS_UPDATES:
1187 UpdateApplicationsList(ENUM_UPDATES);
1188 break;
1189
1190 case IDS_AVAILABLEFORINST:
1191 UpdateApplicationsList(ENUM_ALL_AVAILABLE);
1192 break;
1193
1194 case IDS_CAT_AUDIO:
1195 UpdateApplicationsList(ENUM_CAT_AUDIO);
1196 break;
1197
1198 case IDS_CAT_DEVEL:
1199 UpdateApplicationsList(ENUM_CAT_DEVEL);
1200 break;
1201
1202 case IDS_CAT_DRIVERS:
1203 UpdateApplicationsList(ENUM_CAT_DRIVERS);
1204 break;
1205
1206 case IDS_CAT_EDU:
1207 UpdateApplicationsList(ENUM_CAT_EDU);
1208 break;
1209
1210 case IDS_CAT_ENGINEER:
1211 UpdateApplicationsList(ENUM_CAT_ENGINEER);
1212 break;
1213
1214 case IDS_CAT_FINANCE:
1215 UpdateApplicationsList(ENUM_CAT_FINANCE);
1216 break;
1217
1218 case IDS_CAT_GAMES:
1219 UpdateApplicationsList(ENUM_CAT_GAMES);
1220 break;
1221
1222 case IDS_CAT_GRAPHICS:
1223 UpdateApplicationsList(ENUM_CAT_GRAPHICS);
1224 break;
1225
1226 case IDS_CAT_INTERNET:
1227 UpdateApplicationsList(ENUM_CAT_INTERNET);
1228 break;
1229
1230 case IDS_CAT_LIBS:
1231 UpdateApplicationsList(ENUM_CAT_LIBS);
1232 break;
1233
1234 case IDS_CAT_OFFICE:
1235 UpdateApplicationsList(ENUM_CAT_OFFICE);
1236 break;
1237
1238 case IDS_CAT_OTHER:
1239 UpdateApplicationsList(ENUM_CAT_OTHER);
1240 break;
1241
1242 case IDS_CAT_SCIENCE:
1243 UpdateApplicationsList(ENUM_CAT_SCIENCE);
1244 break;
1245
1246 case IDS_CAT_TOOLS:
1247 UpdateApplicationsList(ENUM_CAT_TOOLS);
1248 break;
1249
1250 case IDS_CAT_VIDEO:
1251 UpdateApplicationsList(ENUM_CAT_VIDEO);
1252 break;
1253
1254 case IDS_CAT_THEMES:
1255 UpdateApplicationsList(ENUM_CAT_THEMES);
1256 break;
1257
1258 case IDS_SELECTEDFORINST:
1259 UpdateApplicationsList(ENUM_CAT_SELECTED);
1260 break;
1261 }
1262 }
1263
1264 HMENU mainMenu = ::GetMenu(hwnd);
1265 HMENU lvwMenu = ::GetMenu(m_ListView->m_hWnd);
1266
1267 /* Disable/enable items based on treeview selection */
1268 if (IsSelectedNodeInstalled())
1269 {
1270 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_ENABLED);
1271 EnableMenuItem(mainMenu, ID_INSTALL, MF_GRAYED);
1272 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_ENABLED);
1273 EnableMenuItem(mainMenu, ID_MODIFY, MF_ENABLED);
1274
1275 EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_ENABLED);
1276 EnableMenuItem(lvwMenu, ID_INSTALL, MF_GRAYED);
1277 EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_ENABLED);
1278 EnableMenuItem(lvwMenu, ID_MODIFY, MF_ENABLED);
1279
1280 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, TRUE);
1281 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, FALSE);
1282 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, TRUE);
1283 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, TRUE);
1284 }
1285 else
1286 {
1287 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_GRAYED);
1288 EnableMenuItem(mainMenu, ID_INSTALL, MF_ENABLED);
1289 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_GRAYED);
1290 EnableMenuItem(mainMenu, ID_MODIFY, MF_GRAYED);
1291
1292 EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_GRAYED);
1293 EnableMenuItem(lvwMenu, ID_INSTALL, MF_ENABLED);
1294 EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_GRAYED);
1295 EnableMenuItem(lvwMenu, ID_MODIFY, MF_GRAYED);
1296
1297 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, FALSE);
1298 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, TRUE);
1299 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, FALSE);
1300 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, FALSE);
1301 }
1302 }
1303 break;
1304
1305 case LVN_ITEMCHANGED:
1306 {
1307 LPNMLISTVIEW pnic = (LPNMLISTVIEW) lParam;
1308
1309 if (pnic->hdr.hwndFrom == m_ListView->m_hWnd)
1310 {
1311 /* Check if this is a valid item
1312 * (technically, it can be also an unselect) */
1313 INT ItemIndex = pnic->iItem;
1314 if (ItemIndex == -1 ||
1315 ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
1316 {
1317 break;
1318 }
1319
1320 /* Check if the focus has been moved to another item */
1321 if ((pnic->uChanged & LVIF_STATE) &&
1322 (pnic->uNewState & LVIS_FOCUSED) &&
1323 !(pnic->uOldState & LVIS_FOCUSED))
1324 {
1325 ShowAppInfo(ItemIndex);
1326 }
1327 /* Check if the item is checked */
1328 if ((pnic->uNewState & LVIS_STATEIMAGEMASK) && !bUpdating)
1329 {
1330 BOOL checked = m_ListView->GetCheckState(pnic->iItem);
1331 /* FIXME: HAX!
1332 - preventing decremention below zero as a safeguard for ReactOS
1333 In ReactOS this action is triggered whenever user changes *selection*, but should be only when *checkbox* state toggled
1334 Maybe LVIS_STATEIMAGEMASK is set incorrectly
1335 */
1336 nSelectedApps +=
1337 (checked)
1338 ? 1
1339 : ((nSelectedApps > 0)
1340 ? -1
1341 : 0);
1342
1343 /* Update item's selection status */
1344 m_ListView->SetSelected(pnic->iItem, checked);
1345
1346 UpdateStatusBarText();
1347 }
1348 }
1349 }
1350 break;
1351
1352 case LVN_COLUMNCLICK:
1353 {
1354 LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
1355
1356 m_ListView->ColumnClick(pnmv);
1357 }
1358 break;
1359
1360 case NM_CLICK:
1361 {
1362 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1363 {
1364 ShowAppInfo(-1);
1365 }
1366 }
1367 break;
1368
1369 case NM_DBLCLK:
1370 {
1371 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1372 {
1373 /* this won't do anything if the program is already installed */
1374 SendMessageW(hwnd, WM_COMMAND, ID_INSTALL, 0);
1375 }
1376 }
1377 break;
1378
1379 case NM_RCLICK:
1380 {
1381 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1382 {
1383 ShowPopupMenu(m_ListView->m_hWnd, 0, ID_INSTALL);
1384 }
1385 }
1386 break;
1387
1388 case EN_LINK:
1389 OnLink((ENLINK*) lParam);
1390 break;
1391
1392 case TTN_GETDISPINFO:
1393 m_Toolbar->OnGetDispInfo((LPTOOLTIPTEXT) lParam);
1394 break;
1395 }
1396 }
1397 break;
1398
1399 case WM_SIZE:
1400 OnSize(hwnd, wParam, lParam);
1401 break;
1402
1403 case WM_SIZING:
1404 {
1405 LPRECT pRect = (LPRECT) lParam;
1406
1407 if (pRect->right - pRect->left < 565)
1408 pRect->right = pRect->left + 565;
1409
1410 if (pRect->bottom - pRect->top < 300)
1411 pRect->bottom = pRect->top + 300;
1412
1413 return TRUE;
1414 }
1415
1416 case WM_SYSCOLORCHANGE:
1417 {
1418 /* Forward WM_SYSCOLORCHANGE to common controls */
1419 m_ListView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1420 m_TreeView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1421 m_Toolbar->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1422 m_ListView->SendMessageW(EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_BTNFACE));
1423 }
1424 break;
1425
1426 case WM_TIMER:
1427 if (wParam == SEARCH_TIMER_ID)
1428 {
1429 ::KillTimer(hwnd, SEARCH_TIMER_ID);
1430 if (bSearchEnabled)
1431 UpdateApplicationsList(-1);
1432 }
1433 break;
1434 }
1435
1436 return FALSE;
1437 }
1438
1439 virtual VOID OnLink(ENLINK *Link)
1440 {
1441 switch (Link->msg)
1442 {
1443 case WM_LBUTTONUP:
1444 case WM_RBUTTONUP:
1445 {
1446 if (pLink) HeapFree(GetProcessHeap(), 0, pLink);
1447
1448 pLink = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
1449 (max(Link->chrg.cpMin, Link->chrg.cpMax) -
1450 min(Link->chrg.cpMin, Link->chrg.cpMax) + 1) * sizeof(WCHAR));
1451 if (!pLink)
1452 {
1453 /* TODO: Error message */
1454 return;
1455 }
1456
1457 m_RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin, Link->chrg.cpMax);
1458 m_RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM) pLink);
1459
1460 ShowPopupMenu(m_RichEdit->m_hWnd, IDR_LINKMENU, -1);
1461 }
1462 break;
1463 }
1464 }
1465
1466 BOOL IsSelectedNodeInstalled()
1467 {
1468 HTREEITEM hSelectedItem = m_TreeView->GetSelection();
1469 TV_ITEM tItem;
1470
1471 tItem.mask = TVIF_PARAM | TVIF_HANDLE;
1472 tItem.hItem = hSelectedItem;
1473 m_TreeView->GetItem(&tItem);
1474 switch (tItem.lParam)
1475 {
1476 case IDS_INSTALLED:
1477 case IDS_APPLICATIONS:
1478 case IDS_UPDATES:
1479 return TRUE;
1480 default:
1481 return FALSE;
1482 }
1483 }
1484
1485 VOID OnCommand(WPARAM wParam, LPARAM lParam)
1486 {
1487 WORD wCommand = LOWORD(wParam);
1488
1489 if (lParam == (LPARAM) m_SearchBar->m_hWnd)
1490 {
1491 ATL::CStringW szBuf;
1492
1493 switch (HIWORD(wParam))
1494 {
1495 case EN_SETFOCUS:
1496 {
1497 ATL::CStringW szWndText;
1498
1499 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1500 m_SearchBar->GetWindowTextW(szWndText);
1501 if (szBuf == szWndText)
1502 {
1503 bSearchEnabled = FALSE;
1504 m_SearchBar->SetWindowTextW(L"");
1505 }
1506 }
1507 break;
1508
1509 case EN_KILLFOCUS:
1510 {
1511 m_SearchBar->GetWindowTextW(szBuf);
1512 if (szBuf.IsEmpty())
1513 {
1514 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1515 bSearchEnabled = FALSE;
1516 m_SearchBar->SetWindowTextW(szBuf.GetString());
1517 }
1518 }
1519 break;
1520
1521 case EN_CHANGE:
1522 {
1523 ATL::CStringW szWndText;
1524
1525 if (!bSearchEnabled)
1526 {
1527 bSearchEnabled = TRUE;
1528 break;
1529 }
1530
1531 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1532 m_SearchBar->GetWindowTextW(szWndText);
1533 if (szBuf == szWndText)
1534 {
1535 szSearchPattern.Empty();
1536 }
1537 else
1538 {
1539 szSearchPattern = szWndText;
1540 }
1541
1542 DWORD dwDelay;
1543 SystemParametersInfoW(SPI_GETMENUSHOWDELAY, 0, &dwDelay, 0);
1544 SetTimer(SEARCH_TIMER_ID, dwDelay);
1545 }
1546 break;
1547 }
1548
1549 return;
1550 }
1551
1552 switch (wCommand)
1553 {
1554 case ID_OPEN_LINK:
1555 ShellExecuteW(m_hWnd, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
1556 HeapFree(GetProcessHeap(), 0, pLink);
1557 break;
1558
1559 case ID_COPY_LINK:
1560 CopyTextToClipboard(pLink);
1561 HeapFree(GetProcessHeap(), 0, pLink);
1562 break;
1563
1564 case ID_SETTINGS:
1565 CreateSettingsDlg(m_hWnd);
1566 break;
1567
1568 case ID_EXIT:
1569 PostMessageW(WM_CLOSE, 0, 0);
1570 break;
1571
1572 case ID_SEARCH:
1573 ::SetFocus(m_SearchBar->m_hWnd);
1574 break;
1575
1576 case ID_INSTALL:
1577 if (IsAvailableEnum(SelectedEnumType))
1578 {
1579 if (nSelectedApps > 0)
1580 {
1581 DownloadListOfApplications(m_AvailableApps.GetSelected(), FALSE);
1582 UpdateApplicationsList(-1);
1583 m_ListView->SetSelected(-1, FALSE);
1584 }
1585 else if (DownloadApplication(m_ListView->GetSelectedData(), FALSE))
1586 {
1587 UpdateApplicationsList(-1);
1588 }
1589
1590 }
1591 break;
1592
1593 case ID_UNINSTALL:
1594 if (UninstallApplication(-1, FALSE))
1595 UpdateApplicationsList(-1);
1596 break;
1597
1598 case ID_MODIFY:
1599 if (UninstallApplication(-1, TRUE))
1600 UpdateApplicationsList(-1);
1601 break;
1602
1603 case ID_REGREMOVE:
1604 RemoveSelectedAppFromRegistry();
1605 break;
1606
1607 case ID_REFRESH:
1608 UpdateApplicationsList(-1);
1609 break;
1610
1611 case ID_RESETDB:
1612 CAvailableApps::ForceUpdateAppsDB();
1613 UpdateApplicationsList(-1);
1614 break;
1615
1616 case ID_HELP:
1617 MessageBoxW(L"Help not implemented yet", NULL, MB_OK);
1618 break;
1619
1620 case ID_ABOUT:
1621 ShowAboutDialog();
1622 break;
1623
1624 case ID_CHECK_ALL:
1625 m_ListView->CheckAll();
1626 break;
1627 }
1628 }
1629
1630 VOID FreeInstalledAppList()
1631 {
1632 INT Count = m_ListView->GetItemCount() - 1;
1633 PINSTALLED_INFO Info;
1634
1635 while (Count >= 0)
1636 {
1637 Info = (PINSTALLED_INFO) ListViewGetlParam(Count);
1638 if (Info)
1639 {
1640 RegCloseKey(Info->hSubKey);
1641 delete Info;
1642 }
1643 Count--;
1644 }
1645 }
1646
1647 static BOOL SearchPatternMatch(LPCWSTR szHaystack, LPCWSTR szNeedle)
1648 {
1649 if (!*szNeedle)
1650 return TRUE;
1651 /* TODO: Improve pattern search beyond a simple case-insensitive substring search. */
1652 return StrStrIW(szHaystack, szNeedle) != NULL;
1653 }
1654
1655 BOOL CALLBACK EnumInstalledAppProc(INT ItemIndex, ATL::CStringW &m_szName, PINSTALLED_INFO Info)
1656 {
1657 PINSTALLED_INFO ItemInfo;
1658 ATL::CStringW szText;
1659 INT Index;
1660
1661 if (!SearchPatternMatch(m_szName.GetString(), szSearchPattern))
1662 {
1663 RegCloseKey(Info->hSubKey);
1664 return TRUE;
1665 }
1666
1667 ItemInfo = new INSTALLED_INFO(*Info);
1668 if (!ItemInfo)
1669 {
1670 RegCloseKey(Info->hSubKey);
1671 return FALSE;
1672 }
1673
1674 Index = m_ListView->AddItem(ItemIndex, 0, m_szName.GetString(), (LPARAM) ItemInfo);
1675
1676 /* Get version info */
1677 ItemInfo->GetApplicationString(L"DisplayVersion", szText);
1678 m_ListView->SetItemText(Index, 1, szText.GetString());
1679
1680 /* Get comments */
1681 ItemInfo->GetApplicationString(L"Comments", szText);
1682 m_ListView->SetItemText(Index, 2, szText.GetString());
1683
1684 return TRUE;
1685 }
1686
1687 BOOL EnumAvailableAppProc(CAvailableApplicationInfo* Info, LPCWSTR szFolderPath)
1688 {
1689 INT Index;
1690 HICON hIcon = NULL;
1691
1692 HIMAGELIST hImageListView = ListView_GetImageList(hListView, LVSIL_SMALL);
1693
1694 if (!SearchPatternMatch(Info->m_szName.GetString(), szSearchPattern) &&
1695 !SearchPatternMatch(Info->m_szDesc.GetString(), szSearchPattern))
1696 {
1697 return TRUE;
1698 }
1699
1700 /* Load icon from file */
1701 ATL::CStringW szIconPath;
1702 szIconPath.Format(L"%lsicons\\%ls.ico", szFolderPath, Info->m_szName.GetString());
1703 hIcon = (HICON) LoadImageW(NULL,
1704 szIconPath.GetString(),
1705 IMAGE_ICON,
1706 LISTVIEW_ICON_SIZE,
1707 LISTVIEW_ICON_SIZE,
1708 LR_LOADFROMFILE);
1709
1710 if (!hIcon || GetLastError() != ERROR_SUCCESS)
1711 {
1712 /* Load default icon */
1713 hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1714 }
1715
1716 Index = ImageList_AddIcon(hImageListView, hIcon);
1717 DestroyIcon(hIcon);
1718
1719 Index = m_ListView->AddItem(Info->m_Category, Index, Info->m_szName.GetString(), (LPARAM) Info);
1720 m_ListView->SetImageList(hImageListView, LVSIL_SMALL);
1721 m_ListView->SetItemText(Index, 1, Info->m_szVersion.GetString());
1722 m_ListView->SetItemText(Index, 2, Info->m_szDesc.GetString());
1723 m_ListView->SetCheckState(Index, Info->m_IsSelected);
1724
1725 return TRUE;
1726 }
1727
1728 static BOOL CALLBACK s_EnumInstalledAppProc(INT ItemIndex, ATL::CStringW &m_szName, PINSTALLED_INFO Info, PVOID param)
1729 {
1730 CMainWindow* pThis = (CMainWindow*)param;
1731 return pThis->EnumInstalledAppProc(ItemIndex, m_szName, Info);
1732 }
1733
1734 static BOOL CALLBACK s_EnumAvailableAppProc(CAvailableApplicationInfo* Info, LPCWSTR szFolderPath, PVOID param)
1735 {
1736 CMainWindow* pThis = (CMainWindow*)param;
1737 return pThis->EnumAvailableAppProc(Info, szFolderPath);
1738 }
1739
1740 VOID UpdateStatusBarText()
1741 {
1742 if (m_StatusBar)
1743 {
1744 ATL::CStringW szBuffer;
1745
1746 szBuffer.Format(IDS_APPS_COUNT, m_ListView->GetItemCount(), nSelectedApps);
1747 m_StatusBar->SetText(szBuffer);
1748 }
1749 }
1750
1751 VOID UpdateApplicationsList(INT EnumType)
1752 {
1753 ATL::CStringW szBuffer1, szBuffer2;
1754 HIMAGELIST hImageListView;
1755 BOOL bWasInInstalled = IsInstalledEnum(SelectedEnumType);
1756
1757 bUpdating = TRUE;
1758 m_ListView->SetRedraw(FALSE);
1759
1760 if (EnumType < 0)
1761 {
1762 EnumType = SelectedEnumType;
1763 }
1764
1765 //if previous one was INSTALLED purge the list
1766 //TODO: make the Installed category a separate class to avoid doing this
1767 if (bWasInInstalled)
1768 {
1769 FreeInstalledAppList();
1770 }
1771
1772 m_ListView->DeleteAllItems();
1773
1774 // Create new ImageList
1775 hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
1776 LISTVIEW_ICON_SIZE,
1777 GetSystemColorDepth() | ILC_MASK,
1778 0, 1);
1779 HIMAGELIST hImageListBuf = m_ListView->SetImageList(hImageListView, LVSIL_SMALL);
1780 if (hImageListBuf)
1781 {
1782 ImageList_Destroy(hImageListBuf);
1783 }
1784
1785 if (IsInstalledEnum(EnumType))
1786 {
1787 if (!bWasInInstalled)
1788 {
1789 m_ListView->SetCheckboxesVisible(FALSE);
1790 }
1791
1792 HICON hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1793 ImageList_AddIcon(hImageListView, hIcon);
1794 DestroyIcon(hIcon);
1795
1796 // Enum installed applications and updates
1797 EnumInstalledApplications(EnumType, TRUE, s_EnumInstalledAppProc, this);
1798 EnumInstalledApplications(EnumType, FALSE, s_EnumInstalledAppProc, this);
1799 }
1800 else if (IsAvailableEnum(EnumType))
1801 {
1802 if (bWasInInstalled)
1803 {
1804 m_ListView->SetCheckboxesVisible(TRUE);
1805 }
1806
1807 // Enum available applications
1808 m_AvailableApps.Enum(EnumType, s_EnumAvailableAppProc, this);
1809 }
1810
1811 SelectedEnumType = EnumType;
1812 UpdateStatusBarText();
1813 m_RichEdit->SetWelcomeText();
1814
1815 // Set automatic column width for program names if the list is not empty
1816 if (m_ListView->GetItemCount() > 0)
1817 {
1818 ListView_SetColumnWidth(m_ListView->GetWindow(), 0, LVSCW_AUTOSIZE);
1819 }
1820
1821 bUpdating = FALSE;
1822 m_ListView->SetRedraw(TRUE);
1823 }
1824
1825 public:
1826 static ATL::CWndClassInfo& GetWndClassInfo()
1827 {
1828 DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
1829 static ATL::CWndClassInfo wc =
1830 {
1831 {
1832 sizeof(WNDCLASSEX),
1833 csStyle,
1834 StartWindowProc,
1835 0,
1836 0,
1837 NULL,
1838 LoadIconW(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCEW(IDI_MAIN)),
1839 LoadCursorW(NULL, IDC_ARROW),
1840 (HBRUSH) (COLOR_BTNFACE + 1),
1841 MAKEINTRESOURCEW(IDR_MAINMENU),
1842 L"RAppsWnd",
1843 NULL
1844 },
1845 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
1846 };
1847 return wc;
1848 }
1849
1850 HWND Create()
1851 {
1852 ATL::CStringW szWindowName;
1853 szWindowName.LoadStringW(IDS_APPTITLE);
1854
1855 RECT r = {
1856 (SettingsInfo.bSaveWndPos ? SettingsInfo.Left : CW_USEDEFAULT),
1857 (SettingsInfo.bSaveWndPos ? SettingsInfo.Top : CW_USEDEFAULT),
1858 (SettingsInfo.bSaveWndPos ? SettingsInfo.Width : 680),
1859 (SettingsInfo.bSaveWndPos ? SettingsInfo.Height : 450)
1860 };
1861 r.right += r.left;
1862 r.bottom += r.top;
1863
1864 return CWindowImpl::Create(NULL, r, szWindowName.GetString(), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE);
1865 }
1866
1867 CStatusBar * GetStatusBar()
1868 {
1869 return m_StatusBar;
1870 }
1871
1872 CAppsListView * GetListView()
1873 {
1874 return m_ListView;
1875 }
1876
1877 CRichEdit * GetRichEdit()
1878 {
1879 return m_RichEdit;
1880 }
1881
1882 CAvailableApps * GetAvailableApps()
1883 {
1884 return &m_AvailableApps;
1885 }
1886 };
1887
1888 // global interface
1889 CMainWindow * g_MainWindow;
1890
1891 HWND CreateMainWindow()
1892 {
1893 g_MainWindow = new CMainWindow();
1894 return g_MainWindow->Create();
1895 }
1896
1897 DWORD_PTR ListViewGetlParam(INT item)
1898 {
1899 if (item < 0)
1900 {
1901 item = g_MainWindow->GetListView()->GetSelectionMark();
1902 }
1903 return g_MainWindow->GetListView()->GetItemData(item);
1904 }
1905
1906 VOID SetStatusBarText(LPCWSTR szText)
1907 {
1908 g_MainWindow->GetStatusBar()->SetText(szText);
1909 }
1910
1911 INT ListViewAddItem(INT ItemIndex, INT IconIndex, LPWSTR lpName, LPARAM lParam)
1912 {
1913 return g_MainWindow->GetListView()->AddItem(ItemIndex, IconIndex, lpName, lParam);
1914 }
1915
1916 VOID NewRichEditText(LPCWSTR szText, DWORD flags)
1917 {
1918 g_MainWindow->GetRichEdit()->SetText(szText, flags);
1919 }
1920
1921 VOID InsertRichEditText(LPCWSTR szText, DWORD flags)
1922 {
1923 g_MainWindow->GetRichEdit()->InsertText(szText, flags);
1924 }
1925
1926 CAvailableApps* GetAvailableApps()
1927 {
1928 return g_MainWindow->GetAvailableApps();
1929 }
1930
1931 // ATL version of functions above
1932 VOID SetStatusBarText(const ATL::CStringW& szText)
1933 {
1934 SetStatusBarText(szText.GetString());
1935 }
1936
1937 INT ListViewAddItem(INT ItemIndex, INT IconIndex, const ATL::CStringW& Name, LPARAM lParam)
1938 {
1939 return ListViewAddItem(ItemIndex, IconIndex, const_cast<LPWSTR>(Name.GetString()), lParam);
1940 }
1941
1942 VOID NewRichEditText(const ATL::CStringW& szText, DWORD flags)
1943 {
1944 NewRichEditText(szText.GetString(), flags);
1945 }
1946
1947 VOID InsertRichEditText(const ATL::CStringW& szText, DWORD flags)
1948 {
1949 InsertRichEditText(szText.GetString(), flags);
1950 }
1951
1952 VOID ShowMainWindow(INT nShowCmd)
1953 {
1954 HACCEL KeyBrd;
1955 MSG Msg;
1956
1957 hMainWnd = CreateMainWindow();
1958
1959 if (hMainWnd)
1960 {
1961 /* Maximize it if we must */
1962 ShowWindow(hMainWnd, ((SettingsInfo.bSaveWndPos && SettingsInfo.Maximized) ? SW_MAXIMIZE : nShowCmd));
1963 UpdateWindow(hMainWnd);
1964
1965 /* Load the menu hotkeys */
1966 KeyBrd = LoadAcceleratorsW(NULL, MAKEINTRESOURCEW(HOTKEYS));
1967
1968 /* Message Loop */
1969 while (GetMessageW(&Msg, NULL, 0, 0))
1970 {
1971 if (!TranslateAcceleratorW(hMainWnd, KeyBrd, &Msg))
1972 {
1973 TranslateMessage(&Msg);
1974 DispatchMessageW(&Msg);
1975 }
1976 }
1977 }
1978 }