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