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