1 /* 2 * Copyright 2015, Axel Dörfler, <axeld@pinc-software.de>. 3 * Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>. 4 * Copyright 2013, Rene Gollent, rene@gollent.com. 5 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. 6 * Copyright 2016-2020, Andrew Lindesay <apl@lindesay.co.nz>. 7 * Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>. 8 * All rights reserved. Distributed under the terms of the MIT License. 9 */ 10 11 12 #include "MainWindow.h" 13 14 #include <map> 15 #include <vector> 16 17 #include <stdio.h> 18 #include <Alert.h> 19 #include <Autolock.h> 20 #include <Application.h> 21 #include <Button.h> 22 #include <Catalog.h> 23 #include <CardLayout.h> 24 #include <LayoutBuilder.h> 25 #include <MenuBar.h> 26 #include <MenuItem.h> 27 #include <Messenger.h> 28 #include <Roster.h> 29 #include <Screen.h> 30 #include <ScrollView.h> 31 #include <StringList.h> 32 #include <StringView.h> 33 #include <TabView.h> 34 35 #include "AppUtils.h" 36 #include "AutoDeleter.h" 37 #include "AutoLocker.h" 38 #include "DecisionProvider.h" 39 #include "FeaturedPackagesView.h" 40 #include "FilterView.h" 41 #include "Logger.h" 42 #include "PackageInfoView.h" 43 #include "PackageListView.h" 44 #include "PackageManager.h" 45 #include "ProcessCoordinator.h" 46 #include "ProcessCoordinatorFactory.h" 47 #include "RatePackageWindow.h" 48 #include "support.h" 49 #include "ScreenshotWindow.h" 50 #include "ToLatestUserUsageConditionsWindow.h" 51 #include "UserLoginWindow.h" 52 #include "UserUsageConditionsWindow.h" 53 #include "WorkStatusView.h" 54 55 56 #undef B_TRANSLATION_CONTEXT 57 #define B_TRANSLATION_CONTEXT "MainWindow" 58 59 60 enum { 61 MSG_REFRESH_REPOS = 'mrrp', 62 MSG_MANAGE_REPOS = 'mmrp', 63 MSG_SOFTWARE_UPDATER = 'mswu', 64 MSG_LOG_IN = 'lgin', 65 MSG_AUTHORIZATION_CHANGED = 'athc', 66 MSG_CATEGORIES_LIST_CHANGED = 'clic', 67 MSG_PACKAGE_CHANGED = 'pchd', 68 MSG_WORK_STATUS_CHANGE = 'wsch', 69 MSG_WORK_STATUS_CLEAR = 'wscl', 70 71 MSG_CHANGE_PACKAGE_LIST_VIEW_MODE = 'cplm', 72 MSG_SHOW_AVAILABLE_PACKAGES = 'savl', 73 MSG_SHOW_INSTALLED_PACKAGES = 'sins', 74 MSG_SHOW_SOURCE_PACKAGES = 'ssrc', 75 MSG_SHOW_DEVELOP_PACKAGES = 'sdvl' 76 }; 77 78 #define KEY_ERROR_STATUS "errorStatus" 79 #define KEY_PACKAGE_LIST_VIEW_MODE "packageListViewMode" 80 81 #define TAB_PROMINENT_PACKAGES 0 82 #define TAB_ALL_PACKAGES 1 83 84 using namespace BPackageKit; 85 using namespace BPackageKit::BManager::BPrivate; 86 87 88 typedef std::map<BString, PackageInfoRef> PackageInfoMap; 89 90 91 struct RefreshWorkerParameters { 92 MainWindow* window; 93 bool forceRefresh; 94 95 RefreshWorkerParameters(MainWindow* window, bool forceRefresh) 96 : 97 window(window), 98 forceRefresh(forceRefresh) 99 { 100 } 101 }; 102 103 104 class MainWindowModelListener : public ModelListener { 105 public: 106 MainWindowModelListener(const BMessenger& messenger) 107 : 108 fMessenger(messenger) 109 { 110 } 111 112 virtual void AuthorizationChanged() 113 { 114 if (fMessenger.IsValid()) 115 fMessenger.SendMessage(MSG_AUTHORIZATION_CHANGED); 116 } 117 118 virtual void CategoryListChanged() 119 { 120 if (fMessenger.IsValid()) 121 fMessenger.SendMessage(MSG_CATEGORIES_LIST_CHANGED); 122 } 123 124 private: 125 BMessenger fMessenger; 126 }; 127 128 129 MainWindow::MainWindow(const BMessage& settings) 130 : 131 BWindow(BRect(50, 50, 650, 550), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"), 132 B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 133 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 134 fScreenshotWindow(NULL), 135 fUserMenu(NULL), 136 fLogInItem(NULL), 137 fLogOutItem(NULL), 138 fUsersUserUsageConditionsMenuItem(NULL), 139 fModelListener(new MainWindowModelListener(BMessenger(this)), true), 140 fCoordinator(NULL), 141 fSinglePackageMode(false) 142 { 143 if ((fCoordinatorRunningSem = create_sem(1, "ProcessCoordinatorSem")) < B_OK) 144 debugger("unable to create the process coordinator semaphore"); 145 146 BMenuBar* menuBar = new BMenuBar("Main Menu"); 147 _BuildMenu(menuBar); 148 149 BMenuBar* userMenuBar = new BMenuBar("User Menu"); 150 _BuildUserMenu(userMenuBar); 151 set_small_font(userMenuBar); 152 userMenuBar->SetExplicitMaxSize(BSize(B_SIZE_UNSET, 153 menuBar->MaxSize().height)); 154 155 fFilterView = new FilterView(); 156 fFeaturedPackagesView = new FeaturedPackagesView(); 157 fPackageListView = new PackageListView(fModel.Lock()); 158 fPackageInfoView = new PackageInfoView(fModel.Lock(), this); 159 160 fSplitView = new BSplitView(B_VERTICAL, 5.0f); 161 162 fWorkStatusView = new WorkStatusView("work status"); 163 fPackageListView->AttachWorkStatusView(fWorkStatusView); 164 165 fListTabs = new TabView(BMessenger(this), 166 BMessage(MSG_CHANGE_PACKAGE_LIST_VIEW_MODE), "list tabs"); 167 fListTabs->AddTab(fFeaturedPackagesView); 168 fListTabs->AddTab(fPackageListView); 169 170 BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f) 171 .AddGroup(B_HORIZONTAL, 0.0f) 172 .Add(menuBar, 1.0f) 173 .Add(userMenuBar, 0.0f) 174 .End() 175 .Add(fFilterView) 176 .AddSplit(fSplitView) 177 .AddGroup(B_VERTICAL) 178 .Add(fListTabs) 179 .SetInsets( 180 B_USE_DEFAULT_SPACING, 0.0f, 181 B_USE_DEFAULT_SPACING, 0.0f) 182 .End() 183 .Add(fPackageInfoView) 184 .End() 185 .Add(fWorkStatusView) 186 ; 187 188 fSplitView->SetCollapsible(0, false); 189 fSplitView->SetCollapsible(1, false); 190 191 fModel.AddListener(fModelListener); 192 193 BMessage columnSettings; 194 if (settings.FindMessage("column settings", &columnSettings) == B_OK) 195 fPackageListView->LoadState(&columnSettings); 196 197 _RestoreModelSettings(settings); 198 199 if (fModel.PackageListViewMode() == PROMINENT) 200 fListTabs->Select(TAB_PROMINENT_PACKAGES); 201 else 202 fListTabs->Select(TAB_ALL_PACKAGES); 203 204 _RestoreNickname(settings); 205 _UpdateAuthorization(); 206 _RestoreWindowFrame(settings); 207 208 // start worker threads 209 BPackageRoster().StartWatching(this, 210 B_WATCH_PACKAGE_INSTALLATION_LOCATIONS); 211 212 _InitWorkerThreads(); 213 _AdoptModel(); 214 _StartBulkLoad(); 215 } 216 217 218 MainWindow::MainWindow(const BMessage& settings, const PackageInfoRef& package) 219 : 220 BWindow(BRect(50, 50, 650, 350), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"), 221 B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 222 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 223 fFeaturedPackagesView(NULL), 224 fPackageListView(NULL), 225 fWorkStatusView(NULL), 226 fScreenshotWindow(NULL), 227 fUserMenu(NULL), 228 fLogInItem(NULL), 229 fLogOutItem(NULL), 230 fUsersUserUsageConditionsMenuItem(NULL), 231 fModelListener(new MainWindowModelListener(BMessenger(this)), true), 232 fCoordinator(NULL), 233 fSinglePackageMode(true) 234 { 235 if ((fCoordinatorRunningSem = create_sem(1, "ProcessCoordinatorSem")) < B_OK) 236 debugger("unable to create the process coordinator semaphore"); 237 238 fFilterView = new FilterView(); 239 fPackageInfoView = new PackageInfoView(fModel.Lock(), this); 240 fWorkStatusView = new WorkStatusView("work status"); 241 242 BLayoutBuilder::Group<>(this, B_VERTICAL) 243 .Add(fPackageInfoView) 244 .Add(fWorkStatusView) 245 .SetInsets(0, B_USE_WINDOW_INSETS, 0, 0) 246 ; 247 248 fModel.AddListener(fModelListener); 249 250 // Restore settings 251 _RestoreNickname(settings); 252 _UpdateAuthorization(); 253 _RestoreWindowFrame(settings); 254 255 fPackageInfoView->SetPackage(package); 256 257 _InitWorkerThreads(); 258 } 259 260 261 MainWindow::~MainWindow() 262 { 263 _SpinUntilProcessCoordinatorComplete(); 264 delete_sem(fCoordinatorRunningSem); 265 fCoordinatorRunningSem = 0; 266 267 BPackageRoster().StopWatching(this); 268 269 delete_sem(fPendingActionsSem); 270 if (fPendingActionsWorker >= 0) 271 wait_for_thread(fPendingActionsWorker, NULL); 272 273 if (fScreenshotWindow != NULL && fScreenshotWindow->Lock()) 274 fScreenshotWindow->Quit(); 275 } 276 277 278 bool 279 MainWindow::QuitRequested() 280 { 281 BMessage settings; 282 StoreSettings(settings); 283 284 BMessage message(MSG_MAIN_WINDOW_CLOSED); 285 message.AddMessage(KEY_WINDOW_SETTINGS, &settings); 286 287 be_app->PostMessage(&message); 288 289 _StopProcessCoordinators(); 290 291 return true; 292 } 293 294 295 void 296 MainWindow::MessageReceived(BMessage* message) 297 { 298 switch (message->what) { 299 case MSG_BULK_LOAD_DONE: 300 { 301 int64 errorStatus64; 302 if (message->FindInt64(KEY_ERROR_STATUS, &errorStatus64) == B_OK) 303 _BulkLoadCompleteReceived((status_t) errorStatus64); 304 else 305 printf("! expected [%s] value in message\n", KEY_ERROR_STATUS); 306 break; 307 } 308 case B_SIMPLE_DATA: 309 case B_REFS_RECEIVED: 310 // TODO: ? 311 break; 312 313 case B_PACKAGE_UPDATE: 314 // TODO: see ticket #15879 315 // work needs to be done here to selectively update package data in 316 // the running HaikuDepot application when there are changes on the 317 // system. There is now too much data to just load everything when 318 // there is a change. 319 //_StartBulkLoad(false); 320 break; 321 322 case MSG_REFRESH_REPOS: 323 _StartBulkLoad(true); 324 break; 325 326 case MSG_WORK_STATUS_CLEAR: 327 _HandleWorkStatusClear(); 328 break; 329 330 case MSG_WORK_STATUS_CHANGE: 331 _HandleWorkStatusChangeMessageReceived(message); 332 break; 333 334 case MSG_MANAGE_REPOS: 335 be_roster->Launch("application/x-vnd.Haiku-Repositories"); 336 break; 337 338 case MSG_SOFTWARE_UPDATER: 339 be_roster->Launch("application/x-vnd.haiku-softwareupdater"); 340 break; 341 342 case MSG_LOG_IN: 343 _OpenLoginWindow(BMessage()); 344 break; 345 346 case MSG_LOG_OUT: 347 fModel.SetNickname(""); 348 break; 349 350 case MSG_VIEW_LATEST_USER_USAGE_CONDITIONS: 351 _ViewUserUsageConditions(LATEST); 352 break; 353 354 case MSG_VIEW_USERS_USER_USAGE_CONDITIONS: 355 _ViewUserUsageConditions(USER); 356 break; 357 358 case MSG_AUTHORIZATION_CHANGED: 359 _StartUserVerify(); 360 _UpdateAuthorization(); 361 break; 362 363 case MSG_CATEGORIES_LIST_CHANGED: 364 fFilterView->AdoptModel(fModel); 365 break; 366 367 case MSG_CHANGE_PACKAGE_LIST_VIEW_MODE: 368 _HandleChangePackageListViewMode(); 369 break; 370 371 case MSG_SHOW_AVAILABLE_PACKAGES: 372 { 373 BAutolock locker(fModel.Lock()); 374 fModel.SetShowAvailablePackages( 375 !fModel.ShowAvailablePackages()); 376 } 377 _AdoptModel(); 378 break; 379 380 case MSG_SHOW_INSTALLED_PACKAGES: 381 { 382 BAutolock locker(fModel.Lock()); 383 fModel.SetShowInstalledPackages( 384 !fModel.ShowInstalledPackages()); 385 } 386 _AdoptModel(); 387 break; 388 389 case MSG_SHOW_SOURCE_PACKAGES: 390 { 391 BAutolock locker(fModel.Lock()); 392 fModel.SetShowSourcePackages(!fModel.ShowSourcePackages()); 393 } 394 _AdoptModel(); 395 break; 396 397 case MSG_SHOW_DEVELOP_PACKAGES: 398 { 399 BAutolock locker(fModel.Lock()); 400 fModel.SetShowDevelopPackages(!fModel.ShowDevelopPackages()); 401 } 402 _AdoptModel(); 403 break; 404 405 // this may be triggered by, for example, a user rating being added 406 // or having been altered. 407 case MSG_SERVER_DATA_CHANGED: 408 { 409 BString name; 410 if (message->FindString("name", &name) == B_OK) { 411 BAutolock locker(fModel.Lock()); 412 if (fPackageInfoView->Package()->Name() == name) { 413 _PopulatePackageAsync(true); 414 } else { 415 if (Logger::IsDebugEnabled()) { 416 printf("pkg [%s] is updated on the server, but is " 417 "not selected so will not be updated.\n", 418 name.String()); 419 } 420 } 421 } 422 break; 423 } 424 425 case MSG_PACKAGE_SELECTED: 426 { 427 BString name; 428 if (message->FindString("name", &name) == B_OK) { 429 PackageInfoRef package; 430 { 431 BAutolock locker(fModel.Lock()); 432 package = fModel.PackageForName(name); 433 } 434 if (package.Get() == NULL) 435 debugger("unable to find the named package"); 436 else 437 _AdoptPackage(package); 438 } else { 439 _ClearPackage(); 440 } 441 break; 442 } 443 444 case MSG_CATEGORY_SELECTED: 445 { 446 BString code; 447 if (message->FindString("code", &code) != B_OK) 448 code = ""; 449 { 450 BAutolock locker(fModel.Lock()); 451 fModel.SetCategory(code); 452 } 453 _AdoptModel(); 454 break; 455 } 456 457 case MSG_DEPOT_SELECTED: 458 { 459 BString name; 460 if (message->FindString("name", &name) != B_OK) 461 name = ""; 462 { 463 BAutolock locker(fModel.Lock()); 464 fModel.SetDepot(name); 465 } 466 _AdoptModel(); 467 _UpdateAvailableRepositories(); 468 break; 469 } 470 471 case MSG_SEARCH_TERMS_MODIFIED: 472 { 473 // TODO: Do this with a delay! 474 BString searchTerms; 475 if (message->FindString("search terms", &searchTerms) != B_OK) 476 searchTerms = ""; 477 { 478 BAutolock locker(fModel.Lock()); 479 fModel.SetSearchTerms(searchTerms); 480 } 481 _AdoptModel(); 482 break; 483 } 484 485 case MSG_PACKAGE_CHANGED: 486 { 487 PackageInfo* info; 488 if (message->FindPointer("package", (void**)&info) == B_OK) { 489 PackageInfoRef ref(info, true); 490 uint32 changes; 491 if (message->FindUInt32("changes", &changes) != B_OK) 492 changes = 0; 493 if ((changes & PKG_CHANGED_STATE) != 0) { 494 BAutolock locker(fModel.Lock()); 495 fModel.SetPackageState(ref, ref->State()); 496 } 497 _AddRemovePackageFromLists(ref); 498 if ((changes & PKG_CHANGED_STATE) != 0 499 && fCoordinator.Get() == NULL) { 500 fWorkStatusView->PackageStatusChanged(ref); 501 } 502 } 503 break; 504 } 505 506 case MSG_RATE_PACKAGE: 507 _RatePackage(); 508 break; 509 510 case MSG_SHOW_SCREENSHOT: 511 _ShowScreenshot(); 512 break; 513 514 case MSG_PACKAGE_WORKER_BUSY: 515 { 516 BString reason; 517 status_t status = message->FindString("reason", &reason); 518 if (status != B_OK) 519 break; 520 fWorkStatusView->SetBusy(reason); 521 break; 522 } 523 524 case MSG_PACKAGE_WORKER_IDLE: 525 fWorkStatusView->SetIdle(); 526 break; 527 528 case MSG_USER_USAGE_CONDITIONS_NOT_LATEST: 529 { 530 BMessage userDetailMsg; 531 if (message->FindMessage("userDetail", &userDetailMsg) != B_OK) { 532 debugger("expected the [userDetail] data to be carried in the " 533 "message."); 534 } 535 UserDetail userDetail(&userDetailMsg); 536 _HandleUserUsageConditionsNotLatest(userDetail); 537 break; 538 } 539 540 default: 541 BWindow::MessageReceived(message); 542 break; 543 } 544 } 545 546 547 static const char* 548 main_window_package_list_view_mode_str(package_list_view_mode mode) 549 { 550 if (mode == PROMINENT) 551 return "PROMINENT"; 552 return "ALL"; 553 } 554 555 556 static package_list_view_mode 557 main_window_str_to_package_list_view_mode(const BString& str) 558 { 559 if (str == "PROMINENT") 560 return PROMINENT; 561 return ALL; 562 } 563 564 565 void 566 MainWindow::StoreSettings(BMessage& settings) const 567 { 568 settings.AddRect(_WindowFrameName(), Frame()); 569 if (!fSinglePackageMode) { 570 settings.AddRect("window frame", Frame()); 571 572 BMessage columnSettings; 573 if (fPackageListView != NULL) 574 fPackageListView->SaveState(&columnSettings); 575 576 settings.AddMessage("column settings", &columnSettings); 577 578 settings.AddString(KEY_PACKAGE_LIST_VIEW_MODE, 579 main_window_package_list_view_mode_str( 580 fModel.PackageListViewMode())); 581 settings.AddBool("show available packages", 582 fModel.ShowAvailablePackages()); 583 settings.AddBool("show installed packages", 584 fModel.ShowInstalledPackages()); 585 settings.AddBool("show develop packages", fModel.ShowDevelopPackages()); 586 settings.AddBool("show source packages", fModel.ShowSourcePackages()); 587 } 588 589 settings.AddString("username", fModel.Nickname()); 590 } 591 592 593 void 594 MainWindow::PackageChanged(const PackageInfoEvent& event) 595 { 596 uint32 watchedChanges = PKG_CHANGED_STATE | PKG_CHANGED_PROMINENCE; 597 if ((event.Changes() & watchedChanges) != 0) { 598 PackageInfoRef ref(event.Package()); 599 BMessage message(MSG_PACKAGE_CHANGED); 600 message.AddPointer("package", ref.Get()); 601 message.AddUInt32("changes", event.Changes()); 602 ref.Detach(); 603 // reference needs to be released by MessageReceived(); 604 PostMessage(&message); 605 } 606 } 607 608 609 status_t 610 MainWindow::SchedulePackageActions(PackageActionList& list) 611 { 612 AutoLocker<BLocker> lock(&fPendingActionsLock); 613 for (int32 i = 0; i < list.CountItems(); i++) { 614 if (!fPendingActions.Add(list.ItemAtFast(i))) 615 return B_NO_MEMORY; 616 } 617 618 return release_sem_etc(fPendingActionsSem, list.CountItems(), 0); 619 } 620 621 622 Model* 623 MainWindow::GetModel() 624 { 625 return &fModel; 626 } 627 628 629 void 630 MainWindow::_BuildMenu(BMenuBar* menuBar) 631 { 632 BMenu* menu = new BMenu(B_TRANSLATE("Tools")); 633 fRefreshRepositoriesItem = new BMenuItem( 634 B_TRANSLATE("Refresh repositories"), new BMessage(MSG_REFRESH_REPOS)); 635 menu->AddItem(fRefreshRepositoriesItem); 636 menu->AddItem(new BMenuItem(B_TRANSLATE("Manage repositories" 637 B_UTF8_ELLIPSIS), new BMessage(MSG_MANAGE_REPOS))); 638 menu->AddItem(new BMenuItem(B_TRANSLATE("Check for updates" 639 B_UTF8_ELLIPSIS), new BMessage(MSG_SOFTWARE_UPDATER))); 640 641 menuBar->AddItem(menu); 642 643 fRepositoryMenu = new BMenu(B_TRANSLATE("Repositories")); 644 menuBar->AddItem(fRepositoryMenu); 645 646 menu = new BMenu(B_TRANSLATE("Show")); 647 648 fShowAvailablePackagesItem = new BMenuItem( 649 B_TRANSLATE("Available packages"), 650 new BMessage(MSG_SHOW_AVAILABLE_PACKAGES)); 651 menu->AddItem(fShowAvailablePackagesItem); 652 653 fShowInstalledPackagesItem = new BMenuItem( 654 B_TRANSLATE("Installed packages"), 655 new BMessage(MSG_SHOW_INSTALLED_PACKAGES)); 656 menu->AddItem(fShowInstalledPackagesItem); 657 658 menu->AddSeparatorItem(); 659 660 fShowDevelopPackagesItem = new BMenuItem( 661 B_TRANSLATE("Develop packages"), 662 new BMessage(MSG_SHOW_DEVELOP_PACKAGES)); 663 menu->AddItem(fShowDevelopPackagesItem); 664 665 fShowSourcePackagesItem = new BMenuItem( 666 B_TRANSLATE("Source packages"), 667 new BMessage(MSG_SHOW_SOURCE_PACKAGES)); 668 menu->AddItem(fShowSourcePackagesItem); 669 670 menuBar->AddItem(menu); 671 } 672 673 674 void 675 MainWindow::_BuildUserMenu(BMenuBar* menuBar) 676 { 677 fUserMenu = new BMenu(B_TRANSLATE("Not logged in")); 678 679 fLogInItem = new BMenuItem(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS), 680 new BMessage(MSG_LOG_IN)); 681 fUserMenu->AddItem(fLogInItem); 682 683 fLogOutItem = new BMenuItem(B_TRANSLATE("Log out"), 684 new BMessage(MSG_LOG_OUT)); 685 fUserMenu->AddItem(fLogOutItem); 686 687 BMenuItem *latestUserUsageConditionsMenuItem = 688 new BMenuItem(B_TRANSLATE("View latest usage conditions" 689 B_UTF8_ELLIPSIS), 690 new BMessage(MSG_VIEW_LATEST_USER_USAGE_CONDITIONS)); 691 fUserMenu->AddItem(latestUserUsageConditionsMenuItem); 692 693 fUsersUserUsageConditionsMenuItem = 694 new BMenuItem(B_TRANSLATE("View agreed usage conditions" 695 B_UTF8_ELLIPSIS), 696 new BMessage(MSG_VIEW_USERS_USER_USAGE_CONDITIONS)); 697 fUserMenu->AddItem(fUsersUserUsageConditionsMenuItem); 698 699 menuBar->AddItem(fUserMenu); 700 } 701 702 703 void 704 MainWindow::_RestoreNickname(const BMessage& settings) 705 { 706 BString nickname; 707 if (settings.FindString("username", &nickname) == B_OK 708 && nickname.Length() > 0) { 709 fModel.SetNickname(nickname); 710 } 711 } 712 713 714 const char* 715 MainWindow::_WindowFrameName() const 716 { 717 if (fSinglePackageMode) 718 return "small window frame"; 719 720 return "window frame"; 721 } 722 723 724 void 725 MainWindow::_RestoreWindowFrame(const BMessage& settings) 726 { 727 BRect frame = Frame(); 728 729 BRect windowFrame; 730 bool fromSettings = false; 731 if (settings.FindRect(_WindowFrameName(), &windowFrame) == B_OK) { 732 frame = windowFrame; 733 fromSettings = true; 734 } else if (!fSinglePackageMode) { 735 // Resize to occupy a certain screen size 736 BRect screenFrame = BScreen(this).Frame(); 737 float width = frame.Width(); 738 float height = frame.Height(); 739 if (width < screenFrame.Width() * .666f 740 && height < screenFrame.Height() * .666f) { 741 frame.bottom = frame.top + screenFrame.Height() * .666f; 742 frame.right = frame.left 743 + std::min(screenFrame.Width() * .666f, height * 7 / 5); 744 } 745 } 746 747 MoveTo(frame.LeftTop()); 748 ResizeTo(frame.Width(), frame.Height()); 749 750 if (fromSettings) 751 MoveOnScreen(); 752 else 753 CenterOnScreen(); 754 } 755 756 757 void 758 MainWindow::_RestoreModelSettings(const BMessage& settings) 759 { 760 BString packageListViewMode; 761 if (settings.FindString(KEY_PACKAGE_LIST_VIEW_MODE, 762 &packageListViewMode) == B_OK) { 763 fModel.SetPackageListViewMode( 764 main_window_str_to_package_list_view_mode(packageListViewMode)); 765 } 766 767 bool showOption; 768 if (settings.FindBool("show available packages", &showOption) == B_OK) 769 fModel.SetShowAvailablePackages(showOption); 770 if (settings.FindBool("show installed packages", &showOption) == B_OK) 771 fModel.SetShowInstalledPackages(showOption); 772 if (settings.FindBool("show develop packages", &showOption) == B_OK) 773 fModel.SetShowDevelopPackages(showOption); 774 if (settings.FindBool("show source packages", &showOption) == B_OK) 775 fModel.SetShowSourcePackages(showOption); 776 } 777 778 779 void 780 MainWindow::_InitWorkerThreads() 781 { 782 fPendingActionsSem = create_sem(0, "PendingPackageActions"); 783 if (fPendingActionsSem >= 0) { 784 fPendingActionsWorker = spawn_thread(&_PackageActionWorker, 785 "Planet Express", B_NORMAL_PRIORITY, this); 786 if (fPendingActionsWorker >= 0) 787 resume_thread(fPendingActionsWorker); 788 } else 789 fPendingActionsWorker = -1; 790 791 fPackageToPopulateSem = create_sem(0, "PopulatePackage"); 792 if (fPackageToPopulateSem >= 0) { 793 fPopulatePackageWorker = spawn_thread(&_PopulatePackageWorker, 794 "Package Populator", B_NORMAL_PRIORITY, this); 795 if (fPopulatePackageWorker >= 0) 796 resume_thread(fPopulatePackageWorker); 797 } else 798 fPopulatePackageWorker = -1; 799 } 800 801 802 void 803 MainWindow::_AdoptModelControls() 804 { 805 if (fSinglePackageMode) 806 return; 807 808 BAutolock locker(fModel.Lock()); 809 fShowAvailablePackagesItem->SetMarked(fModel.ShowAvailablePackages()); 810 fShowInstalledPackagesItem->SetMarked(fModel.ShowInstalledPackages()); 811 fShowSourcePackagesItem->SetMarked(fModel.ShowSourcePackages()); 812 fShowDevelopPackagesItem->SetMarked(fModel.ShowDevelopPackages()); 813 814 if (fModel.PackageListViewMode() == PROMINENT) 815 fListTabs->Select(TAB_PROMINENT_PACKAGES); 816 else 817 fListTabs->Select(TAB_ALL_PACKAGES); 818 819 fFilterView->AdoptModel(fModel); 820 } 821 822 823 void 824 MainWindow::_AdoptModel() 825 { 826 if (Logger::IsTraceEnabled()) 827 printf("adopting model to main window ui\n"); 828 829 if (fSinglePackageMode) 830 return; 831 832 fModel.Lock()->Lock(); 833 const DepotList& depots = fModel.Depots(); 834 fModel.Lock()->Unlock(); 835 836 for (int32 d = 0; d < depots.CountItems(); d++) { 837 const DepotInfo& depot = depots.ItemAtFast(d); 838 const PackageList& packages = depot.Packages(); 839 for (int32 p = 0; p < packages.CountItems(); p++) 840 _AddRemovePackageFromLists(packages.ItemAtFast(p)); 841 } 842 843 _AdoptModelControls(); 844 } 845 846 847 void 848 MainWindow::_AddRemovePackageFromLists(const PackageInfoRef& package) 849 { 850 bool matches; 851 852 { 853 AutoLocker<BLocker> modelLocker(fModel.Lock()); 854 matches = fModel.MatchesFilter(package); 855 } 856 857 if (matches) { 858 if (package->IsProminent()) 859 fFeaturedPackagesView->AddPackage(package); 860 fPackageListView->AddPackage(package); 861 } else { 862 fFeaturedPackagesView->RemovePackage(package); 863 fPackageListView->RemovePackage(package); 864 } 865 } 866 867 868 void 869 MainWindow::_AdoptPackage(const PackageInfoRef& package) 870 { 871 { 872 BAutolock locker(fModel.Lock()); 873 fPackageInfoView->SetPackage(package); 874 875 if (fFeaturedPackagesView != NULL) 876 fFeaturedPackagesView->SelectPackage(package); 877 if (fPackageListView != NULL) 878 fPackageListView->SelectPackage(package); 879 } 880 881 _PopulatePackageAsync(false); 882 } 883 884 885 void 886 MainWindow::_ClearPackage() 887 { 888 fPackageInfoView->Clear(); 889 } 890 891 892 void 893 MainWindow::_StartBulkLoad(bool force) 894 { 895 if (fFeaturedPackagesView != NULL) 896 fFeaturedPackagesView->Clear(); 897 if (fPackageListView != NULL) 898 fPackageListView->Clear(); 899 fPackageInfoView->Clear(); 900 901 fRefreshRepositoriesItem->SetEnabled(false); 902 ProcessCoordinator* bulkLoadCoordinator = 903 ProcessCoordinatorFactory::CreateBulkLoadCoordinator( 904 this, 905 // PackageInfoListener 906 this, 907 // ProcessCoordinatorListener 908 &fModel, force); 909 _AddProcessCoordinator(bulkLoadCoordinator); 910 } 911 912 913 void 914 MainWindow::_BulkLoadCompleteReceived(status_t errorStatus) 915 { 916 if (errorStatus != B_OK) { 917 AppUtils::NotifySimpleError( 918 B_TRANSLATE("Package update error"), 919 B_TRANSLATE("While updating package data, a problem has arisen " 920 "that may cause data to be outdated or missing from the " 921 "application's display. Additional details regarding this " 922 "problem may be able to be obtained from the application " 923 "logs." 924 ALERT_MSG_LOGS_USER_GUIDE)); 925 } 926 927 fRefreshRepositoriesItem->SetEnabled(true); 928 _AdoptModel(); 929 _UpdateAvailableRepositories(); 930 931 // if after loading everything in, it transpires that there are no 932 // featured packages then the featured packages should be disabled 933 // and the user should be switched to the "all packages" view so 934 // that they are not presented with a blank window! 935 936 bool hasProminentPackages = fModel.HasAnyProminentPackages(); 937 fListTabs->TabAt(TAB_PROMINENT_PACKAGES)->SetEnabled(hasProminentPackages); 938 if (!hasProminentPackages 939 && fListTabs->Selection() == TAB_PROMINENT_PACKAGES) { 940 fModel.SetPackageListViewMode(ALL); 941 fListTabs->Select(TAB_ALL_PACKAGES); 942 } 943 } 944 945 946 void 947 MainWindow::_NotifyWorkStatusClear() 948 { 949 BMessage message(MSG_WORK_STATUS_CLEAR); 950 this->PostMessage(&message, this); 951 } 952 953 954 void 955 MainWindow::_HandleWorkStatusClear() 956 { 957 fWorkStatusView->SetText(""); 958 fWorkStatusView->SetIdle(); 959 } 960 961 962 /*! Sends off a message to the Window so that it can change the status view 963 on the front-end in the UI thread. 964 */ 965 966 void 967 MainWindow::_NotifyWorkStatusChange(const BString& text, float progress) 968 { 969 BMessage message(MSG_WORK_STATUS_CHANGE); 970 971 if (!text.IsEmpty()) 972 message.AddString(KEY_WORK_STATUS_TEXT, text); 973 message.AddFloat(KEY_WORK_STATUS_PROGRESS, progress); 974 975 this->PostMessage(&message, this); 976 } 977 978 979 void 980 MainWindow::_HandleWorkStatusChangeMessageReceived(const BMessage* message) 981 { 982 if (fWorkStatusView == NULL) 983 return; 984 985 BString text; 986 float progress; 987 988 if (message->FindString(KEY_WORK_STATUS_TEXT, &text) == B_OK) 989 fWorkStatusView->SetText(text); 990 991 if (message->FindFloat(KEY_WORK_STATUS_PROGRESS, &progress) == B_OK) 992 fWorkStatusView->SetProgress(progress); 993 } 994 995 996 status_t 997 MainWindow::_PackageActionWorker(void* arg) 998 { 999 MainWindow* window = reinterpret_cast<MainWindow*>(arg); 1000 1001 while (acquire_sem(window->fPendingActionsSem) == B_OK) { 1002 PackageActionRef ref; 1003 { 1004 AutoLocker<BLocker> lock(&window->fPendingActionsLock); 1005 ref = window->fPendingActions.ItemAt(0); 1006 if (ref.Get() == NULL) 1007 break; 1008 window->fPendingActions.Remove(0); 1009 } 1010 1011 BMessenger messenger(window); 1012 BMessage busyMessage(MSG_PACKAGE_WORKER_BUSY); 1013 BString text(ref->Label()); 1014 text << B_UTF8_ELLIPSIS; 1015 busyMessage.AddString("reason", text); 1016 1017 messenger.SendMessage(&busyMessage); 1018 ref->Perform(); 1019 messenger.SendMessage(MSG_PACKAGE_WORKER_IDLE); 1020 } 1021 1022 return 0; 1023 } 1024 1025 1026 /*! This method will cause the package to have its data refreshed from 1027 the server application. The refresh happens in the background; this method 1028 is asynchronous. 1029 */ 1030 1031 void 1032 MainWindow::_PopulatePackageAsync(bool forcePopulate) 1033 { 1034 // Trigger asynchronous package population from the web-app 1035 { 1036 AutoLocker<BLocker> lock(&fPackageToPopulateLock); 1037 fPackageToPopulate = fPackageInfoView->Package(); 1038 fForcePopulatePackage = forcePopulate; 1039 } 1040 release_sem_etc(fPackageToPopulateSem, 1, 0); 1041 1042 if (Logger::IsDebugEnabled()) { 1043 printf("pkg [%s] will be updated from the server.\n", 1044 fPackageToPopulate->Name().String()); 1045 } 1046 } 1047 1048 1049 /*! This method will run in the background. The thread will block until there 1050 is a package to be updated. When the thread unblocks, it will update the 1051 package with information from the server. 1052 */ 1053 1054 status_t 1055 MainWindow::_PopulatePackageWorker(void* arg) 1056 { 1057 MainWindow* window = reinterpret_cast<MainWindow*>(arg); 1058 1059 while (acquire_sem(window->fPackageToPopulateSem) == B_OK) { 1060 PackageInfoRef package; 1061 bool force; 1062 { 1063 AutoLocker<BLocker> lock(&window->fPackageToPopulateLock); 1064 package = window->fPackageToPopulate; 1065 force = window->fForcePopulatePackage; 1066 } 1067 1068 if (package.Get() != NULL) { 1069 uint32 populateFlags = Model::POPULATE_USER_RATINGS 1070 | Model::POPULATE_SCREEN_SHOTS 1071 | Model::POPULATE_CHANGELOG; 1072 1073 if (force) 1074 populateFlags |= Model::POPULATE_FORCE; 1075 1076 window->fModel.PopulatePackage(package, populateFlags); 1077 1078 if (Logger::IsDebugEnabled()) { 1079 printf("populating package [%s]\n", 1080 package->Name().String()); 1081 } 1082 } 1083 } 1084 1085 return 0; 1086 } 1087 1088 1089 void 1090 MainWindow::_OpenLoginWindow(const BMessage& onSuccessMessage) 1091 { 1092 UserLoginWindow* window = new UserLoginWindow(this, 1093 BRect(0, 0, 500, 400), fModel); 1094 1095 if (onSuccessMessage.what != 0) 1096 window->SetOnSuccessMessage(BMessenger(this), onSuccessMessage); 1097 1098 window->Show(); 1099 } 1100 1101 1102 void 1103 MainWindow::_StartUserVerify() 1104 { 1105 if (!fModel.Nickname().IsEmpty()) { 1106 _AddProcessCoordinator( 1107 ProcessCoordinatorFactory::CreateUserDetailVerifierCoordinator( 1108 this, 1109 // UserDetailVerifierListener 1110 this, 1111 // ProcessCoordinatorListener 1112 &fModel) ); 1113 } 1114 } 1115 1116 1117 void 1118 MainWindow::_UpdateAuthorization() 1119 { 1120 BString nickname(fModel.Nickname()); 1121 bool hasUser = !nickname.IsEmpty(); 1122 1123 if (fLogOutItem != NULL) 1124 fLogOutItem->SetEnabled(hasUser); 1125 if (fUsersUserUsageConditionsMenuItem != NULL) 1126 fUsersUserUsageConditionsMenuItem->SetEnabled(hasUser); 1127 if (fLogInItem != NULL) { 1128 if (hasUser) 1129 fLogInItem->SetLabel(B_TRANSLATE("Switch account" B_UTF8_ELLIPSIS)); 1130 else 1131 fLogInItem->SetLabel(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS)); 1132 } 1133 1134 if (fUserMenu != NULL) { 1135 BString label; 1136 if (hasUser) { 1137 label = B_TRANSLATE("Logged in as %User%"); 1138 label.ReplaceAll("%User%", nickname); 1139 } else { 1140 label = B_TRANSLATE("Not logged in"); 1141 } 1142 fUserMenu->Superitem()->SetLabel(label); 1143 } 1144 } 1145 1146 1147 void 1148 MainWindow::_UpdateAvailableRepositories() 1149 { 1150 fRepositoryMenu->RemoveItems(0, fRepositoryMenu->CountItems(), true); 1151 1152 fRepositoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All repositories"), 1153 new BMessage(MSG_DEPOT_SELECTED))); 1154 1155 fRepositoryMenu->AddItem(new BSeparatorItem()); 1156 1157 bool foundSelectedDepot = false; 1158 const DepotList& depots = fModel.Depots(); 1159 for (int i = 0; i < depots.CountItems(); i++) { 1160 const DepotInfo& depot = depots.ItemAtFast(i); 1161 1162 if (depot.Name().Length() != 0) { 1163 BMessage* message = new BMessage(MSG_DEPOT_SELECTED); 1164 message->AddString("name", depot.Name()); 1165 BMenuItem* item = new BMenuItem(depot.Name(), message); 1166 fRepositoryMenu->AddItem(item); 1167 1168 if (depot.Name() == fModel.Depot()) { 1169 item->SetMarked(true); 1170 foundSelectedDepot = true; 1171 } 1172 } 1173 } 1174 1175 if (!foundSelectedDepot) 1176 fRepositoryMenu->ItemAt(0)->SetMarked(true); 1177 } 1178 1179 1180 bool 1181 MainWindow::_SelectedPackageHasWebAppRepositoryCode() 1182 { 1183 const PackageInfoRef& package = fPackageInfoView->Package(); 1184 const BString depotName = package->DepotName(); 1185 1186 if (depotName.IsEmpty()) { 1187 if (Logger::IsDebugEnabled()) { 1188 printf("the package [%s] has no depot name\n", 1189 package->Name().String()); 1190 } 1191 } else { 1192 const DepotInfo* depot = fModel.DepotForName(depotName); 1193 1194 if (depot == NULL) { 1195 printf("the depot [%s] was not able to be found\n", 1196 depotName.String()); 1197 } else { 1198 BString repositoryCode = depot->WebAppRepositoryCode(); 1199 1200 if (repositoryCode.IsEmpty()) { 1201 printf("the depot [%s] has no web app repository code\n", 1202 depotName.String()); 1203 } else { 1204 return true; 1205 } 1206 } 1207 } 1208 1209 return false; 1210 } 1211 1212 1213 void 1214 MainWindow::_RatePackage() 1215 { 1216 if (!_SelectedPackageHasWebAppRepositoryCode()) { 1217 BAlert* alert = new(std::nothrow) BAlert( 1218 B_TRANSLATE("Rating not possible"), 1219 B_TRANSLATE("This package doesn't seem to be on the HaikuDepot " 1220 "Server, so it's not possible to create a new rating " 1221 "or edit an existing rating."), 1222 B_TRANSLATE("OK")); 1223 alert->Go(); 1224 return; 1225 } 1226 1227 if (fModel.Nickname().IsEmpty()) { 1228 BAlert* alert = new(std::nothrow) BAlert( 1229 B_TRANSLATE("Not logged in"), 1230 B_TRANSLATE("You need to be logged into an account before you " 1231 "can rate packages."), 1232 B_TRANSLATE("Cancel"), 1233 B_TRANSLATE("Login or Create account")); 1234 1235 if (alert == NULL) 1236 return; 1237 1238 int32 choice = alert->Go(); 1239 if (choice == 1) 1240 _OpenLoginWindow(BMessage(MSG_RATE_PACKAGE)); 1241 return; 1242 } 1243 1244 // TODO: Allow only one RatePackageWindow 1245 // TODO: Mechanism for remembering the window frame 1246 RatePackageWindow* window = new RatePackageWindow(this, 1247 BRect(0, 0, 500, 400), fModel); 1248 window->SetPackage(fPackageInfoView->Package()); 1249 window->Show(); 1250 } 1251 1252 1253 void 1254 MainWindow::_ShowScreenshot() 1255 { 1256 // TODO: Mechanism for remembering the window frame 1257 if (fScreenshotWindow == NULL) 1258 fScreenshotWindow = new ScreenshotWindow(this, BRect(0, 0, 500, 400)); 1259 1260 if (fScreenshotWindow->LockWithTimeout(1000) != B_OK) 1261 return; 1262 1263 fScreenshotWindow->SetPackage(fPackageInfoView->Package()); 1264 1265 if (fScreenshotWindow->IsHidden()) 1266 fScreenshotWindow->Show(); 1267 else 1268 fScreenshotWindow->Activate(); 1269 1270 fScreenshotWindow->Unlock(); 1271 } 1272 1273 1274 void 1275 MainWindow::_ViewUserUsageConditions( 1276 UserUsageConditionsSelectionMode mode) 1277 { 1278 UserUsageConditionsWindow* window = new UserUsageConditionsWindow( 1279 fModel, mode); 1280 window->Show(); 1281 } 1282 1283 1284 void 1285 MainWindow::UserCredentialsFailed() 1286 { 1287 BString message = B_TRANSLATE("The password previously " 1288 "supplied for the user [%Nickname%] is not currently " 1289 "valid. The user will be logged-out of this application " 1290 "and you should login again with your updated password."); 1291 message.ReplaceAll("%Nickname%", fModel.Nickname()); 1292 1293 AppUtils::NotifySimpleError(B_TRANSLATE("Login issue"), 1294 message); 1295 1296 { 1297 AutoLocker<BLocker> locker(fModel.Lock()); 1298 fModel.SetNickname(""); 1299 } 1300 } 1301 1302 1303 /*! \brief This method is invoked from the UserDetailVerifierProcess on a 1304 background thread. For this reason it lodges a message into itself 1305 which can then be handled on the main thread. 1306 */ 1307 1308 void 1309 MainWindow::UserUsageConditionsNotLatest(const UserDetail& userDetail) 1310 { 1311 BMessage message(MSG_USER_USAGE_CONDITIONS_NOT_LATEST); 1312 BMessage detailsMessage; 1313 if (userDetail.Archive(&detailsMessage, true) != B_OK 1314 || message.AddMessage("userDetail", &detailsMessage) != B_OK) { 1315 printf("!! unable to archive the user detail into a message\n"); 1316 } 1317 else 1318 BMessenger(this).SendMessage(&message); 1319 } 1320 1321 1322 void 1323 MainWindow::_HandleUserUsageConditionsNotLatest( 1324 const UserDetail& userDetail) 1325 { 1326 ToLatestUserUsageConditionsWindow* window = 1327 new ToLatestUserUsageConditionsWindow(this, fModel, userDetail); 1328 window->Show(); 1329 } 1330 1331 1332 void 1333 MainWindow::_AddProcessCoordinator(ProcessCoordinator* item) 1334 { 1335 AutoLocker<BLocker> lock(&fCoordinatorLock); 1336 1337 if (fCoordinator.Get() == NULL) { 1338 if (acquire_sem(fCoordinatorRunningSem) != B_OK) 1339 debugger("unable to acquire the process coordinator sem"); 1340 if (Logger::IsInfoEnabled()) { 1341 printf("adding and starting a process coordinator [%s]\n", 1342 item->Name().String()); 1343 } 1344 fCoordinator = BReference<ProcessCoordinator>(item); 1345 fCoordinator->Start(); 1346 } 1347 else { 1348 if (Logger::IsInfoEnabled()) { 1349 printf("adding process coordinator [%s] to the queue\n", 1350 item->Name().String()); 1351 } 1352 fCoordinatorQueue.push(item); 1353 } 1354 } 1355 1356 1357 void 1358 MainWindow::_SpinUntilProcessCoordinatorComplete() 1359 { 1360 while (true) { 1361 if (acquire_sem(fCoordinatorRunningSem) != B_OK) 1362 debugger("unable to acquire the process coordinator sem"); 1363 if (release_sem(fCoordinatorRunningSem) != B_OK) 1364 debugger("unable to release the process coordinator sem"); 1365 { 1366 AutoLocker<BLocker> lock(&fCoordinatorLock); 1367 if (fCoordinator.Get() == NULL) 1368 return; 1369 } 1370 } 1371 } 1372 1373 1374 void 1375 MainWindow::_StopProcessCoordinators() 1376 { 1377 if (Logger::IsInfoEnabled()) 1378 printf("will stop all process coordinators\n"); 1379 1380 { 1381 AutoLocker<BLocker> lock(&fCoordinatorLock); 1382 1383 while (!fCoordinatorQueue.empty()) { 1384 BReference<ProcessCoordinator> processCoordinator = fCoordinatorQueue.front(); 1385 if (Logger::IsInfoEnabled()) { 1386 printf("will drop queued process coordinator [%s]\n", 1387 processCoordinator->Name().String()); 1388 } 1389 fCoordinatorQueue.pop(); 1390 } 1391 1392 if (fCoordinator.Get() != NULL) { 1393 fCoordinator->Stop(); 1394 } 1395 } 1396 1397 if (Logger::IsInfoEnabled()) 1398 printf("will wait until the process coordinator has stopped\n"); 1399 1400 _SpinUntilProcessCoordinatorComplete(); 1401 1402 if (Logger::IsInfoEnabled()) 1403 printf("did stop all process coordinators\n"); 1404 } 1405 1406 1407 /*! This method is called when there is some change in the bulk load process 1408 or other process coordinator. 1409 A change may mean that a new process has started / stopped etc... or it 1410 may mean that the entire coordinator has finished. 1411 */ 1412 1413 void 1414 MainWindow::CoordinatorChanged(ProcessCoordinatorState& coordinatorState) 1415 { 1416 AutoLocker<BLocker> lock(&fCoordinatorLock); 1417 1418 if (fCoordinator.Get() == coordinatorState.Coordinator()) { 1419 if (!coordinatorState.IsRunning()) { 1420 if (release_sem(fCoordinatorRunningSem) != B_OK) 1421 debugger("unable to release the process coordinator sem"); 1422 if (Logger::IsInfoEnabled()) { 1423 printf("process coordinator [%s] did complete\n", 1424 fCoordinator->Name().String()); 1425 } 1426 // complete the last one that just finished 1427 BMessage* message = fCoordinator->Message(); 1428 1429 if (message != NULL) { 1430 BMessenger messenger(this); 1431 message->AddInt64(KEY_ERROR_STATUS, 1432 (int64) fCoordinator->ErrorStatus()); 1433 messenger.SendMessage(message); 1434 } 1435 1436 fCoordinator = BReference<ProcessCoordinator>(NULL); 1437 // will delete the old process coordinator if it is not used 1438 // elsewhere. 1439 1440 // now schedule the next one. 1441 if (!fCoordinatorQueue.empty()) { 1442 if (acquire_sem(fCoordinatorRunningSem) != B_OK) 1443 debugger("unable to acquire the process coordinator sem"); 1444 fCoordinator = fCoordinatorQueue.front(); 1445 if (Logger::IsInfoEnabled()) { 1446 printf("starting next process coordinator [%s]\n", 1447 fCoordinator->Name().String()); 1448 } 1449 fCoordinatorQueue.pop(); 1450 fCoordinator->Start(); 1451 } 1452 else { 1453 _NotifyWorkStatusClear(); 1454 } 1455 } 1456 else { 1457 _NotifyWorkStatusChange(coordinatorState.Message(), 1458 coordinatorState.Progress()); 1459 // show the progress to the user. 1460 } 1461 } else { 1462 if (Logger::IsInfoEnabled()) 1463 printf("! unknown process coordinator changed\n"); 1464 } 1465 } 1466 1467 1468 static package_list_view_mode 1469 main_window_tab_to_package_list_view_mode(int32 tab) 1470 { 1471 if (tab == TAB_PROMINENT_PACKAGES) 1472 return PROMINENT; 1473 return ALL; 1474 } 1475 1476 1477 void 1478 MainWindow::_HandleChangePackageListViewMode() 1479 { 1480 package_list_view_mode tabMode = main_window_tab_to_package_list_view_mode( 1481 fListTabs->Selection()); 1482 package_list_view_mode modelMode = fModel.PackageListViewMode(); 1483 1484 if (tabMode != modelMode) { 1485 BAutolock locker(fModel.Lock()); 1486 fModel.SetPackageListViewMode(tabMode); 1487 } 1488 }