xref: /reactos/base/applications/rapps/appview.cpp (revision e1605243)
1 /*
2  * PROJECT:     ReactOS Applications Manager
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Application view class and other classes used by it
5  * COPYRIGHT:   Copyright 2020 He Yang            (1160386205@qq.com)
6  */
7 
8 #include "rapps.h"
9 #include "appview.h"
10 #include "gui.h"
11 #include <windowsx.h>
12 
13 
14  // **** CMainToolbar ****
15 
16 VOID CMainToolbar::AddImageToImageList(HIMAGELIST hImageList, UINT ImageIndex)
17 {
18     HICON hImage;
19 
20     if (!(hImage = (HICON)LoadImageW(hInst,
21         MAKEINTRESOURCE(ImageIndex),
22         IMAGE_ICON,
23         m_iToolbarHeight,
24         m_iToolbarHeight,
25         0)))
26     {
27         /* TODO: Error message */
28     }
29 
30     ImageList_AddIcon(hImageList, hImage);
31     DeleteObject(hImage);
32 }
33 
34 HIMAGELIST CMainToolbar::InitImageList()
35 {
36     HIMAGELIST hImageList;
37 
38     /* Create the toolbar icon image list */
39     hImageList = ImageList_Create(m_iToolbarHeight,//GetSystemMetrics(SM_CXSMICON),
40         m_iToolbarHeight,//GetSystemMetrics(SM_CYSMICON),
41         ILC_MASK | GetSystemColorDepth(),
42         1, 1);
43     if (!hImageList)
44     {
45         /* TODO: Error message */
46         return NULL;
47     }
48 
49     AddImageToImageList(hImageList, IDI_INSTALL);
50     AddImageToImageList(hImageList, IDI_UNINSTALL);
51     AddImageToImageList(hImageList, IDI_MODIFY);
52     AddImageToImageList(hImageList, IDI_CHECK_ALL);
53     AddImageToImageList(hImageList, IDI_REFRESH);
54     AddImageToImageList(hImageList, IDI_UPDATE_DB);
55     AddImageToImageList(hImageList, IDI_SETTINGS);
56     AddImageToImageList(hImageList, IDI_EXIT);
57 
58     return hImageList;
59 }
60 
61 CMainToolbar::CMainToolbar() : m_iToolbarHeight(24)
62 {
63 }
64 
65 VOID CMainToolbar::OnGetDispInfo(LPTOOLTIPTEXT lpttt)
66 {
67     UINT idButton = (UINT)lpttt->hdr.idFrom;
68 
69     switch (idButton)
70     {
71     case ID_EXIT:
72         lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_EXIT);
73         break;
74 
75     case ID_INSTALL:
76         lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_INSTALL);
77         break;
78 
79     case ID_UNINSTALL:
80         lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UNINSTALL);
81         break;
82 
83     case ID_MODIFY:
84         lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_MODIFY);
85         break;
86 
87     case ID_SETTINGS:
88         lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_SETTINGS);
89         break;
90 
91     case ID_REFRESH:
92         lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_REFRESH);
93         break;
94 
95     case ID_RESETDB:
96         lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UPDATE_DB);
97         break;
98     }
99 }
100 
101 HWND CMainToolbar::Create(HWND hwndParent)
102 {
103     /* Create buttons */
104     TBBUTTON Buttons[] =
105     {   /* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */
106         {  0, ID_TOOLBAR_INSTALL,   TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR)szInstallBtn      },
107         {  1, ID_UNINSTALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR)szUninstallBtn    },
108         {  2, ID_MODIFY,    TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR)szModifyBtn       },
109         {  3, ID_CHECK_ALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR)szSelectAll       },
110         { -1, 0,            TBSTATE_ENABLED, BTNS_SEP,                    { 0 }, 0, 0                           },
111         {  4, ID_REFRESH,   TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0                           },
112         {  5, ID_RESETDB,   TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0                           }
113     };
114 
115     LoadStringW(hInst, IDS_INSTALL, szInstallBtn, _countof(szInstallBtn));
116     LoadStringW(hInst, IDS_UNINSTALL, szUninstallBtn, _countof(szUninstallBtn));
117     LoadStringW(hInst, IDS_MODIFY, szModifyBtn, _countof(szModifyBtn));
118     LoadStringW(hInst, IDS_SELECT_ALL, szSelectAll, _countof(szSelectAll));
119 
120     m_hWnd = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
121         WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_LIST,
122         0, 0, 0, 0,
123         hwndParent,
124         0, hInst, NULL);
125 
126     if (!m_hWnd)
127     {
128         /* TODO: Show error message */
129         return FALSE;
130     }
131 
132     SendMessageW(TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS);
133     SetButtonStructSize();
134 
135     /* Set image list */
136     HIMAGELIST hImageList = InitImageList();
137 
138     if (!hImageList)
139     {
140         /* TODO: Show error message */
141         return FALSE;
142     }
143 
144     ImageList_Destroy(SetImageList(hImageList));
145 
146     AddButtons(_countof(Buttons), Buttons);
147 
148     /* Remember ideal width to use as a max width of buttons */
149     SIZE size;
150     GetIdealSize(FALSE, &size);
151     m_dButtonsWidthMax = size.cx;
152 
153     return m_hWnd;
154 }
155 
156 VOID CMainToolbar::HideButtonCaption()
157 {
158     DWORD dCurrentExStyle = (DWORD)SendMessageW(TB_GETEXTENDEDSTYLE, 0, 0);
159     SendMessageW(TB_SETEXTENDEDSTYLE, 0, dCurrentExStyle | TBSTYLE_EX_MIXEDBUTTONS);
160 }
161 
162 VOID CMainToolbar::ShowButtonCaption()
163 {
164     DWORD dCurrentExStyle = (DWORD)SendMessageW(TB_GETEXTENDEDSTYLE, 0, 0);
165     SendMessageW(TB_SETEXTENDEDSTYLE, 0, dCurrentExStyle & ~TBSTYLE_EX_MIXEDBUTTONS);
166 }
167 
168 DWORD CMainToolbar::GetMaxButtonsWidth() const
169 {
170     return m_dButtonsWidthMax;
171 }
172 // **** CMainToolbar ****
173 
174 
175 // **** CSearchBar ****
176 
177 CSearchBar::CSearchBar() : m_Width(180), m_Height(22)
178 {
179 }
180 
181 VOID CSearchBar::SetText(LPCWSTR lpszText)
182 {
183     SendMessageW(SB_SETTEXT, SBT_NOBORDERS, (LPARAM)lpszText);
184 }
185 
186 HWND CSearchBar::Create(HWND hwndParent)
187 {
188     ATL::CStringW szBuf;
189     m_hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL,
190         WS_CHILD | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
191         0, 0, m_Width, m_Height,
192         hwndParent, (HMENU)NULL,
193         hInst, 0);
194 
195     SendMessageW(WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0);
196     szBuf.LoadStringW(IDS_SEARCH_TEXT);
197     SetWindowTextW(szBuf);
198     return m_hWnd;
199 }
200 // **** CSearchBar ****
201 
202 
203 // **** CComboBox ****
204 
205 CComboBox::CComboBox() : m_Width(80), m_Height(22)
206 {
207 }
208 
209 HWND CComboBox::Create(HWND hwndParent)
210 {
211     m_hWnd = CreateWindowW(WC_COMBOBOX, L"",
212         CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE,
213         0, 0, m_Width, m_Height, hwndParent, NULL, 0,
214         NULL);
215 
216     SendMessageW(WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0);
217 
218     for (int i = 0; i < (int)_countof(m_TypeStringID); i++)
219     {
220         ATL::CStringW szBuf;
221         szBuf.LoadStringW(m_TypeStringID[i]);
222         SendMessageW(CB_ADDSTRING, 0, (LPARAM)(LPCWSTR)szBuf);
223     }
224 
225     SendMessageW(CB_SETCURSEL, m_DefaultSelectType, 0); // select the first item
226 
227     return m_hWnd;
228 }
229 // **** CComboBox ****
230 
231 
232 // **** CAppRichEdit ****
233 
234 VOID CAppRichEdit::LoadAndInsertText(UINT uStringID,
235     const ATL::CStringW &szText,
236     DWORD StringFlags,
237     DWORD TextFlags)
238 {
239     ATL::CStringW szLoadedText;
240     if (!szText.IsEmpty() && szLoadedText.LoadStringW(uStringID))
241     {
242         InsertText(szLoadedText, StringFlags);
243         InsertText(szText, TextFlags);
244     }
245 }
246 
247 VOID CAppRichEdit::LoadAndInsertText(UINT uStringID,
248     DWORD StringFlags)
249 {
250     ATL::CStringW szLoadedText;
251     if (szLoadedText.LoadStringW(uStringID))
252     {
253         InsertText(L"\n", 0);
254         InsertText(szLoadedText, StringFlags);
255         InsertText(L"\n", 0);
256     }
257 }
258 
259 VOID CAppRichEdit::InsertVersionInfo(CAvailableApplicationInfo *Info)
260 {
261     if (Info->IsInstalled())
262     {
263         if (Info->HasInstalledVersion())
264         {
265             if (Info->HasUpdate())
266                 LoadAndInsertText(IDS_STATUS_UPDATE_AVAILABLE, CFE_ITALIC);
267             else
268                 LoadAndInsertText(IDS_STATUS_INSTALLED, CFE_ITALIC);
269 
270             LoadAndInsertText(IDS_AINFO_VERSION, Info->m_szInstalledVersion, CFE_BOLD, 0);
271         }
272         else
273         {
274             LoadAndInsertText(IDS_STATUS_INSTALLED, CFE_ITALIC);
275         }
276     }
277     else
278     {
279         LoadAndInsertText(IDS_STATUS_NOTINSTALLED, CFE_ITALIC);
280     }
281 
282     LoadAndInsertText(IDS_AINFO_AVAILABLEVERSION, Info->m_szVersion, CFE_BOLD, 0);
283 }
284 
285 VOID CAppRichEdit::InsertLicenseInfo(CAvailableApplicationInfo *Info)
286 {
287     ATL::CStringW szLicense;
288     switch (Info->m_LicenseType)
289     {
290     case LICENSE_OPENSOURCE:
291         szLicense.LoadStringW(IDS_LICENSE_OPENSOURCE);
292         break;
293     case LICENSE_FREEWARE:
294         szLicense.LoadStringW(IDS_LICENSE_FREEWARE);
295         break;
296     case LICENSE_TRIAL:
297         szLicense.LoadStringW(IDS_LICENSE_TRIAL);
298         break;
299     default:
300         LoadAndInsertText(IDS_AINFO_LICENSE, Info->m_szLicense, CFE_BOLD, 0);
301         return;
302     }
303 
304     szLicense += L" (" + Info->m_szLicense + L")";
305     LoadAndInsertText(IDS_AINFO_LICENSE, szLicense, CFE_BOLD, 0);
306 }
307 
308 VOID CAppRichEdit::InsertLanguageInfo(CAvailableApplicationInfo *Info)
309 {
310     if (!Info->HasLanguageInfo())
311     {
312         return;
313     }
314 
315     const INT nTranslations = Info->m_LanguageLCIDs.GetSize();
316     ATL::CStringW szLangInfo;
317     ATL::CStringW szLoadedTextAvailability;
318     ATL::CStringW szLoadedAInfoText;
319 
320     szLoadedAInfoText.LoadStringW(IDS_AINFO_LANGUAGES);
321 
322     if (Info->HasNativeLanguage())
323     {
324         szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_AVAILABLE_TRANSLATION);
325         if (nTranslations > 1)
326         {
327             ATL::CStringW buf;
328             buf.LoadStringW(IDS_LANGUAGE_MORE_PLACEHOLDER);
329             szLangInfo.Format(buf, nTranslations - 1);
330         }
331         else
332         {
333             szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE);
334             szLangInfo = L" (" + szLangInfo + L")";
335         }
336     }
337     else if (Info->HasEnglishLanguage())
338     {
339         szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_ENGLISH_TRANSLATION);
340         if (nTranslations > 1)
341         {
342             ATL::CStringW buf;
343             buf.LoadStringW(IDS_LANGUAGE_AVAILABLE_PLACEHOLDER);
344             szLangInfo.Format(buf, nTranslations - 1);
345         }
346         else
347         {
348             szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE);
349             szLangInfo = L" (" + szLangInfo + L")";
350         }
351     }
352     else
353     {
354         szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_NO_TRANSLATION);
355     }
356 
357     InsertText(szLoadedAInfoText, CFE_BOLD);
358     InsertText(szLoadedTextAvailability, NULL);
359     InsertText(szLangInfo, CFE_ITALIC);
360 }
361 
362 BOOL CAppRichEdit::ShowAvailableAppInfo(CAvailableApplicationInfo *Info)
363 {
364     if (!Info) return FALSE;
365 
366     SetText(Info->m_szName, CFE_BOLD);
367     InsertVersionInfo(Info);
368     InsertLicenseInfo(Info);
369     InsertLanguageInfo(Info);
370 
371     LoadAndInsertText(IDS_AINFO_SIZE, Info->m_szSize, CFE_BOLD, 0);
372     LoadAndInsertText(IDS_AINFO_URLSITE, Info->m_szUrlSite, CFE_BOLD, CFE_LINK);
373     LoadAndInsertText(IDS_AINFO_DESCRIPTION, Info->m_szDesc, CFE_BOLD, 0);
374     LoadAndInsertText(IDS_AINFO_URLDOWNLOAD, Info->m_szUrlDownload, CFE_BOLD, CFE_LINK);
375     LoadAndInsertText(IDS_AINFO_PACKAGE_NAME, Info->m_szPkgName, CFE_BOLD, 0);
376 
377     return TRUE;
378 }
379 
380 inline VOID CAppRichEdit::InsertTextWithString(UINT StringID, DWORD StringFlags, const ATL::CStringW &Text, DWORD TextFlags)
381 {
382     if (!Text.IsEmpty())
383     {
384         LoadAndInsertText(StringID, Text, StringFlags, TextFlags);
385     }
386 }
387 
388 BOOL CAppRichEdit::ShowInstalledAppInfo(CInstalledApplicationInfo *Info)
389 {
390     if (!Info) return FALSE;
391 
392     SetText(Info->szDisplayName, CFE_BOLD);
393     InsertText(L"\n", 0);
394 
395     InsertTextWithString(IDS_INFO_VERSION, CFE_BOLD, Info->szDisplayVersion, 0);
396     InsertTextWithString(IDS_INFO_PUBLISHER, CFE_BOLD, Info->szPublisher, 0);
397     InsertTextWithString(IDS_INFO_REGOWNER, CFE_BOLD, Info->szRegOwner, 0);
398     InsertTextWithString(IDS_INFO_PRODUCTID, CFE_BOLD, Info->szProductID, 0);
399     InsertTextWithString(IDS_INFO_HELPLINK, CFE_BOLD, Info->szHelpLink, CFM_LINK);
400     InsertTextWithString(IDS_INFO_HELPPHONE, CFE_BOLD, Info->szHelpTelephone, 0);
401     InsertTextWithString(IDS_INFO_README, CFE_BOLD, Info->szReadme, 0);
402     InsertTextWithString(IDS_INFO_CONTACT, CFE_BOLD, Info->szContact, 0);
403     InsertTextWithString(IDS_INFO_UPDATEINFO, CFE_BOLD, Info->szURLUpdateInfo, CFM_LINK);
404     InsertTextWithString(IDS_INFO_INFOABOUT, CFE_BOLD, Info->szURLInfoAbout, CFM_LINK);
405     InsertTextWithString(IDS_INFO_COMMENTS, CFE_BOLD, Info->szComments, 0);
406     InsertTextWithString(IDS_INFO_INSTALLDATE, CFE_BOLD, Info->szInstallDate, 0);
407     InsertTextWithString(IDS_INFO_INSTLOCATION, CFE_BOLD, Info->szInstallLocation, 0);
408     InsertTextWithString(IDS_INFO_INSTALLSRC, CFE_BOLD, Info->szInstallSource, 0);
409     InsertTextWithString(IDS_INFO_UNINSTALLSTR, CFE_BOLD, Info->szUninstallString, 0);
410     InsertTextWithString(IDS_INFO_MODIFYPATH, CFE_BOLD, Info->szModifyPath, 0);
411 
412     return TRUE;
413 }
414 
415 VOID CAppRichEdit::SetWelcomeText()
416 {
417     ATL::CStringW szText;
418 
419     szText.LoadStringW(IDS_WELCOME_TITLE);
420     SetText(szText, CFE_BOLD);
421 
422     szText.LoadStringW(IDS_WELCOME_TEXT);
423     InsertText(szText, 0);
424 
425     szText.LoadStringW(IDS_WELCOME_URL);
426     InsertText(szText, CFM_LINK);
427 }
428 // **** CAppRichEdit ****
429 
430 
431 int ScrnshotDownloadCallback(
432     pASYNCINET AsyncInet,
433     ASYNC_EVENT Event,
434     WPARAM wParam,
435     LPARAM lParam,
436     VOID *Extension
437 )
438 {
439     ScrnshotDownloadParam *DownloadParam = (ScrnshotDownloadParam *)Extension;
440     switch (Event)
441     {
442     case ASYNCINET_DATA:
443         DWORD BytesWritten;
444         WriteFile(DownloadParam->hFile, (LPCVOID)wParam, (DWORD)lParam, &BytesWritten, NULL);
445         break;
446     case ASYNCINET_COMPLETE:
447         CloseHandle(DownloadParam->hFile);
448         SendMessage(DownloadParam->hwndNotify, WM_RAPPS_DOWNLOAD_COMPLETE, (WPARAM)ERROR_SUCCESS, (LPARAM)DownloadParam);
449         break;
450     case ASYNCINET_CANCELLED:
451         CloseHandle(DownloadParam->hFile);
452         SendMessage(DownloadParam->hwndNotify, WM_RAPPS_DOWNLOAD_COMPLETE, (WPARAM)ERROR_CANCELLED, (LPARAM)DownloadParam);
453         break;
454     case ASYNCINET_ERROR:
455         CloseHandle(DownloadParam->hFile);
456         SendMessage(DownloadParam->hwndNotify, WM_RAPPS_DOWNLOAD_COMPLETE, wParam, (LPARAM)DownloadParam);
457         break;
458     default:
459         ATLASSERT(FALSE);
460         break;
461     }
462     return 0;
463 }
464 
465 
466 // **** CAppScrnshotPreview ****
467 
468 BOOL CAppScrnshotPreview::ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT &theResult, DWORD dwMapId)
469 {
470     theResult = 0;
471     switch (Msg)
472     {
473     case WM_CREATE:
474         hBrokenImgIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_BROKEN_IMAGE), IMAGE_ICON, BrokenImgSize, BrokenImgSize, 0);
475         break;
476     case WM_SIZE:
477     {
478         if (BrokenImgSize != min(min(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), BROKENIMG_ICON_SIZE))
479         {
480             BrokenImgSize = min(min(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), BROKENIMG_ICON_SIZE);
481 
482             if (hBrokenImgIcon)
483             {
484                 DeleteObject(hBrokenImgIcon);
485                 hBrokenImgIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_BROKEN_IMAGE), IMAGE_ICON, BrokenImgSize, BrokenImgSize, 0);
486             }
487         }
488         break;
489     }
490     case WM_RAPPS_DOWNLOAD_COMPLETE:
491     {
492         ScrnshotDownloadParam *DownloadParam = (ScrnshotDownloadParam *)lParam;
493         AsyncInetRelease(AsyncInet);
494         AsyncInet = NULL;
495         switch (wParam)
496         {
497         case ERROR_SUCCESS:
498             if (ContentID == DownloadParam->ID)
499             {
500                 DisplayFile(DownloadParam->DownloadFileName);
501                 // send a message to trigger resizing
502                 ::SendMessageW(::GetParent(m_hWnd), WM_RAPPS_RESIZE_CHILDREN, 0, 0);
503                 InvalidateRect(0, 0);
504                 TempImagePath = DownloadParam->DownloadFileName; // record tmp file path in order to delete it when cleanup
505             }
506             else
507             {
508                 // the picture downloaded is already outdated. delete it.
509                 DeleteFileW(DownloadParam->DownloadFileName);
510             }
511             break;
512         case ERROR_CANCELLED:
513             DeleteFileW(DownloadParam->DownloadFileName);
514             break;
515         default:
516             DisplayFailed();
517             // send a message to trigger resizing
518             ::SendMessageW(::GetParent(m_hWnd), WM_RAPPS_RESIZE_CHILDREN, 0, 0);
519             InvalidateRect(0, 0);
520             DeleteFileW(DownloadParam->DownloadFileName);
521             break;
522         }
523         delete DownloadParam;
524         break;
525     }
526     case WM_PAINT:
527     {
528         PAINTSTRUCT ps;
529         HDC hdc = BeginPaint(&ps);
530         CRect rect;
531         GetClientRect(&rect);
532 
533         PaintOnDC(hdc,
534             rect.Width(),
535             rect.Height(),
536             ps.fErase);
537 
538         EndPaint(&ps);
539         break;
540     }
541     case WM_PRINTCLIENT:
542     {
543         if (lParam & PRF_CHECKVISIBLE)
544         {
545             if (!IsWindowVisible()) break;
546         }
547         CRect rect;
548         GetClientRect(&rect);
549 
550         PaintOnDC((HDC)wParam,
551             rect.Width(),
552             rect.Height(),
553             lParam & PRF_ERASEBKGND);
554         break;
555     }
556     case WM_ERASEBKGND:
557     {
558         return TRUE; // do not erase to avoid blinking
559     }
560     case WM_TIMER:
561     {
562         switch (wParam)
563         {
564         case TIMER_LOADING_ANIMATION:
565             LoadingAnimationFrame++;
566             LoadingAnimationFrame %= (LOADING_ANIMATION_PERIOD * LOADING_ANIMATION_FPS);
567             HDC hdc = GetDC();
568             CRect rect;
569             GetClientRect(&rect);
570 
571             PaintOnDC(hdc,
572                 rect.Width(),
573                 rect.Height(),
574                 TRUE);
575             ReleaseDC(hdc);
576         }
577         break;
578     }
579     case WM_DESTROY:
580     {
581         PreviousDisplayCleanup();
582         DeleteObject(hBrokenImgIcon);
583         hBrokenImgIcon = NULL;
584         break;
585     }
586     }
587     return FALSE;
588 }
589 
590 VOID CAppScrnshotPreview::DisplayLoading()
591 {
592     SetStatus(SCRNSHOT_PREV_LOADING);
593     if (bLoadingTimerOn)
594     {
595         KillTimer(TIMER_LOADING_ANIMATION);
596     }
597     LoadingAnimationFrame = 0;
598     bLoadingTimerOn = TRUE;
599     SetTimer(TIMER_LOADING_ANIMATION, 1000 / LOADING_ANIMATION_FPS, 0);
600 }
601 
602 VOID CAppScrnshotPreview::DisplayFailed()
603 {
604     InterlockedIncrement64(&ContentID);
605     SetStatus(SCRNSHOT_PREV_FAILED);
606     PreviousDisplayCleanup();
607 }
608 
609 BOOL CAppScrnshotPreview::DisplayFile(LPCWSTR lpszFileName)
610 {
611     PreviousDisplayCleanup();
612     SetStatus(SCRNSHOT_PREV_IMAGE);
613     pImage = Bitmap::FromFile(lpszFileName, 0);
614     if (pImage->GetLastStatus() != Ok)
615     {
616         DisplayFailed();
617         return FALSE;
618     }
619     return TRUE;
620 }
621 
622 VOID CAppScrnshotPreview::SetStatus(SCRNSHOT_STATUS Status)
623 {
624     ScrnshotPrevStauts = Status;
625 }
626 
627 VOID CAppScrnshotPreview::PaintOnDC(HDC hdc, int width, int height, BOOL bDrawBkgnd)
628 {
629     // use an off screen dc to avoid blinking
630     HDC hdcMem = CreateCompatibleDC(hdc);
631     HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
632     SelectObject(hdcMem, hBitmap);
633 
634     if (bDrawBkgnd)
635     {
636         HBRUSH hOldBrush = (HBRUSH)SelectObject(hdcMem, (HGDIOBJ)GetSysColorBrush(COLOR_BTNFACE));
637         PatBlt(hdcMem, 0, 0, width, height, PATCOPY);
638         SelectObject(hdcMem, hOldBrush);
639     }
640 
641     switch (ScrnshotPrevStauts)
642     {
643     case SCRNSHOT_PREV_EMPTY:
644     {
645 
646     }
647     break;
648 
649     case SCRNSHOT_PREV_LOADING:
650     {
651         Graphics graphics(hdcMem);
652         Color color(255, 0, 0);
653         SolidBrush dotBrush(Color(255, 100, 100, 100));
654 
655         graphics.SetSmoothingMode(SmoothingMode::SmoothingModeAntiAlias);
656 
657         // Paint three dot
658         float DotWidth = GetLoadingDotWidth(width, height);
659         graphics.FillEllipse((Brush *)(&dotBrush),
660             (REAL)width / 2.0 - min(width, height) * 2.0 / 16.0 - DotWidth / 2.0,
661             (REAL)height / 2.0 - GetFrameDotShift(LoadingAnimationFrame + LOADING_ANIMATION_FPS / 4, width, height) - DotWidth / 2.0,
662             DotWidth,
663             DotWidth);
664 
665         graphics.FillEllipse((Brush *)(&dotBrush),
666             (REAL)width / 2.0 - DotWidth / 2.0,
667             (REAL)height / 2.0 - GetFrameDotShift(LoadingAnimationFrame, width, height) - DotWidth / 2.0,
668             DotWidth,
669             DotWidth);
670 
671         graphics.FillEllipse((Brush *)(&dotBrush),
672             (REAL)width / 2.0 + min(width, height) * 2.0 / 16.0 - DotWidth / 2.0,
673             (REAL)height / 2.0 - GetFrameDotShift(LoadingAnimationFrame - LOADING_ANIMATION_FPS / 4, width, height) - DotWidth / 2.0,
674             DotWidth,
675             DotWidth);
676     }
677     break;
678 
679     case SCRNSHOT_PREV_IMAGE:
680     {
681         if (pImage)
682         {
683             // always draw entire image inside the window.
684             Graphics graphics(hdcMem);
685             float ZoomRatio = min(((float)width / (float)pImage->GetWidth()), ((float)height / (float)pImage->GetHeight()));
686             float ZoomedImgWidth = ZoomRatio * (float)pImage->GetWidth();
687             float ZoomedImgHeight = ZoomRatio * (float)pImage->GetHeight();
688 
689             graphics.DrawImage(pImage,
690                 ((float)width - ZoomedImgWidth) / 2.0, ((float)height - ZoomedImgHeight) / 2.0,
691                 ZoomedImgWidth, ZoomedImgHeight);
692         }
693     }
694     break;
695 
696     case SCRNSHOT_PREV_FAILED:
697     {
698         DrawIconEx(hdcMem,
699             (width - BrokenImgSize) / 2,
700             (height - BrokenImgSize) / 2,
701             hBrokenImgIcon,
702             BrokenImgSize,
703             BrokenImgSize,
704             NULL,
705             NULL,
706             DI_NORMAL | DI_COMPAT);
707     }
708     break;
709     }
710 
711     // copy the content form off-screen dc to hdc
712     BitBlt(hdc, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);
713     DeleteDC(hdcMem);
714     DeleteObject(hBitmap);
715 }
716 
717 float CAppScrnshotPreview::GetLoadingDotWidth(int width, int height)
718 {
719     return min(width, height) / 20.0;
720 }
721 
722 float CAppScrnshotPreview::GetFrameDotShift(int Frame, int width, int height)
723 {
724     return min(width, height) *
725         (1.0 / 16.0) *
726         (2.0 / (2.0 - sqrt(3.0))) *
727         (max(sin((float)Frame * 2 * PI / (LOADING_ANIMATION_PERIOD * LOADING_ANIMATION_FPS)), sqrt(3.0) / 2.0) - sqrt(3.0) / 2.0);
728 }
729 
730 ATL::CWndClassInfo &CAppScrnshotPreview::GetWndClassInfo()
731 {
732     DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
733     static ATL::CWndClassInfo wc =
734     {
735         {
736             sizeof(WNDCLASSEX),
737             csStyle,
738             StartWindowProc,
739             0,
740             0,
741             NULL,
742             0,
743             LoadCursorW(NULL, IDC_ARROW),
744             (HBRUSH)(COLOR_BTNFACE + 1),
745             0,
746             L"RAppsScrnshotPreview",
747             NULL
748         },
749         NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
750     };
751     return wc;
752 }
753 
754 HWND CAppScrnshotPreview::Create(HWND hParent)
755 {
756     RECT r = { 0,0,0,0 };
757 
758     return CWindowImpl::Create(hParent, r, L"", WS_CHILD | WS_VISIBLE);
759 }
760 
761 VOID CAppScrnshotPreview::PreviousDisplayCleanup()
762 {
763     if (bLoadingTimerOn)
764     {
765         KillTimer(TIMER_LOADING_ANIMATION);
766         bLoadingTimerOn = FALSE;
767     }
768     LoadingAnimationFrame = 0;
769     if (pImage)
770     {
771         delete pImage;
772         pImage = NULL;
773     }
774     if (AsyncInet)
775     {
776         AsyncInetCancel(AsyncInet);
777     }
778     if (!TempImagePath.IsEmpty())
779     {
780         DeleteFileW(TempImagePath.GetString());
781         TempImagePath.Empty();
782     }
783 }
784 
785 VOID CAppScrnshotPreview::DisplayEmpty()
786 {
787     InterlockedIncrement64(&ContentID);
788     SetStatus(SCRNSHOT_PREV_EMPTY);
789     PreviousDisplayCleanup();
790 }
791 
792 BOOL CAppScrnshotPreview::DisplayImage(LPCWSTR lpszLocation)
793 {
794     LONGLONG ID = InterlockedIncrement64(&ContentID);
795     PreviousDisplayCleanup();
796 
797     if (PathIsURLW(lpszLocation))
798     {
799         DisplayLoading();
800 
801         ScrnshotDownloadParam *DownloadParam = new ScrnshotDownloadParam;
802         if (!DownloadParam) return FALSE;
803 
804         DownloadParam->hwndNotify = m_hWnd;
805         DownloadParam->ID = ID;
806         // generate a filename
807         ATL::CStringW ScrnshotFolder = CAvailableApps::m_Strings.szAppsPath;
808         PathAppendW(ScrnshotFolder.GetBuffer(MAX_PATH), L"screenshots");
809         ScrnshotFolder.ReleaseBuffer();
810 
811         if (!PathIsDirectoryW(ScrnshotFolder.GetString()))
812         {
813             CreateDirectoryW(ScrnshotFolder.GetString(), NULL);
814         }
815 
816         if (!GetTempFileNameW(ScrnshotFolder.GetString(), L"img",
817             0, DownloadParam->DownloadFileName.GetBuffer(MAX_PATH)))
818         {
819             DownloadParam->DownloadFileName.ReleaseBuffer();
820             delete DownloadParam;
821             DisplayFailed();
822             return FALSE;
823         }
824         DownloadParam->DownloadFileName.ReleaseBuffer();
825 
826         DownloadParam->hFile = CreateFileW(DownloadParam->DownloadFileName.GetString(),
827             GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
828         if (DownloadParam->hFile == INVALID_HANDLE_VALUE)
829         {
830             delete DownloadParam;
831             DisplayFailed();
832             return FALSE;
833         }
834 
835         AsyncInet = AsyncInetDownload(0, INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, lpszLocation, TRUE, ScrnshotDownloadCallback, DownloadParam);
836         if (!AsyncInet)
837         {
838             CloseHandle(DownloadParam->hFile);
839             DeleteFileW(DownloadParam->DownloadFileName.GetBuffer());
840             delete DownloadParam;
841             DisplayFailed();
842             return FALSE;
843         }
844         return TRUE;
845     }
846     else
847     {
848         return DisplayFile(lpszLocation);
849     }
850 }
851 
852 int CAppScrnshotPreview::GetRequestedWidth(int Height) // calculate requested window width by given height
853 {
854     switch (ScrnshotPrevStauts)
855     {
856     case SCRNSHOT_PREV_EMPTY:
857         return 0;
858     case SCRNSHOT_PREV_LOADING:
859         return 200;
860     case SCRNSHOT_PREV_IMAGE:
861         if (pImage)
862         {
863             // return the width needed to display image inside the window.
864             // and always keep window w/h ratio inside [ 1/SCRNSHOT_MAX_ASPECT_RAT, SCRNSHOT_MAX_ASPECT_RAT ]
865             return (int)floor((float)Height *
866                 max(min((float)pImage->GetWidth() / (float)pImage->GetHeight(), (float)SCRNSHOT_MAX_ASPECT_RAT), 1.0 / (float)SCRNSHOT_MAX_ASPECT_RAT));
867         }
868         return 0;
869     case SCRNSHOT_PREV_FAILED:
870         return 200;
871     default:
872         return 0;
873     }
874 }
875 
876 CAppScrnshotPreview::~CAppScrnshotPreview()
877 {
878     PreviousDisplayCleanup();
879 }
880 // **** CAppScrnshotPreview ****
881 
882 
883 // **** CAppInfoDisplay ****
884 
885 BOOL CAppInfoDisplay::ProcessWindowMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT &theResult, DWORD dwMapId)
886 {
887     theResult = 0;
888     switch (message)
889     {
890     case WM_CREATE:
891     {
892         RichEdit = new CAppRichEdit();
893         RichEdit->Create(hwnd);
894 
895         ScrnshotPrev = new CAppScrnshotPreview();
896         ScrnshotPrev->Create(hwnd);
897         break;
898     }
899     case WM_SIZE:
900     {
901         ResizeChildren(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
902         break;
903     }
904     case WM_RAPPS_RESIZE_CHILDREN:
905     {
906         ResizeChildren();
907         break;
908     }
909     case WM_COMMAND:
910     {
911         OnCommand(wParam, lParam);
912         break;
913     }
914     case WM_NOTIFY:
915     {
916         NMHDR *NotifyHeader = (NMHDR *)lParam;
917         if (NotifyHeader->hwndFrom == RichEdit->m_hWnd)
918         {
919             switch (NotifyHeader->code)
920             {
921             case EN_LINK:
922                 OnLink((ENLINK *)lParam);
923                 break;
924             }
925         }
926         break;
927     }
928     }
929 
930     return FALSE;
931 }
932 
933 VOID CAppInfoDisplay::ResizeChildren()
934 {
935     CRect rect;
936     GetWindowRect(&rect);
937     ResizeChildren(rect.Width(), rect.Height());
938 }
939 
940 VOID CAppInfoDisplay::ResizeChildren(int Width, int Height)
941 {
942     int ScrnshotWidth = ScrnshotPrev->GetRequestedWidth(Height);
943 
944     // make sure richedit always have room to display
945     ScrnshotWidth = min(ScrnshotWidth, Width - INFO_DISPLAY_PADDING - RICHEDIT_MIN_WIDTH);
946 
947     DWORD dwError = ERROR_SUCCESS;
948     HDWP hDwp = BeginDeferWindowPos(2);
949 
950     if (hDwp)
951     {
952         hDwp = ::DeferWindowPos(hDwp, ScrnshotPrev->m_hWnd, NULL,
953             0, 0, ScrnshotWidth, Height, 0);
954 
955         if (hDwp)
956         {
957             // hide the padding if scrnshot window width == 0
958             int RicheditPosX = ScrnshotWidth ? (ScrnshotWidth + INFO_DISPLAY_PADDING) : 0;
959 
960             hDwp = ::DeferWindowPos(hDwp, RichEdit->m_hWnd, NULL,
961                 RicheditPosX, 0, Width - RicheditPosX, Height, 0);
962 
963             if (hDwp)
964             {
965                 EndDeferWindowPos(hDwp);
966             }
967             else
968             {
969                 dwError = GetLastError();
970             }
971         }
972         else
973         {
974             dwError = GetLastError();
975         }
976     }
977     else
978     {
979         dwError = GetLastError();
980     }
981 
982 
983 #if DBG
984     ATLASSERT(dwError == ERROR_SUCCESS);
985 #endif
986 
987     UpdateWindow();
988 }
989 
990 VOID CAppInfoDisplay::OnLink(ENLINK *Link)
991 {
992     switch (Link->msg)
993     {
994     case WM_LBUTTONUP:
995     case WM_RBUTTONUP:
996     {
997         if (pLink) HeapFree(GetProcessHeap(), 0, pLink);
998 
999         pLink = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
1000             (max(Link->chrg.cpMin, Link->chrg.cpMax) -
1001                 min(Link->chrg.cpMin, Link->chrg.cpMax) + 1) * sizeof(WCHAR));
1002         if (!pLink)
1003         {
1004             /* TODO: Error message */
1005             return;
1006         }
1007 
1008         RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin, Link->chrg.cpMax);
1009         RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM)pLink);
1010 
1011         ShowPopupMenuEx(m_hWnd, m_hWnd, IDR_LINKMENU, -1);
1012     }
1013     break;
1014     }
1015 }
1016 
1017 ATL::CWndClassInfo &CAppInfoDisplay::GetWndClassInfo()
1018 {
1019     DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
1020     static ATL::CWndClassInfo wc =
1021     {
1022         {
1023             sizeof(WNDCLASSEX),
1024             csStyle,
1025             StartWindowProc,
1026             0,
1027             0,
1028             NULL,
1029             NULL,
1030             NULL,
1031             (HBRUSH)(COLOR_BTNFACE + 1),
1032             NULL,
1033             L"RAppsAppInfo",
1034             NULL
1035         },
1036         NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
1037     };
1038     return wc;
1039 }
1040 
1041 HWND CAppInfoDisplay::Create(HWND hwndParent)
1042 {
1043     RECT r = { 0,0,0,0 };
1044 
1045     return CWindowImpl::Create(hwndParent, r, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
1046 }
1047 
1048 BOOL CAppInfoDisplay::ShowAvailableAppInfo(CAvailableApplicationInfo *Info)
1049 {
1050     ATL::CStringW ScrnshotLocation;
1051     if (Info->RetrieveScrnshot(0, ScrnshotLocation))
1052     {
1053         ScrnshotPrev->DisplayImage(ScrnshotLocation);
1054     }
1055     else
1056     {
1057         ScrnshotPrev->DisplayEmpty();
1058     }
1059     ResizeChildren();
1060     return RichEdit->ShowAvailableAppInfo(Info);
1061 }
1062 
1063 BOOL CAppInfoDisplay::ShowInstalledAppInfo(CInstalledApplicationInfo *Info)
1064 {
1065     ScrnshotPrev->DisplayEmpty();
1066     ResizeChildren();
1067     return RichEdit->ShowInstalledAppInfo(Info);
1068 }
1069 
1070 VOID CAppInfoDisplay::SetWelcomeText()
1071 {
1072     ScrnshotPrev->DisplayEmpty();
1073     ResizeChildren();
1074     RichEdit->SetWelcomeText();
1075 }
1076 
1077 VOID CAppInfoDisplay::OnCommand(WPARAM wParam, LPARAM lParam)
1078 {
1079     WORD wCommand = LOWORD(wParam);
1080 
1081     switch (wCommand)
1082     {
1083     case ID_OPEN_LINK:
1084 
1085         ShellExecuteW(m_hWnd, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
1086         HeapFree(GetProcessHeap(), 0, pLink);
1087         pLink = NULL;
1088         break;
1089 
1090     case ID_COPY_LINK:
1091         CopyTextToClipboard(pLink);
1092         HeapFree(GetProcessHeap(), 0, pLink);
1093         pLink = NULL;
1094         break;
1095 
1096     }
1097 }
1098 
1099 CAppInfoDisplay::~CAppInfoDisplay()
1100 {
1101     delete RichEdit;
1102     delete ScrnshotPrev;
1103 }
1104 // **** CAppInfoDisplay ****
1105 
1106 
1107 // **** CAppsListView ****
1108 
1109 CAppsListView::CAppsListView() :
1110     bHasCheckboxes(FALSE),
1111     nLastHeaderID(-1)
1112 {
1113 }
1114 
1115 VOID CAppsListView::SetCheckboxesVisible(BOOL bIsVisible)
1116 {
1117     if (bIsVisible)
1118     {
1119         SetExtendedListViewStyle(LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
1120     }
1121     else
1122     {
1123         SetExtendedListViewStyle(LVS_EX_FULLROWSELECT);
1124     }
1125 
1126     bHasCheckboxes = bIsVisible;
1127 }
1128 
1129 VOID CAppsListView::ColumnClick(LPNMLISTVIEW pnmv)
1130 {
1131     HWND hHeader;
1132     HDITEMW hColumn;
1133     INT nHeaderID = pnmv->iSubItem;
1134 
1135     if ((GetWindowLongPtr(GWL_STYLE) & ~LVS_NOSORTHEADER) == 0)
1136         return;
1137 
1138     hHeader = (HWND)SendMessage(LVM_GETHEADER, 0, 0);
1139     ZeroMemory(&hColumn, sizeof(hColumn));
1140 
1141     /* If the sorting column changed, remove the sorting style from the old column */
1142     if ((nLastHeaderID != -1) && (nLastHeaderID != nHeaderID))
1143     {
1144         bIsAscending = TRUE; // also reset sorting method to ascending
1145         hColumn.mask = HDI_FORMAT;
1146         Header_GetItem(hHeader, nLastHeaderID, &hColumn);
1147         hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
1148         Header_SetItem(hHeader, nLastHeaderID, &hColumn);
1149     }
1150 
1151     /* Set the sorting style to the new column */
1152     hColumn.mask = HDI_FORMAT;
1153     Header_GetItem(hHeader, nHeaderID, &hColumn);
1154 
1155     hColumn.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);
1156     hColumn.fmt |= (bIsAscending ? HDF_SORTUP : HDF_SORTDOWN);
1157     Header_SetItem(hHeader, nHeaderID, &hColumn);
1158 
1159     /* Sort the list, using the current values of nHeaderID and bIsAscending */
1160     SortContext ctx = { this, nHeaderID };
1161     SortItems(s_CompareFunc, &ctx);
1162 
1163     /* Save new values */
1164     nLastHeaderID = nHeaderID;
1165     bIsAscending = !bIsAscending;
1166 }
1167 
1168 BOOL CAppsListView::AddColumn(INT Index, ATL::CStringW &Text, INT Width, INT Format)
1169 {
1170     return AddColumn(Index, const_cast<LPWSTR>(Text.GetString()), Width, Format);
1171 }
1172 
1173 int CAppsListView::AddColumn(INT Index, LPWSTR lpText, INT Width, INT Format)
1174 {
1175     LVCOLUMNW Column;
1176 
1177     ZeroMemory(&Column, sizeof(Column));
1178 
1179     Column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
1180     Column.iSubItem = Index;
1181     Column.pszText = lpText;
1182     Column.cx = Width;
1183     Column.fmt = Format;
1184 
1185     return SendMessage(LVM_INSERTCOLUMN, Index, (LPARAM)(&Column));
1186 }
1187 
1188 void CAppsListView::DeleteColumn(INT Index)
1189 {
1190     SendMessage(LVM_DELETECOLUMN, Index, 0);
1191     return;
1192 }
1193 
1194 INT CAppsListView::AddItem(INT ItemIndex, INT IconIndex, LPCWSTR lpText, LPARAM lParam)
1195 {
1196     LVITEMW Item;
1197 
1198     ZeroMemory(&Item, sizeof(Item));
1199 
1200     Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
1201     Item.pszText = const_cast<LPWSTR>(lpText);
1202     Item.lParam = lParam;
1203     Item.iItem = ItemIndex;
1204     Item.iImage = IconIndex;
1205 
1206     if (IconIndex >= 0)
1207     {
1208         Item.iImage = IconIndex;
1209         Item.mask |= LVIF_IMAGE;
1210     }
1211     return InsertItem(&Item);
1212 }
1213 
1214 HIMAGELIST CAppsListView::GetImageList(int iImageList)
1215 {
1216     return (HIMAGELIST)SendMessage(LVM_GETIMAGELIST, iImageList, 0);
1217 }
1218 
1219 INT CALLBACK CAppsListView::s_CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
1220 {
1221     SortContext *ctx = ((SortContext *)lParamSort);
1222     return ctx->lvw->CompareFunc(lParam1, lParam2, ctx->iSubItem);
1223 }
1224 
1225 INT CAppsListView::CompareFunc(LPARAM lParam1, LPARAM lParam2, INT iSubItem)
1226 {
1227     ATL::CStringW Item1, Item2;
1228     LVFINDINFOW IndexInfo;
1229     INT Index;
1230 
1231     IndexInfo.flags = LVFI_PARAM;
1232 
1233     IndexInfo.lParam = lParam1;
1234     Index = FindItem(-1, &IndexInfo);
1235     GetItemText(Index, iSubItem, Item1.GetBuffer(MAX_STR_LEN), MAX_STR_LEN);
1236     Item1.ReleaseBuffer();
1237 
1238     IndexInfo.lParam = lParam2;
1239     Index = FindItem(-1, &IndexInfo);
1240     GetItemText(Index, iSubItem, Item2.GetBuffer(MAX_STR_LEN), MAX_STR_LEN);
1241     Item2.ReleaseBuffer();
1242 
1243     return bIsAscending ? Item1.Compare(Item2) : Item2.Compare(Item1);
1244 }
1245 
1246 HWND CAppsListView::Create(HWND hwndParent)
1247 {
1248     RECT r = { 205, 28, 465, 250 };
1249     DWORD style = WS_CHILD | WS_VISIBLE | LVS_SORTASCENDING | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_AUTOARRANGE;
1250 
1251     HWND hwnd = CListView::Create(hwndParent, r, NULL, style, WS_EX_CLIENTEDGE);
1252 
1253     if (hwnd)
1254     {
1255         SetCheckboxesVisible(FALSE);
1256     }
1257 
1258     m_hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
1259         LISTVIEW_ICON_SIZE,
1260         GetSystemColorDepth() | ILC_MASK,
1261         0, 1);
1262 
1263     // currently, this two Imagelist is the same one.
1264     SetImageList(m_hImageListView, LVSIL_SMALL);
1265     SetImageList(m_hImageListView, LVSIL_NORMAL);
1266 
1267     return hwnd;
1268 }
1269 
1270 BOOL CAppsListView::GetCheckState(INT item)
1271 {
1272     return (BOOL)(GetItemState(item, LVIS_STATEIMAGEMASK) >> 12) - 1;
1273 }
1274 
1275 VOID CAppsListView::SetCheckState(INT item, BOOL fCheck)
1276 {
1277     if (bHasCheckboxes)
1278     {
1279         SetItemState(item, INDEXTOSTATEIMAGEMASK((fCheck) ? 2 : 1), LVIS_STATEIMAGEMASK);
1280     }
1281 }
1282 
1283 VOID CAppsListView::CheckAll()
1284 {
1285     if (bHasCheckboxes)
1286     {
1287         if (CheckedItemCount == ItemCount)
1288         {
1289             // clear all
1290             SetCheckState(-1, FALSE);
1291         }
1292         else
1293         {
1294             // check all
1295             SetCheckState(-1, TRUE);
1296         }
1297     }
1298 }
1299 
1300 PVOID CAppsListView::GetFocusedItemData()
1301 {
1302     INT item = GetSelectionMark();
1303     if (item == -1)
1304     {
1305         return (PVOID)0;
1306     }
1307     return (PVOID)GetItemData(item);
1308 }
1309 
1310 BOOL CAppsListView::SetDisplayAppType(APPLICATION_VIEW_TYPE AppType)
1311 {
1312     if (!DeleteAllItems()) return FALSE;
1313     ApplicationViewType = AppType;
1314 
1315     bIsAscending = TRUE;
1316 
1317     ItemCount = 0;
1318     CheckedItemCount = 0;
1319 
1320     // delete old columns
1321     while (ColumnCount)
1322     {
1323         DeleteColumn(--ColumnCount);
1324     }
1325 
1326     ImageList_RemoveAll(m_hImageListView);
1327 
1328     // add new columns
1329     ATL::CStringW szText;
1330     switch (AppType)
1331     {
1332     case AppViewTypeInstalledApps:
1333 
1334         /* Add columns to ListView */
1335         szText.LoadStringW(IDS_APP_NAME);
1336         AddColumn(ColumnCount++, szText, 250, LVCFMT_LEFT);
1337 
1338         szText.LoadStringW(IDS_APP_INST_VERSION);
1339         AddColumn(ColumnCount++, szText, 90, LVCFMT_RIGHT);
1340 
1341         szText.LoadStringW(IDS_APP_DESCRIPTION);
1342         AddColumn(ColumnCount++, szText, 300, LVCFMT_LEFT);
1343 
1344         // disable checkboxes
1345         SetCheckboxesVisible(FALSE);
1346         break;
1347 
1348     case AppViewTypeAvailableApps:
1349 
1350         /* Add columns to ListView */
1351         szText.LoadStringW(IDS_APP_NAME);
1352         AddColumn(ColumnCount++, szText, 250, LVCFMT_LEFT);
1353 
1354         szText.LoadStringW(IDS_APP_INST_VERSION);
1355         AddColumn(ColumnCount++, szText, 90, LVCFMT_RIGHT);
1356 
1357         szText.LoadStringW(IDS_APP_DESCRIPTION);
1358         AddColumn(ColumnCount++, szText, 300, LVCFMT_LEFT);
1359 
1360         // enable checkboxes
1361         SetCheckboxesVisible(TRUE);
1362         break;
1363 
1364     case AppViewTypeEmpty:
1365     default:
1366         break;
1367     }
1368 
1369 
1370     return TRUE;
1371 }
1372 
1373 BOOL CAppsListView::SetViewMode(DWORD ViewMode)
1374 {
1375     return SendMessage(LVM_SETVIEW, (WPARAM)ViewMode, 0) == 1;
1376 }
1377 
1378 BOOL CAppsListView::AddInstalledApplication(CInstalledApplicationInfo *InstAppInfo, LPVOID CallbackParam)
1379 {
1380     if (ApplicationViewType != AppViewTypeInstalledApps)
1381     {
1382         return FALSE;
1383     }
1384 
1385     HICON hIcon = (HICON)LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1386 
1387     int IconIndex = ImageList_AddIcon(m_hImageListView, hIcon);
1388     DestroyIcon(hIcon);
1389 
1390     int Index = AddItem(ItemCount, IconIndex, InstAppInfo->szDisplayName, (LPARAM)CallbackParam);
1391     SetItemText(Index, 1, InstAppInfo->szDisplayVersion.IsEmpty() ? L"---" : InstAppInfo->szDisplayVersion);
1392     SetItemText(Index, 2, InstAppInfo->szComments.IsEmpty() ? L"---" : InstAppInfo->szComments);
1393 
1394     ItemCount++;
1395     return TRUE;
1396 }
1397 
1398 BOOL CAppsListView::AddAvailableApplication(CAvailableApplicationInfo *AvlbAppInfo, BOOL InitCheckState, LPVOID CallbackParam)
1399 {
1400     if (ApplicationViewType != AppViewTypeAvailableApps)
1401     {
1402         return FALSE;
1403     }
1404 
1405     /* Load icon from file */
1406     HICON hIcon = NULL;
1407     ATL::CStringW szIconPath;
1408     if (AvlbAppInfo->RetrieveIcon(szIconPath))
1409     {
1410         hIcon = (HICON)LoadImageW(NULL,
1411             szIconPath.GetString(),
1412             IMAGE_ICON,
1413             LISTVIEW_ICON_SIZE,
1414             LISTVIEW_ICON_SIZE,
1415             LR_LOADFROMFILE);
1416     }
1417 
1418     if (!hIcon || GetLastError() != ERROR_SUCCESS)
1419     {
1420         /* Load default icon */
1421         hIcon = (HICON)LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1422     }
1423 
1424     int IconIndex = ImageList_AddIcon(m_hImageListView, hIcon);
1425     DestroyIcon(hIcon);
1426 
1427     int Index = AddItem(ItemCount, IconIndex, AvlbAppInfo->m_szName, (LPARAM)CallbackParam);
1428 
1429     if (InitCheckState)
1430     {
1431         SetCheckState(Index, TRUE);
1432     }
1433 
1434     SetItemText(Index, 1, AvlbAppInfo->m_szVersion);
1435     SetItemText(Index, 2, AvlbAppInfo->m_szDesc);
1436 
1437     ItemCount++;
1438     return TRUE;
1439 }
1440 
1441 // this function is called when parent window receiving an notification about checkstate changing
1442 VOID CAppsListView::ItemCheckStateNotify(int iItem, BOOL bCheck)
1443 {
1444     if (bCheck)
1445     {
1446         CheckedItemCount++;
1447     }
1448     else
1449     {
1450         CheckedItemCount--;
1451     }
1452 }
1453 // **** CAppsListView ****
1454 
1455 
1456 // **** CApplicationView ****
1457 
1458 BOOL CApplicationView::ProcessWindowMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT &theResult, DWORD dwMapId)
1459 {
1460     theResult = 0;
1461     switch (message)
1462     {
1463     case WM_CREATE:
1464     {
1465         BOOL bSuccess = TRUE;
1466         m_Panel = new CUiPanel();
1467         m_Panel->m_VerticalAlignment = UiAlign_Stretch;
1468         m_Panel->m_HorizontalAlignment = UiAlign_Stretch;
1469 
1470         bSuccess &= CreateToolbar();
1471         bSuccess &= CreateSearchBar();
1472         bSuccess &= CreateComboBox();
1473         bSuccess &= CreateHSplitter();
1474         bSuccess &= CreateListView();
1475         bSuccess &= CreateAppInfoDisplay();
1476 
1477         m_Toolbar->AutoSize();
1478 
1479         RECT rTop;
1480 
1481         ::GetWindowRect(m_Toolbar->m_hWnd, &rTop);
1482         m_HSplitter->m_Margin.top = rTop.bottom - rTop.top;
1483         if (!bSuccess)
1484         {
1485             return -1; // creation failure
1486         }
1487     }
1488     break;
1489 
1490     case WM_NOTIFY:
1491     {
1492         LPNMHDR pNotifyHeader = (LPNMHDR)lParam;
1493         if (pNotifyHeader->hwndFrom == m_ListView->GetWindow())
1494         {
1495             switch (pNotifyHeader->code)
1496             {
1497             case LVN_ITEMCHANGED:
1498             {
1499                 LPNMLISTVIEW pnic = (LPNMLISTVIEW)lParam;
1500 
1501                 /* Check if this is a valid item
1502                 * (technically, it can be also an unselect) */
1503                 INT ItemIndex = pnic->iItem;
1504                 if (ItemIndex == -1 ||
1505                     ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
1506                 {
1507                     break;
1508                 }
1509 
1510                 /* Check if the focus has been moved to another item */
1511                 if ((pnic->uChanged & LVIF_STATE) &&
1512                     (pnic->uNewState & LVIS_FOCUSED) &&
1513                     !(pnic->uOldState & LVIS_FOCUSED))
1514                 {
1515                     ItemGetFocus((LPVOID)pnic->lParam);
1516                 }
1517 
1518                 /* Check if the item is checked/unchecked */
1519                 if (pnic->uChanged & LVIF_STATE)
1520                 {
1521                     int iOldState = STATEIMAGETOINDEX(pnic->uOldState);
1522                     int iNewState = STATEIMAGETOINDEX(pnic->uNewState);
1523 
1524                     if (iOldState == STATEIMAGE_UNCHECKED && iNewState == STATEIMAGE_CHECKED)
1525                     {
1526                         // this item is just checked
1527                         m_ListView->ItemCheckStateNotify(pnic->iItem, TRUE);
1528                         ItemCheckStateChanged(TRUE, (LPVOID)pnic->lParam);
1529                     }
1530                     else if (iOldState == STATEIMAGE_CHECKED && iNewState == STATEIMAGE_UNCHECKED)
1531                     {
1532                         // this item is just unchecked
1533                         m_ListView->ItemCheckStateNotify(pnic->iItem, FALSE);
1534                         ItemCheckStateChanged(FALSE, (LPVOID)pnic->lParam);
1535                     }
1536                 }
1537             }
1538             break;
1539 
1540             case LVN_COLUMNCLICK:
1541             {
1542                 LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
1543 
1544                 m_ListView->ColumnClick(pnmv);
1545             }
1546             break;
1547 
1548             case NM_DBLCLK:
1549             {
1550                 LPNMITEMACTIVATE Item = (LPNMITEMACTIVATE)lParam;
1551                 if (Item->iItem != -1)
1552                 {
1553                     /* this won't do anything if the program is already installed */
1554 
1555                     if (ApplicationViewType == AppViewTypeAvailableApps)
1556                     {
1557                         m_MainWindow->InstallApplication((CAvailableApplicationInfo *)m_ListView->GetItemData(Item->iItem));
1558                     }
1559                 }
1560             }
1561             break;
1562 
1563             case NM_RCLICK:
1564             {
1565                 if (((LPNMLISTVIEW)lParam)->iItem != -1)
1566                 {
1567                     ShowPopupMenuEx(m_hWnd, m_hWnd, 0, ID_INSTALL);
1568                 }
1569             }
1570             break;
1571             }
1572         }
1573         else if (pNotifyHeader->hwndFrom == m_Toolbar->GetWindow())
1574         {
1575             switch (pNotifyHeader->code)
1576             {
1577             case TTN_GETDISPINFO:
1578                 m_Toolbar->OnGetDispInfo((LPTOOLTIPTEXT)lParam);
1579                 break;
1580             }
1581         }
1582     }
1583     break;
1584 
1585     case WM_SYSCOLORCHANGE:
1586     {
1587         /* Forward WM_SYSCOLORCHANGE to common controls */
1588         m_ListView->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
1589         m_ListView->SendMessageW(EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_BTNFACE));
1590         m_Toolbar->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
1591         m_ComboBox->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
1592     }
1593     break;
1594 
1595     case WM_SIZE:
1596     {
1597         OnSize(hwnd, wParam, lParam);
1598         break;
1599     }
1600 
1601     case WM_COMMAND:
1602     {
1603         OnCommand(wParam, lParam);
1604     }
1605     break;
1606     }
1607     return FALSE;
1608 }
1609 
1610 BOOL CApplicationView::CreateToolbar()
1611 {
1612     m_Toolbar = new CMainToolbar();
1613     m_Toolbar->m_VerticalAlignment = UiAlign_LeftTop;
1614     m_Toolbar->m_HorizontalAlignment = UiAlign_Stretch;
1615     m_Panel->Children().Append(m_Toolbar);
1616 
1617     return m_Toolbar->Create(m_hWnd) != NULL;
1618 }
1619 
1620 BOOL CApplicationView::CreateSearchBar()
1621 {
1622     m_SearchBar = new CUiWindow<CSearchBar>();
1623     m_SearchBar->m_VerticalAlignment = UiAlign_LeftTop;
1624     m_SearchBar->m_HorizontalAlignment = UiAlign_RightBtm;
1625     m_SearchBar->m_Margin.top = 4;
1626     m_SearchBar->m_Margin.right = TOOLBAR_PADDING;
1627 
1628     return m_SearchBar->Create(m_Toolbar->m_hWnd) != NULL;
1629 }
1630 
1631 BOOL CApplicationView::CreateComboBox()
1632 {
1633     m_ComboBox = new CUiWindow<CComboBox>();
1634     m_ComboBox->m_VerticalAlignment = UiAlign_LeftTop;
1635     m_ComboBox->m_HorizontalAlignment = UiAlign_RightBtm;
1636     m_ComboBox->m_Margin.top = 4;
1637 
1638     return m_ComboBox->Create(m_Toolbar->m_hWnd) != NULL;
1639 }
1640 
1641 BOOL CApplicationView::CreateHSplitter()
1642 {
1643     m_HSplitter = new CUiSplitPanel();
1644     m_HSplitter->m_VerticalAlignment = UiAlign_Stretch;
1645     m_HSplitter->m_HorizontalAlignment = UiAlign_Stretch;
1646     m_HSplitter->m_DynamicFirst = TRUE;
1647     m_HSplitter->m_Horizontal = TRUE;
1648     m_HSplitter->m_Pos = INT_MAX; //set INT_MAX to use lowest possible position (m_MinSecond)
1649     m_HSplitter->m_MinFirst = 10;
1650     m_HSplitter->m_MinSecond = 140;
1651     m_Panel->Children().Append(m_HSplitter);
1652 
1653     return m_HSplitter->Create(m_hWnd) != NULL;
1654 }
1655 
1656 BOOL CApplicationView::CreateListView()
1657 {
1658     m_ListView = new CAppsListView();
1659     m_ListView->m_VerticalAlignment = UiAlign_Stretch;
1660     m_ListView->m_HorizontalAlignment = UiAlign_Stretch;
1661     m_HSplitter->First().Append(m_ListView);
1662 
1663     return m_ListView->Create(m_hWnd) != NULL;
1664 }
1665 
1666 BOOL CApplicationView::CreateAppInfoDisplay()
1667 {
1668     m_AppsInfo = new CAppInfoDisplay();
1669     m_AppsInfo->m_VerticalAlignment = UiAlign_Stretch;
1670     m_AppsInfo->m_HorizontalAlignment = UiAlign_Stretch;
1671     m_HSplitter->Second().Append(m_AppsInfo);
1672 
1673     return m_AppsInfo->Create(m_hWnd) != NULL;
1674 }
1675 
1676 VOID CApplicationView::OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
1677 {
1678     if (wParam == SIZE_MINIMIZED)
1679         return;
1680 
1681     /* Size tool bar */
1682     m_Toolbar->AutoSize();
1683 
1684     /* Automatically hide captions */
1685     DWORD dToolbarTreshold = m_Toolbar->GetMaxButtonsWidth();
1686     DWORD dSearchbarMargin = (LOWORD(lParam) - m_SearchBar->m_Width - m_ComboBox->m_Width - TOOLBAR_PADDING * 2);
1687 
1688     if (dSearchbarMargin > dToolbarTreshold)
1689     {
1690         m_Toolbar->ShowButtonCaption();
1691     }
1692     else if (dSearchbarMargin < dToolbarTreshold)
1693     {
1694         m_Toolbar->HideButtonCaption();
1695 
1696     }
1697 
1698     RECT r = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
1699     HDWP hdwp = NULL;
1700     INT count = m_Panel->CountSizableChildren();
1701 
1702     hdwp = BeginDeferWindowPos(count);
1703     if (hdwp)
1704     {
1705         hdwp = m_Panel->OnParentSize(r, hdwp);
1706         if (hdwp)
1707         {
1708             EndDeferWindowPos(hdwp);
1709         }
1710     }
1711 
1712     count = m_SearchBar->CountSizableChildren();
1713     hdwp = BeginDeferWindowPos(count);
1714     if (hdwp)
1715     {
1716         hdwp = m_SearchBar->OnParentSize(r, hdwp);
1717         if (hdwp)
1718         {
1719             EndDeferWindowPos(hdwp);
1720         }
1721     }
1722 
1723     m_ComboBox->m_Margin.right = m_SearchBar->m_Width + m_SearchBar->m_Margin.right + TOOLBAR_PADDING;
1724     count = m_ComboBox->CountSizableChildren();
1725     hdwp = BeginDeferWindowPos(count);
1726     if (hdwp)
1727     {
1728         hdwp = m_ComboBox->OnParentSize(r, hdwp);
1729         if (hdwp)
1730         {
1731             EndDeferWindowPos(hdwp);
1732         }
1733     }
1734 }
1735 
1736 VOID CApplicationView::OnCommand(WPARAM wParam, LPARAM lParam)
1737 {
1738     if (lParam)
1739     {
1740         if ((HWND)lParam == m_SearchBar->GetWindow())
1741         {
1742             ATL::CStringW szBuf;
1743             switch (HIWORD(wParam))
1744             {
1745             case EN_SETFOCUS:
1746             {
1747                 ATL::CStringW szWndText;
1748 
1749                 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1750                 m_SearchBar->GetWindowTextW(szWndText);
1751                 if (szBuf == szWndText)
1752                 {
1753                     m_SearchBar->SetWindowTextW(L"");
1754                 }
1755             }
1756             break;
1757 
1758             case EN_KILLFOCUS:
1759             {
1760                 m_SearchBar->GetWindowTextW(szBuf);
1761                 if (szBuf.IsEmpty())
1762                 {
1763                     szBuf.LoadStringW(IDS_SEARCH_TEXT);
1764                     m_SearchBar->SetWindowTextW(szBuf.GetString());
1765                 }
1766             }
1767             break;
1768 
1769             case EN_CHANGE:
1770             {
1771                 ATL::CStringW szWndText;
1772 
1773                 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1774                 m_SearchBar->GetWindowTextW(szWndText);
1775                 if (szBuf == szWndText)
1776                 {
1777                     szWndText = L"";
1778                     m_MainWindow->SearchTextChanged(szWndText);
1779                 }
1780                 else
1781                 {
1782                     m_MainWindow->SearchTextChanged(szWndText);
1783                 }
1784             }
1785             break;
1786             }
1787 
1788             return;
1789         }
1790         else if ((HWND)lParam == m_ComboBox->GetWindow())
1791         {
1792             int NotifyCode = HIWORD(wParam);
1793             switch (NotifyCode)
1794             {
1795             case CBN_SELCHANGE:
1796                 int CurrSelection = m_ComboBox->SendMessageW(CB_GETCURSEL);
1797 
1798                 int ViewModeList[] = { LV_VIEW_DETAILS, LV_VIEW_LIST, LV_VIEW_TILE };
1799                 ATLASSERT(CurrSelection < (int)_countof(ViewModeList));
1800                 if (!m_ListView->SetViewMode(ViewModeList[CurrSelection]))
1801                 {
1802                     MessageBoxW(L"View mode invalid or unimplemented");
1803                 }
1804                 break;
1805             }
1806 
1807             return;
1808         }
1809         else if ((HWND)lParam == m_Toolbar->GetWindow())
1810         {
1811             // the message is sent from Toolbar. fall down to continue process
1812         }
1813         else
1814         {
1815             return;
1816         }
1817     }
1818 
1819     // the LOWORD of wParam contains a Menu or Control ID
1820     WORD wCommand = LOWORD(wParam);
1821 
1822     switch (wCommand)
1823     {
1824     case ID_INSTALL:
1825         m_MainWindow->InstallApplication((CAvailableApplicationInfo *)GetFocusedItemData());
1826         break;
1827 
1828     case ID_TOOLBAR_INSTALL:
1829         m_MainWindow->SendMessageW(WM_COMMAND, ID_INSTALL, 0);
1830         break;
1831 
1832     case ID_UNINSTALL:
1833         m_MainWindow->SendMessageW(WM_COMMAND, ID_UNINSTALL, 0);
1834         break;
1835 
1836     case ID_MODIFY:
1837         m_MainWindow->SendMessageW(WM_COMMAND, ID_MODIFY, 0);
1838         break;
1839 
1840     case ID_REGREMOVE:
1841         m_MainWindow->SendMessageW(WM_COMMAND, ID_REGREMOVE, 0);
1842         break;
1843 
1844     case ID_REFRESH:
1845         m_MainWindow->SendMessageW(WM_COMMAND, ID_REFRESH, 0);
1846         break;
1847 
1848     case ID_RESETDB:
1849         m_MainWindow->SendMessageW(WM_COMMAND, ID_RESETDB, 0);
1850         break;
1851     }
1852 }
1853 
1854 CApplicationView::CApplicationView(CMainWindow *MainWindow)
1855     : m_MainWindow(MainWindow)
1856 {
1857 }
1858 
1859 CApplicationView::~CApplicationView()
1860 {
1861     delete m_Toolbar;
1862     delete m_SearchBar;
1863     delete m_ListView;
1864     delete m_AppsInfo;
1865     delete m_HSplitter;
1866 }
1867 
1868 ATL::CWndClassInfo &CApplicationView::GetWndClassInfo()
1869 {
1870     DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
1871     static ATL::CWndClassInfo wc =
1872     {
1873         {
1874             sizeof(WNDCLASSEX),
1875             csStyle,
1876             StartWindowProc,
1877             0,
1878             0,
1879             NULL,
1880             NULL,
1881             NULL,
1882             (HBRUSH)(COLOR_BTNFACE + 1),
1883             NULL,
1884             L"RAppsApplicationView",
1885             NULL
1886         },
1887         NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
1888     };
1889     return wc;
1890 }
1891 
1892 HWND CApplicationView::Create(HWND hwndParent)
1893 {
1894     RECT r = { 0,0,0,0 };
1895 
1896     HMENU menu = GetSubMenu(LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_APPLICATIONMENU)), 0);
1897 
1898     return CWindowImpl::Create(hwndParent, r, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, menu);
1899 }
1900 
1901 BOOL CApplicationView::SetDisplayAppType(APPLICATION_VIEW_TYPE AppType)
1902 {
1903     if (!m_ListView->SetDisplayAppType(AppType))
1904     {
1905         return FALSE;
1906     }
1907     ApplicationViewType = AppType;
1908     m_AppsInfo->SetWelcomeText();
1909 
1910     HMENU hMenu = ::GetMenu(m_hWnd);
1911     switch (AppType)
1912     {
1913     case AppViewTypeEmpty:
1914     default:
1915         EnableMenuItem(hMenu, ID_REGREMOVE, MF_GRAYED);
1916         EnableMenuItem(hMenu, ID_INSTALL, MF_GRAYED);
1917         EnableMenuItem(hMenu, ID_UNINSTALL, MF_GRAYED);
1918         EnableMenuItem(hMenu, ID_MODIFY, MF_GRAYED);
1919 
1920         m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, TRUE);
1921         m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, FALSE);
1922         m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, TRUE);
1923         m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, TRUE);
1924         break;
1925 
1926     case AppViewTypeInstalledApps:
1927         EnableMenuItem(hMenu, ID_REGREMOVE, MF_ENABLED);
1928         EnableMenuItem(hMenu, ID_INSTALL, MF_GRAYED);
1929         EnableMenuItem(hMenu, ID_UNINSTALL, MF_ENABLED);
1930         EnableMenuItem(hMenu, ID_MODIFY, MF_ENABLED);
1931 
1932         // TODO: instead of disable these button, I would rather remove them.
1933         m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, TRUE);
1934         m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, FALSE);
1935         m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, TRUE);
1936         m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, TRUE);
1937         break;
1938 
1939     case AppViewTypeAvailableApps:
1940         EnableMenuItem(hMenu, ID_REGREMOVE, MF_GRAYED);
1941         EnableMenuItem(hMenu, ID_INSTALL, MF_ENABLED);
1942         EnableMenuItem(hMenu, ID_UNINSTALL, MF_GRAYED);
1943         EnableMenuItem(hMenu, ID_MODIFY, MF_GRAYED);
1944 
1945         // TODO: instead of disable these button, I would rather remove them.
1946         m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, FALSE);
1947         m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, TRUE);
1948         m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, FALSE);
1949         m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, FALSE);
1950         break;
1951     }
1952     return TRUE;
1953 }
1954 
1955 BOOL CApplicationView::AddInstalledApplication(CInstalledApplicationInfo *InstAppInfo, LPVOID param)
1956 {
1957     if (ApplicationViewType != AppViewTypeInstalledApps)
1958     {
1959         return FALSE;
1960     }
1961     return m_ListView->AddInstalledApplication(InstAppInfo, param);
1962 }
1963 
1964 BOOL CApplicationView::AddAvailableApplication(CAvailableApplicationInfo *AvlbAppInfo, BOOL InitCheckState, LPVOID param)
1965 {
1966     if (ApplicationViewType != AppViewTypeAvailableApps)
1967     {
1968         return FALSE;
1969     }
1970     return m_ListView->AddAvailableApplication(AvlbAppInfo, InitCheckState, param);
1971 }
1972 
1973 void CApplicationView::CheckAll()
1974 {
1975     m_ListView->CheckAll();
1976     return;
1977 }
1978 
1979 PVOID CApplicationView::GetFocusedItemData()
1980 {
1981     return m_ListView->GetFocusedItemData();
1982 }
1983 
1984 int CApplicationView::GetItemCount()
1985 {
1986     return m_ListView->GetItemCount();
1987 }
1988 
1989 VOID CApplicationView::AppendTabOrderWindow(int Direction, ATL::CSimpleArray<HWND> &TabOrderList)
1990 {
1991     m_Toolbar->AppendTabOrderWindow(Direction, TabOrderList);
1992     m_ComboBox->AppendTabOrderWindow(Direction, TabOrderList);
1993     m_SearchBar->AppendTabOrderWindow(Direction, TabOrderList);
1994     m_ListView->AppendTabOrderWindow(Direction, TabOrderList);
1995     m_AppsInfo->AppendTabOrderWindow(Direction, TabOrderList);
1996 
1997     return;
1998 }
1999 
2000 // this function is called when a item of listview get focus.
2001 // CallbackParam is the param passed to listview when adding the item (the one getting focus now).
2002 BOOL CApplicationView::ItemGetFocus(LPVOID CallbackParam)
2003 {
2004     switch (ApplicationViewType)
2005     {
2006     case AppViewTypeInstalledApps:
2007         return m_AppsInfo->ShowInstalledAppInfo((CInstalledApplicationInfo *)CallbackParam);
2008 
2009     case AppViewTypeAvailableApps:
2010         return m_AppsInfo->ShowAvailableAppInfo((CAvailableApplicationInfo *)CallbackParam);
2011 
2012     case AppViewTypeEmpty:
2013     default:
2014         m_AppsInfo->SetWelcomeText();
2015         return FALSE;
2016     }
2017 }
2018 
2019 // this function is called when a item of listview is checked/unchecked
2020 // CallbackParam is the param passed to listview when adding the item (the one getting focus now).
2021 BOOL CApplicationView::ItemCheckStateChanged(BOOL bChecked, LPVOID CallbackParam)
2022 {
2023     m_MainWindow->ItemCheckStateChanged(bChecked, CallbackParam);
2024     return TRUE;
2025 }
2026 // **** CApplicationView ****
2027 
2028