1 /* 2 * PROJECT: ReactOS Applications Manager 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: GUI classes for RAPPS 5 * COPYRIGHT: Copyright 2015 David Quintana (gigaherz@gmail.com) 6 * Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org) 7 * Copyright 2020 He Yang (1160386205@qq.com) 8 */ 9 10 #include "rapps.h" 11 #include "rosui.h" 12 #include "crichedit.h" 13 #include "appview.h" 14 #include "asyncinet.h" 15 #include "misc.h" 16 #include "gui.h" 17 #include "appview.h" 18 #include "winmain.h" 19 #include <shlobj_undoc.h> 20 #include <shlguid_undoc.h> 21 22 #include <atlbase.h> 23 #include <atlcom.h> 24 #include <atltypes.h> 25 #include <atlwin.h> 26 #include <wininet.h> 27 #include <shellutils.h> 28 #include <rosctrls.h> 29 #include <gdiplus.h> 30 #include <math.h> 31 32 #define SEARCH_TIMER_ID 'SR' 33 #define TREEVIEW_ICON_SIZE 24 34 35 36 37 // **** CSideTreeView **** 38 39 CSideTreeView::CSideTreeView() : 40 CUiWindow(), 41 hImageTreeView(ImageList_Create(TREEVIEW_ICON_SIZE, TREEVIEW_ICON_SIZE, 42 GetSystemColorDepth() | ILC_MASK, 43 0, 1)) 44 { 45 } 46 47 HTREEITEM CSideTreeView::AddItem(HTREEITEM hParent, ATL::CStringW &Text, INT Image, INT SelectedImage, LPARAM lParam) 48 { 49 return CUiWindow<CTreeView>::AddItem(hParent, const_cast<LPWSTR>(Text.GetString()), Image, SelectedImage, lParam); 50 } 51 52 HTREEITEM CSideTreeView::AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex) 53 { 54 ATL::CStringW szText; 55 INT Index = 0; 56 HICON hIcon; 57 58 hIcon = (HICON)LoadImageW(hInst, 59 MAKEINTRESOURCE(IconIndex), 60 IMAGE_ICON, 61 TREEVIEW_ICON_SIZE, 62 TREEVIEW_ICON_SIZE, 63 LR_CREATEDIBSECTION); 64 if (hIcon) 65 { 66 Index = ImageList_AddIcon(hImageTreeView, hIcon); 67 DestroyIcon(hIcon); 68 } 69 70 szText.LoadStringW(TextIndex); 71 return AddItem(hRootItem, szText, Index, Index, TextIndex); 72 } 73 74 HIMAGELIST CSideTreeView::SetImageList() 75 { 76 return CUiWindow<CTreeView>::SetImageList(hImageTreeView, TVSIL_NORMAL); 77 } 78 79 VOID CSideTreeView::DestroyImageList() 80 { 81 if (hImageTreeView) 82 ImageList_Destroy(hImageTreeView); 83 } 84 85 CSideTreeView::~CSideTreeView() 86 { 87 DestroyImageList(); 88 } 89 // **** CSideTreeView **** 90 91 92 93 // **** CMainWindow **** 94 95 CMainWindow::CMainWindow() : 96 m_ClientPanel(NULL), 97 SelectedEnumType(ENUM_ALL_INSTALLED) 98 { 99 } 100 101 CMainWindow::~CMainWindow() 102 { 103 LayoutCleanup(); 104 } 105 106 VOID CMainWindow::InitCategoriesList() 107 { 108 HTREEITEM hRootItemInstalled, hRootItemAvailable; 109 110 hRootItemInstalled = m_TreeView->AddCategory(TVI_ROOT, IDS_INSTALLED, IDI_CATEGORY); 111 m_TreeView->AddCategory(hRootItemInstalled, IDS_APPLICATIONS, IDI_APPS); 112 m_TreeView->AddCategory(hRootItemInstalled, IDS_UPDATES, IDI_APPUPD); 113 114 m_TreeView->AddCategory(TVI_ROOT, IDS_SELECTEDFORINST, IDI_SELECTEDFORINST); 115 116 hRootItemAvailable = m_TreeView->AddCategory(TVI_ROOT, IDS_AVAILABLEFORINST, IDI_CATEGORY); 117 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_AUDIO, IDI_CAT_AUDIO); 118 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_VIDEO, IDI_CAT_VIDEO); 119 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_GRAPHICS, IDI_CAT_GRAPHICS); 120 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_GAMES, IDI_CAT_GAMES); 121 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_INTERNET, IDI_CAT_INTERNET); 122 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_OFFICE, IDI_CAT_OFFICE); 123 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_DEVEL, IDI_CAT_DEVEL); 124 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_EDU, IDI_CAT_EDU); 125 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_ENGINEER, IDI_CAT_ENGINEER); 126 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_FINANCE, IDI_CAT_FINANCE); 127 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_SCIENCE, IDI_CAT_SCIENCE); 128 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_TOOLS, IDI_CAT_TOOLS); 129 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_DRIVERS, IDI_CAT_DRIVERS); 130 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_LIBS, IDI_CAT_LIBS); 131 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_THEMES, IDI_CAT_THEMES); 132 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_OTHER, IDI_CAT_OTHER); 133 134 m_TreeView->SetImageList(); 135 m_TreeView->Expand(hRootItemInstalled, TVE_EXPAND); 136 m_TreeView->Expand(hRootItemAvailable, TVE_EXPAND); 137 m_TreeView->SelectItem(hRootItemAvailable); 138 } 139 140 BOOL CMainWindow::CreateStatusBar() 141 { 142 m_StatusBar = new CUiWindow<CStatusBar>(); 143 m_StatusBar->m_VerticalAlignment = UiAlign_RightBtm; 144 m_StatusBar->m_HorizontalAlignment = UiAlign_Stretch; 145 m_ClientPanel->Children().Append(m_StatusBar); 146 147 return m_StatusBar->Create(m_hWnd, (HMENU)IDC_STATUSBAR) != NULL; 148 } 149 150 BOOL CMainWindow::CreateTreeView() 151 { 152 m_TreeView = new CSideTreeView(); 153 m_TreeView->m_VerticalAlignment = UiAlign_Stretch; 154 m_TreeView->m_HorizontalAlignment = UiAlign_Stretch; 155 m_VSplitter->First().Append(m_TreeView); 156 157 return m_TreeView->Create(m_hWnd) != NULL; 158 } 159 160 BOOL CMainWindow::CreateApplicationView() 161 { 162 m_ApplicationView = new CApplicationView(this); // pass this to ApplicationView for callback purpose 163 m_ApplicationView->m_VerticalAlignment = UiAlign_Stretch; 164 m_ApplicationView->m_HorizontalAlignment = UiAlign_Stretch; 165 m_VSplitter->Second().Append(m_ApplicationView); 166 167 return m_ApplicationView->Create(m_hWnd) != NULL; 168 } 169 170 BOOL CMainWindow::CreateVSplitter() 171 { 172 m_VSplitter = new CUiSplitPanel(); 173 m_VSplitter->m_VerticalAlignment = UiAlign_Stretch; 174 m_VSplitter->m_HorizontalAlignment = UiAlign_Stretch; 175 m_VSplitter->m_DynamicFirst = FALSE; 176 m_VSplitter->m_Horizontal = FALSE; 177 m_VSplitter->m_MinFirst = 0; 178 179 // TODO: m_MinSecond should be calculate dynamically instead of hard-coded 180 m_VSplitter->m_MinSecond = 480; 181 m_VSplitter->m_Pos = 240; 182 m_ClientPanel->Children().Append(m_VSplitter); 183 184 return m_VSplitter->Create(m_hWnd) != NULL; 185 } 186 187 BOOL CMainWindow::CreateLayout() 188 { 189 BOOL b = TRUE; 190 bUpdating = TRUE; 191 192 m_ClientPanel = new CUiPanel(); 193 m_ClientPanel->m_VerticalAlignment = UiAlign_Stretch; 194 m_ClientPanel->m_HorizontalAlignment = UiAlign_Stretch; 195 196 // Top level 197 b = b && CreateStatusBar(); 198 b = b && CreateVSplitter(); 199 200 // Inside V Splitter 201 b = b && CreateTreeView(); 202 b = b && CreateApplicationView(); 203 204 if (b) 205 { 206 RECT rBottom; 207 208 /* Size status bar */ 209 m_StatusBar->SendMessageW(WM_SIZE, 0, 0); 210 211 ::GetWindowRect(m_StatusBar->m_hWnd, &rBottom); 212 213 m_VSplitter->m_Margin.bottom = rBottom.bottom - rBottom.top; 214 } 215 216 bUpdating = FALSE; 217 return b; 218 } 219 220 VOID CMainWindow::LayoutCleanup() 221 { 222 delete m_TreeView; 223 delete m_ApplicationView; 224 delete m_VSplitter; 225 delete m_StatusBar; 226 return; 227 } 228 229 BOOL CMainWindow::InitControls() 230 { 231 if (CreateLayout()) 232 { 233 InitCategoriesList(); 234 235 UpdateStatusBarText(); 236 237 return TRUE; 238 } 239 240 return FALSE; 241 } 242 243 VOID CMainWindow::OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam) 244 { 245 if (wParam == SIZE_MINIMIZED) 246 return; 247 248 /* Size status bar */ 249 m_StatusBar->SendMessage(WM_SIZE, 0, 0); 250 251 252 RECT r = { 0, 0, LOWORD(lParam), HIWORD(lParam) }; 253 HDWP hdwp = NULL; 254 INT count = m_ClientPanel->CountSizableChildren(); 255 256 hdwp = BeginDeferWindowPos(count); 257 if (hdwp) 258 { 259 hdwp = m_ClientPanel->OnParentSize(r, hdwp); 260 if (hdwp) 261 { 262 EndDeferWindowPos(hdwp); 263 } 264 } 265 } 266 267 BOOL CMainWindow::RemoveSelectedAppFromRegistry() 268 { 269 if (!IsInstalledEnum(SelectedEnumType)) 270 return FALSE; 271 272 ATL::CStringW szMsgText, szMsgTitle; 273 274 if (!szMsgText.LoadStringW(IDS_APP_REG_REMOVE) || 275 !szMsgTitle.LoadStringW(IDS_INFORMATION)) 276 return FALSE; 277 278 if (MessageBoxW(szMsgText, szMsgTitle, MB_YESNO | MB_ICONQUESTION) == IDYES) 279 { 280 CInstalledApplicationInfo *InstalledApp = (CInstalledApplicationInfo *)m_ApplicationView->GetFocusedItemData(); 281 if (!InstalledApp) 282 return FALSE; 283 284 LSTATUS Result = InstalledApp->RemoveFromRegistry(); 285 if (Result != ERROR_SUCCESS) 286 { 287 // TODO: popup a messagebox telling user it fails somehow 288 return FALSE; 289 } 290 291 // as it's already removed form registry, this will also remove it from the list 292 UpdateApplicationsList(-1); 293 return TRUE; 294 } 295 296 return FALSE; 297 } 298 299 BOOL CMainWindow::UninstallSelectedApp(BOOL bModify) 300 { 301 if (!IsInstalledEnum(SelectedEnumType)) 302 return FALSE; 303 304 CInstalledApplicationInfo *InstalledApp = (CInstalledApplicationInfo *)m_ApplicationView->GetFocusedItemData(); 305 if (!InstalledApp) 306 return FALSE; 307 308 return InstalledApp->UninstallApplication(bModify); 309 } 310 311 BOOL CMainWindow::ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT &theResult, DWORD dwMapId) 312 { 313 theResult = 0; 314 switch (Msg) 315 { 316 case WM_CREATE: 317 if (!InitControls()) 318 ::PostMessageW(hwnd, WM_CLOSE, 0, 0); 319 break; 320 321 case WM_DESTROY: 322 { 323 ShowWindow(SW_HIDE); 324 SaveSettings(hwnd, &SettingsInfo); 325 326 FreeLogs(); 327 m_AvailableApps.FreeCachedEntries(); 328 m_InstalledApps.FreeCachedEntries(); 329 330 delete m_ClientPanel; 331 332 PostQuitMessage(0); 333 return 0; 334 } 335 336 case WM_COMMAND: 337 OnCommand(wParam, lParam); 338 break; 339 340 case WM_NOTIFY: 341 { 342 LPNMHDR data = (LPNMHDR)lParam; 343 344 switch (data->code) 345 { 346 case TVN_SELCHANGED: 347 { 348 if (data->hwndFrom == m_TreeView->m_hWnd) 349 { 350 switch (((LPNMTREEVIEW)lParam)->itemNew.lParam) 351 { 352 case IDS_INSTALLED: 353 UpdateApplicationsList(ENUM_ALL_INSTALLED); 354 break; 355 356 case IDS_APPLICATIONS: 357 UpdateApplicationsList(ENUM_INSTALLED_APPLICATIONS); 358 break; 359 360 case IDS_UPDATES: 361 UpdateApplicationsList(ENUM_UPDATES); 362 break; 363 364 case IDS_AVAILABLEFORINST: 365 UpdateApplicationsList(ENUM_ALL_AVAILABLE); 366 break; 367 368 case IDS_CAT_AUDIO: 369 UpdateApplicationsList(ENUM_CAT_AUDIO); 370 break; 371 372 case IDS_CAT_DEVEL: 373 UpdateApplicationsList(ENUM_CAT_DEVEL); 374 break; 375 376 case IDS_CAT_DRIVERS: 377 UpdateApplicationsList(ENUM_CAT_DRIVERS); 378 break; 379 380 case IDS_CAT_EDU: 381 UpdateApplicationsList(ENUM_CAT_EDU); 382 break; 383 384 case IDS_CAT_ENGINEER: 385 UpdateApplicationsList(ENUM_CAT_ENGINEER); 386 break; 387 388 case IDS_CAT_FINANCE: 389 UpdateApplicationsList(ENUM_CAT_FINANCE); 390 break; 391 392 case IDS_CAT_GAMES: 393 UpdateApplicationsList(ENUM_CAT_GAMES); 394 break; 395 396 case IDS_CAT_GRAPHICS: 397 UpdateApplicationsList(ENUM_CAT_GRAPHICS); 398 break; 399 400 case IDS_CAT_INTERNET: 401 UpdateApplicationsList(ENUM_CAT_INTERNET); 402 break; 403 404 case IDS_CAT_LIBS: 405 UpdateApplicationsList(ENUM_CAT_LIBS); 406 break; 407 408 case IDS_CAT_OFFICE: 409 UpdateApplicationsList(ENUM_CAT_OFFICE); 410 break; 411 412 case IDS_CAT_OTHER: 413 UpdateApplicationsList(ENUM_CAT_OTHER); 414 break; 415 416 case IDS_CAT_SCIENCE: 417 UpdateApplicationsList(ENUM_CAT_SCIENCE); 418 break; 419 420 case IDS_CAT_TOOLS: 421 UpdateApplicationsList(ENUM_CAT_TOOLS); 422 break; 423 424 case IDS_CAT_VIDEO: 425 UpdateApplicationsList(ENUM_CAT_VIDEO); 426 break; 427 428 case IDS_CAT_THEMES: 429 UpdateApplicationsList(ENUM_CAT_THEMES); 430 break; 431 432 case IDS_SELECTEDFORINST: 433 UpdateApplicationsList(ENUM_CAT_SELECTED); 434 break; 435 } 436 } 437 438 HMENU mainMenu = ::GetMenu(hwnd); 439 440 /* Disable/enable items based on treeview selection */ 441 if (IsSelectedNodeInstalled()) 442 { 443 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_ENABLED); 444 EnableMenuItem(mainMenu, ID_INSTALL, MF_GRAYED); 445 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_ENABLED); 446 EnableMenuItem(mainMenu, ID_MODIFY, MF_ENABLED); 447 } 448 else 449 { 450 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_GRAYED); 451 EnableMenuItem(mainMenu, ID_INSTALL, MF_ENABLED); 452 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_GRAYED); 453 EnableMenuItem(mainMenu, ID_MODIFY, MF_GRAYED); 454 } 455 } 456 break; 457 458 } 459 } 460 break; 461 462 case WM_SIZE: 463 OnSize(hwnd, wParam, lParam); 464 break; 465 466 case WM_SIZING: 467 { 468 LPRECT pRect = (LPRECT)lParam; 469 470 if (pRect->right - pRect->left < 565) 471 pRect->right = pRect->left + 565; 472 473 if (pRect->bottom - pRect->top < 300) 474 pRect->bottom = pRect->top + 300; 475 476 return TRUE; 477 } 478 479 case WM_SYSCOLORCHANGE: 480 { 481 /* Forward WM_SYSCOLORCHANGE to common controls */ 482 m_ApplicationView->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam); 483 m_TreeView->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam); 484 } 485 break; 486 487 case WM_TIMER: 488 if (wParam == SEARCH_TIMER_ID) 489 { 490 ::KillTimer(hwnd, SEARCH_TIMER_ID); 491 492 UpdateApplicationsList(-1); 493 } 494 break; 495 } 496 497 return FALSE; 498 } 499 500 BOOL CMainWindow::IsSelectedNodeInstalled() 501 { 502 HTREEITEM hSelectedItem = m_TreeView->GetSelection(); 503 TV_ITEM tItem; 504 505 tItem.mask = TVIF_PARAM | TVIF_HANDLE; 506 tItem.hItem = hSelectedItem; 507 m_TreeView->GetItem(&tItem); 508 switch (tItem.lParam) 509 { 510 case IDS_INSTALLED: 511 case IDS_APPLICATIONS: 512 case IDS_UPDATES: 513 return TRUE; 514 default: 515 return FALSE; 516 } 517 } 518 519 VOID CMainWindow::ShowAboutDlg() 520 { 521 ATL::CStringW szApp; 522 ATL::CStringW szAuthors; 523 HICON hIcon; 524 525 szApp.LoadStringW(IDS_APPTITLE); 526 szAuthors.LoadStringW(IDS_APP_AUTHORS); 527 hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN)); 528 ShellAboutW(m_hWnd, szApp, szAuthors, hIcon); 529 DestroyIcon(hIcon); 530 } 531 532 VOID CMainWindow::OnCommand(WPARAM wParam, LPARAM lParam) 533 { 534 WORD wCommand = LOWORD(wParam); 535 536 if (!lParam) 537 { 538 switch (wCommand) 539 { 540 case ID_SETTINGS: 541 CreateSettingsDlg(m_hWnd); 542 break; 543 544 case ID_EXIT: 545 PostMessageW(WM_CLOSE, 0, 0); 546 break; 547 548 case ID_INSTALL: 549 if (IsAvailableEnum(SelectedEnumType)) 550 { 551 ATL::CSimpleArray<CAvailableApplicationInfo> AppsList; 552 553 // enum all selected apps 554 m_AvailableApps.Enum(ENUM_CAT_SELECTED, s_EnumSelectedAppForDownloadProc, (PVOID)&AppsList); 555 556 if (AppsList.GetSize()) 557 { 558 if (DownloadListOfApplications(AppsList, FALSE)) 559 { 560 m_AvailableApps.RemoveAllSelected(); 561 UpdateApplicationsList(-1); 562 } 563 } 564 else 565 { 566 // use the currently focused item in application-view 567 CAvailableApplicationInfo *FocusedApps = (CAvailableApplicationInfo *)m_ApplicationView->GetFocusedItemData(); 568 if (FocusedApps) 569 { 570 if (DownloadApplication(FocusedApps, FALSE)) 571 { 572 UpdateApplicationsList(-1); 573 } 574 } 575 else 576 { 577 // TODO: in this case, Install button in toolbar (and all other places) should be disabled 578 // or at least popup a messagebox telling user to select/check some app first 579 } 580 } 581 } 582 break; 583 584 case ID_UNINSTALL: 585 if (UninstallSelectedApp(FALSE)) 586 UpdateApplicationsList(-1); 587 break; 588 589 case ID_MODIFY: 590 if (UninstallSelectedApp(TRUE)) 591 UpdateApplicationsList(-1); 592 break; 593 594 case ID_REGREMOVE: 595 RemoveSelectedAppFromRegistry(); 596 break; 597 598 case ID_REFRESH: 599 UpdateApplicationsList(-1); 600 break; 601 602 case ID_RESETDB: 603 CAvailableApps::ForceUpdateAppsDB(); 604 UpdateApplicationsList(-1); 605 break; 606 607 case ID_HELP: 608 MessageBoxW(L"Help not implemented yet", NULL, MB_OK); 609 break; 610 611 case ID_ABOUT: 612 ShowAboutDlg(); 613 break; 614 615 case ID_CHECK_ALL: 616 m_ApplicationView->CheckAll(); 617 break; 618 } 619 } 620 } 621 622 BOOL CALLBACK CMainWindow::EnumInstalledAppProc(CInstalledApplicationInfo *Info) 623 { 624 if (!SearchPatternMatch(Info->szDisplayName.GetString(), szSearchPattern)) 625 { 626 return TRUE; 627 } 628 return m_ApplicationView->AddInstalledApplication(Info, Info); // currently, the callback param is Info itself 629 } 630 631 BOOL CALLBACK CMainWindow::EnumAvailableAppProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState) 632 { 633 if (!SearchPatternMatch(Info->m_szName.GetString(), szSearchPattern) && 634 !SearchPatternMatch(Info->m_szDesc.GetString(), szSearchPattern)) 635 { 636 return TRUE; 637 } 638 return m_ApplicationView->AddAvailableApplication(Info, bInitialCheckState, Info); // currently, the callback param is Info itself 639 } 640 641 BOOL CALLBACK CMainWindow::s_EnumInstalledAppProc(CInstalledApplicationInfo *Info, PVOID param) 642 { 643 CMainWindow *pThis = (CMainWindow *)param; 644 return pThis->EnumInstalledAppProc(Info); 645 } 646 647 BOOL CALLBACK CMainWindow::s_EnumAvailableAppProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState, PVOID param) 648 { 649 CMainWindow *pThis = (CMainWindow *)param; 650 return pThis->EnumAvailableAppProc(Info, bInitialCheckState); 651 } 652 653 BOOL CALLBACK CMainWindow::s_EnumSelectedAppForDownloadProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState, PVOID param) 654 { 655 ATL::CSimpleArray<CAvailableApplicationInfo> *pAppList = (ATL::CSimpleArray<CAvailableApplicationInfo> *)param; 656 pAppList->Add(*Info); 657 return TRUE; 658 } 659 660 VOID CMainWindow::UpdateStatusBarText() 661 { 662 if (m_StatusBar) 663 { 664 ATL::CStringW szBuffer; 665 666 szBuffer.Format(IDS_APPS_COUNT, m_ApplicationView->GetItemCount(), m_AvailableApps.GetSelectedCount()); 667 m_StatusBar->SetText(szBuffer); 668 } 669 } 670 671 VOID CMainWindow::UpdateApplicationsList(INT EnumType) 672 { 673 bUpdating = TRUE; 674 675 if (EnumType == -1) 676 { 677 // keep the old enum type 678 EnumType = SelectedEnumType; 679 } 680 else 681 { 682 SelectedEnumType = EnumType; 683 } 684 685 m_ApplicationView->SetRedraw(FALSE); 686 if (IsInstalledEnum(EnumType)) 687 { 688 // set the display type of application-view. this will remove all the item in application-view too. 689 m_ApplicationView->SetDisplayAppType(AppViewTypeInstalledApps); 690 691 // enum installed softwares 692 m_InstalledApps.Enum(EnumType, s_EnumInstalledAppProc, this); 693 } 694 else if (IsAvailableEnum(EnumType)) 695 { 696 // set the display type of application-view. this will remove all the item in application-view too. 697 m_ApplicationView->SetDisplayAppType(AppViewTypeAvailableApps); 698 699 // enum available softwares 700 m_AvailableApps.Enum(EnumType, s_EnumAvailableAppProc, this); 701 } 702 m_ApplicationView->SetRedraw(TRUE); 703 m_ApplicationView->RedrawWindow(0, 0, RDW_INVALIDATE | RDW_ALLCHILDREN); // force the child window to repaint 704 UpdateStatusBarText(); 705 bUpdating = FALSE; 706 } 707 708 ATL::CWndClassInfo &CMainWindow::GetWndClassInfo() 709 { 710 DWORD csStyle = CS_VREDRAW | CS_HREDRAW; 711 static ATL::CWndClassInfo wc = 712 { 713 { 714 sizeof(WNDCLASSEX), 715 csStyle, 716 StartWindowProc, 717 0, 718 0, 719 NULL, 720 LoadIconW(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCEW(IDI_MAIN)), 721 LoadCursorW(NULL, IDC_ARROW), 722 (HBRUSH)(COLOR_BTNFACE + 1), 723 MAKEINTRESOURCEW(IDR_MAINMENU), 724 szWindowClass, 725 NULL 726 }, 727 NULL, NULL, IDC_ARROW, TRUE, 0, _T("") 728 }; 729 return wc; 730 } 731 732 HWND CMainWindow::Create() 733 { 734 ATL::CStringW szWindowName; 735 szWindowName.LoadStringW(IDS_APPTITLE); 736 737 RECT r = { 738 (SettingsInfo.bSaveWndPos ? SettingsInfo.Left : CW_USEDEFAULT), 739 (SettingsInfo.bSaveWndPos ? SettingsInfo.Top : CW_USEDEFAULT), 740 (SettingsInfo.bSaveWndPos ? SettingsInfo.Width : 680), 741 (SettingsInfo.bSaveWndPos ? SettingsInfo.Height : 450) 742 }; 743 r.right += r.left; 744 r.bottom += r.top; 745 746 return CWindowImpl::Create(NULL, r, szWindowName.GetString(), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE); 747 } 748 749 // this function is called when a item of application-view is checked/unchecked 750 // CallbackParam is the param passed to application-view when adding the item (the one getting focus now). 751 BOOL CMainWindow::ItemCheckStateChanged(BOOL bChecked, LPVOID CallbackParam) 752 { 753 if (!bUpdating) 754 { 755 if (bChecked) 756 { 757 if (!m_AvailableApps.AddSelected((CAvailableApplicationInfo *)CallbackParam)) 758 { 759 return FALSE; 760 } 761 } 762 else 763 { 764 if (!m_AvailableApps.RemoveSelected((CAvailableApplicationInfo *)CallbackParam)) 765 { 766 return FALSE; 767 } 768 } 769 770 UpdateStatusBarText(); 771 return TRUE; 772 } 773 else 774 { 775 return TRUE; 776 } 777 } 778 779 // this function is called when one or more application(s) should be installed install 780 // if Info is not zero, this app should be installed. otherwise those checked apps should be installed 781 BOOL CMainWindow::InstallApplication(CAvailableApplicationInfo *Info) 782 { 783 if (Info) 784 { 785 if (DownloadApplication(Info, FALSE)) 786 { 787 UpdateApplicationsList(-1); 788 return TRUE; 789 } 790 } 791 else 792 { 793 ATL::CSimpleArray<CAvailableApplicationInfo> AppsList; 794 795 // enum all selected apps 796 m_AvailableApps.Enum(ENUM_CAT_SELECTED, s_EnumSelectedAppForDownloadProc, (PVOID)&AppsList); 797 798 if (AppsList.GetSize()) 799 { 800 if (DownloadListOfApplications(AppsList, FALSE)) 801 { 802 m_AvailableApps.RemoveAllSelected(); 803 UpdateApplicationsList(-1); 804 return TRUE; 805 } 806 } 807 } 808 809 return FALSE; 810 } 811 812 BOOL CMainWindow::SearchTextChanged(ATL::CStringW &SearchText) 813 { 814 if (szSearchPattern == SearchText) 815 { 816 return FALSE; 817 } 818 819 szSearchPattern = SearchText; 820 821 DWORD dwDelay; 822 SystemParametersInfoW(SPI_GETMENUSHOWDELAY, 0, &dwDelay, 0); 823 SetTimer(SEARCH_TIMER_ID, dwDelay); 824 825 return TRUE; 826 } 827 828 void CMainWindow::HandleTabOrder(int direction) 829 { 830 ATL::CSimpleArray<HWND> TabOrderHwndList; 831 832 m_TreeView->AppendTabOrderWindow(direction, TabOrderHwndList); 833 m_ApplicationView->AppendTabOrderWindow(direction, TabOrderHwndList); 834 835 836 if (TabOrderHwndList.GetSize() == 0) 837 { 838 // in case the list is empty 839 return; 840 } 841 842 int FocusIndex; 843 844 if ((FocusIndex = TabOrderHwndList.Find(GetFocus())) == -1) 845 { 846 FocusIndex = 0; // focus the first window in the list 847 } 848 else 849 { 850 FocusIndex += direction; 851 FocusIndex += TabOrderHwndList.GetSize(); // FocusIndex might be negative. we don't want to mod a negative number 852 FocusIndex %= TabOrderHwndList.GetSize(); 853 } 854 855 ::SetFocus(TabOrderHwndList[FocusIndex]); 856 return; 857 } 858 // **** CMainWindow **** 859 860 861 862 VOID MainWindowLoop(INT nShowCmd) 863 { 864 HACCEL KeyBrd; 865 MSG Msg; 866 867 CMainWindow* wnd = new CMainWindow(); 868 if (!wnd) 869 return; 870 871 hMainWnd = wnd->Create(); 872 if (!hMainWnd) 873 return; 874 875 /* Maximize it if we must */ 876 wnd->ShowWindow((SettingsInfo.bSaveWndPos && SettingsInfo.Maximized) ? SW_MAXIMIZE : nShowCmd); 877 wnd->UpdateWindow(); 878 879 /* Load the menu hotkeys */ 880 KeyBrd = LoadAcceleratorsW(NULL, MAKEINTRESOURCEW(HOTKEYS)); 881 882 /* Message Loop */ 883 while (GetMessageW(&Msg, NULL, 0, 0)) 884 { 885 if (!TranslateAcceleratorW(hMainWnd, KeyBrd, &Msg)) 886 { 887 if (Msg.message == WM_CHAR && 888 Msg.wParam == VK_TAB) 889 { 890 // Move backwards if shift is held down 891 int direction = (GetKeyState(VK_SHIFT) & 0x8000) ? -1 : 1; 892 893 wnd->HandleTabOrder(direction); 894 continue; 895 } 896 897 TranslateMessage(&Msg); 898 DispatchMessageW(&Msg); 899 } 900 } 901 902 delete wnd; 903 } 904