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