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