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