104c9d578SStephan Aßmus /* 2f7c2983eSAxel Dörfler * Copyright 2015, Axel Dörfler, <axeld@pinc-software.de>. 304c9d578SStephan Aßmus * Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>. 404c9d578SStephan Aßmus * Copyright 2013, Rene Gollent, rene@gollent.com. 504c9d578SStephan Aßmus * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. 6ebb1a01cSAndrew Lindesay * Copyright 2016, Andrew Lindesay <apl@lindesay.co.nz>. 7125d42d9SJulian Harnath * Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>. 804c9d578SStephan Aßmus * All rights reserved. Distributed under the terms of the MIT License. 904c9d578SStephan Aßmus */ 1004c9d578SStephan Aßmus 11f7c2983eSAxel Dörfler 1204c9d578SStephan Aßmus #include "MainWindow.h" 1304c9d578SStephan Aßmus 1404c9d578SStephan Aßmus #include <map> 1504c9d578SStephan Aßmus 1604c9d578SStephan Aßmus #include <stdio.h> 1704c9d578SStephan Aßmus 1804c9d578SStephan Aßmus #include <Alert.h> 1904c9d578SStephan Aßmus #include <Autolock.h> 2004c9d578SStephan Aßmus #include <Application.h> 2104c9d578SStephan Aßmus #include <Button.h> 2204c9d578SStephan Aßmus #include <Catalog.h> 234b930ccaSStephan Aßmus #include <CardLayout.h> 2404c9d578SStephan Aßmus #include <LayoutBuilder.h> 2504c9d578SStephan Aßmus #include <MenuBar.h> 2604c9d578SStephan Aßmus #include <MenuItem.h> 2704c9d578SStephan Aßmus #include <Messenger.h> 285bf2b6ebSBrian Hill #include <Roster.h> 29f7c2983eSAxel Dörfler #include <Screen.h> 3004c9d578SStephan Aßmus #include <ScrollView.h> 3104c9d578SStephan Aßmus #include <StringList.h> 320a9c9029SStephan Aßmus #include <StringView.h> 3304c9d578SStephan Aßmus #include <TabView.h> 3404c9d578SStephan Aßmus 3504c9d578SStephan Aßmus #include <package/Context.h> 3604c9d578SStephan Aßmus #include <package/manager/Exceptions.h> 3704c9d578SStephan Aßmus #include <package/manager/RepositoryBuilder.h> 3804c9d578SStephan Aßmus #include <package/RefreshRepositoryRequest.h> 3904c9d578SStephan Aßmus #include <package/PackageRoster.h> 4004c9d578SStephan Aßmus #include "package/RepositoryCache.h" 4104c9d578SStephan Aßmus #include <package/solver/SolverPackage.h> 4204c9d578SStephan Aßmus #include <package/solver/SolverProblem.h> 4304c9d578SStephan Aßmus #include <package/solver/SolverProblemSolution.h> 4404c9d578SStephan Aßmus #include <package/solver/SolverRepository.h> 4504c9d578SStephan Aßmus #include <package/solver/SolverResult.h> 4604c9d578SStephan Aßmus 4704c9d578SStephan Aßmus #include "AutoDeleter.h" 4804c9d578SStephan Aßmus #include "AutoLocker.h" 4904c9d578SStephan Aßmus #include "DecisionProvider.h" 504b930ccaSStephan Aßmus #include "FeaturedPackagesView.h" 5104c9d578SStephan Aßmus #include "FilterView.h" 5204c9d578SStephan Aßmus #include "JobStateListener.h" 5304c9d578SStephan Aßmus #include "PackageInfoView.h" 5404c9d578SStephan Aßmus #include "PackageListView.h" 5504c9d578SStephan Aßmus #include "PackageManager.h" 5604c9d578SStephan Aßmus #include "RatePackageWindow.h" 57e0a26dceSStephan Aßmus #include "support.h" 58d5ef985eSStephan Aßmus #include "ScreenshotWindow.h" 5904c9d578SStephan Aßmus #include "UserLoginWindow.h" 60125d42d9SJulian Harnath #include "WorkStatusView.h" 6104c9d578SStephan Aßmus 6204c9d578SStephan Aßmus 6304c9d578SStephan Aßmus #undef B_TRANSLATION_CONTEXT 6404c9d578SStephan Aßmus #define B_TRANSLATION_CONTEXT "MainWindow" 6504c9d578SStephan Aßmus 6604c9d578SStephan Aßmus 6704c9d578SStephan Aßmus enum { 6804c9d578SStephan Aßmus MSG_MODEL_WORKER_DONE = 'mmwd', 695bf2b6ebSBrian Hill MSG_REFRESH_REPOS = 'mrrp', 705bf2b6ebSBrian Hill MSG_MANAGE_REPOS = 'mmrp', 7104c9d578SStephan Aßmus MSG_LOG_IN = 'lgin', 728f03a0f9SStephan Aßmus MSG_LOG_OUT = 'lgot', 738f03a0f9SStephan Aßmus MSG_AUTHORIZATION_CHANGED = 'athc', 74da651104SStephan Aßmus MSG_PACKAGE_CHANGED = 'pchd', 75fdec4227SStephan Aßmus 764fade61fSStephan Aßmus MSG_SHOW_FEATURED_PACKAGES = 'sofp', 77fdec4227SStephan Aßmus MSG_SHOW_AVAILABLE_PACKAGES = 'savl', 78fdec4227SStephan Aßmus MSG_SHOW_INSTALLED_PACKAGES = 'sins', 7904c9d578SStephan Aßmus MSG_SHOW_SOURCE_PACKAGES = 'ssrc', 8004c9d578SStephan Aßmus MSG_SHOW_DEVELOP_PACKAGES = 'sdvl' 8104c9d578SStephan Aßmus }; 8204c9d578SStephan Aßmus 8304c9d578SStephan Aßmus 8404c9d578SStephan Aßmus using namespace BPackageKit; 8504c9d578SStephan Aßmus using namespace BPackageKit::BManager::BPrivate; 8604c9d578SStephan Aßmus 8704c9d578SStephan Aßmus 8804c9d578SStephan Aßmus typedef std::map<BString, PackageInfoRef> PackageInfoMap; 8904c9d578SStephan Aßmus typedef std::map<BString, DepotInfo> DepotInfoMap; 9004c9d578SStephan Aßmus 9104c9d578SStephan Aßmus 9204c9d578SStephan Aßmus struct RefreshWorkerParameters { 9304c9d578SStephan Aßmus MainWindow* window; 9404c9d578SStephan Aßmus bool forceRefresh; 9504c9d578SStephan Aßmus 9604c9d578SStephan Aßmus RefreshWorkerParameters(MainWindow* window, bool forceRefresh) 9704c9d578SStephan Aßmus : 9804c9d578SStephan Aßmus window(window), 9904c9d578SStephan Aßmus forceRefresh(forceRefresh) 10004c9d578SStephan Aßmus { 10104c9d578SStephan Aßmus } 10204c9d578SStephan Aßmus }; 10304c9d578SStephan Aßmus 10404c9d578SStephan Aßmus 1058f03a0f9SStephan Aßmus class MessageModelListener : public ModelListener { 1068f03a0f9SStephan Aßmus public: 1078f03a0f9SStephan Aßmus MessageModelListener(const BMessenger& messenger) 1088f03a0f9SStephan Aßmus : 1098f03a0f9SStephan Aßmus fMessenger(messenger) 1108f03a0f9SStephan Aßmus { 1118f03a0f9SStephan Aßmus } 1128f03a0f9SStephan Aßmus 1138f03a0f9SStephan Aßmus virtual void AuthorizationChanged() 1148f03a0f9SStephan Aßmus { 1158f03a0f9SStephan Aßmus if (fMessenger.IsValid()) 1168f03a0f9SStephan Aßmus fMessenger.SendMessage(MSG_AUTHORIZATION_CHANGED); 1178f03a0f9SStephan Aßmus } 1188f03a0f9SStephan Aßmus 1198f03a0f9SStephan Aßmus private: 1208f03a0f9SStephan Aßmus BMessenger fMessenger; 1218f03a0f9SStephan Aßmus }; 1228f03a0f9SStephan Aßmus 1238f03a0f9SStephan Aßmus 124f7c2983eSAxel Dörfler MainWindow::MainWindow(const BMessage& settings) 12504c9d578SStephan Aßmus : 126f7c2983eSAxel Dörfler BWindow(BRect(50, 50, 650, 550), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"), 12704c9d578SStephan Aßmus B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 12804c9d578SStephan Aßmus B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 129d5ef985eSStephan Aßmus fScreenshotWindow(NULL), 130e0a26dceSStephan Aßmus fUserMenu(NULL), 131e0a26dceSStephan Aßmus fLogInItem(NULL), 132e0a26dceSStephan Aßmus fLogOutItem(NULL), 1338f03a0f9SStephan Aßmus fModelListener(new MessageModelListener(BMessenger(this)), true), 13404c9d578SStephan Aßmus fTerminating(false), 1356d519fd1SStephan Aßmus fSinglePackageMode(false), 13604c9d578SStephan Aßmus fModelWorker(B_BAD_THREAD_ID) 13704c9d578SStephan Aßmus { 13804c9d578SStephan Aßmus BMenuBar* menuBar = new BMenuBar(B_TRANSLATE("Main Menu")); 13904c9d578SStephan Aßmus _BuildMenu(menuBar); 14004c9d578SStephan Aßmus 141e0a26dceSStephan Aßmus BMenuBar* userMenuBar = new BMenuBar(B_TRANSLATE("User Menu")); 142e0a26dceSStephan Aßmus _BuildUserMenu(userMenuBar); 143e0a26dceSStephan Aßmus set_small_font(userMenuBar); 144e0a26dceSStephan Aßmus userMenuBar->SetExplicitMaxSize(BSize(B_SIZE_UNSET, 145e0a26dceSStephan Aßmus menuBar->MaxSize().height)); 146e0a26dceSStephan Aßmus 14704c9d578SStephan Aßmus fFilterView = new FilterView(); 1484b930ccaSStephan Aßmus fFeaturedPackagesView = new FeaturedPackagesView(); 14904c9d578SStephan Aßmus fPackageListView = new PackageListView(fModel.Lock()); 15004c9d578SStephan Aßmus fPackageInfoView = new PackageInfoView(fModel.Lock(), this); 15104c9d578SStephan Aßmus 15204c9d578SStephan Aßmus fSplitView = new BSplitView(B_VERTICAL, 5.0f); 15304c9d578SStephan Aßmus 1540a9c9029SStephan Aßmus BGroupView* featuredPackagesGroup = new BGroupView(B_VERTICAL); 1550a9c9029SStephan Aßmus BStringView* featuredPackagesTitle = new BStringView( 1560a9c9029SStephan Aßmus "featured packages title", B_TRANSLATE("Featured packages")); 1570a9c9029SStephan Aßmus BFont font(be_bold_font); 1580a9c9029SStephan Aßmus font.SetSize(font.Size() * 1.3f); 1590a9c9029SStephan Aßmus featuredPackagesTitle->SetFont(&font); 1600a9c9029SStephan Aßmus featuredPackagesGroup->SetExplicitMaxSize( 1610a9c9029SStephan Aßmus BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 1620a9c9029SStephan Aßmus BLayoutBuilder::Group<>(featuredPackagesGroup) 1630a9c9029SStephan Aßmus .Add(featuredPackagesTitle) 1640a9c9029SStephan Aßmus .Add(fFeaturedPackagesView) 1650a9c9029SStephan Aßmus ; 1664b930ccaSStephan Aßmus 167125d42d9SJulian Harnath fWorkStatusView = new WorkStatusView("work status"); 168125d42d9SJulian Harnath fPackageListView->AttachWorkStatusView(fWorkStatusView); 169125d42d9SJulian Harnath 1700a9c9029SStephan Aßmus BView* listArea = new BView("list area", 0); 1714b930ccaSStephan Aßmus fListLayout = new BCardLayout(); 1724b930ccaSStephan Aßmus listArea->SetLayout(fListLayout); 1730a9c9029SStephan Aßmus listArea->AddChild(featuredPackagesGroup); 1744b930ccaSStephan Aßmus listArea->AddChild(fPackageListView); 1754b930ccaSStephan Aßmus 17604c9d578SStephan Aßmus BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f) 177e0a26dceSStephan Aßmus .AddGroup(B_HORIZONTAL, 0.0f) 178e0a26dceSStephan Aßmus .Add(menuBar, 1.0f) 179e0a26dceSStephan Aßmus .Add(userMenuBar, 0.0f) 180e0a26dceSStephan Aßmus .End() 18104c9d578SStephan Aßmus .Add(fFilterView) 18204c9d578SStephan Aßmus .AddSplit(fSplitView) 18304c9d578SStephan Aßmus .AddGroup(B_VERTICAL) 1844b930ccaSStephan Aßmus .Add(listArea) 18504c9d578SStephan Aßmus .SetInsets( 18604c9d578SStephan Aßmus B_USE_DEFAULT_SPACING, 0.0f, 18704c9d578SStephan Aßmus B_USE_DEFAULT_SPACING, 0.0f) 18804c9d578SStephan Aßmus .End() 18904c9d578SStephan Aßmus .Add(fPackageInfoView) 19004c9d578SStephan Aßmus .End() 191125d42d9SJulian Harnath .Add(fWorkStatusView) 19204c9d578SStephan Aßmus ; 19304c9d578SStephan Aßmus 19404c9d578SStephan Aßmus fSplitView->SetCollapsible(0, false); 19504c9d578SStephan Aßmus fSplitView->SetCollapsible(1, false); 19604c9d578SStephan Aßmus 1978f03a0f9SStephan Aßmus fModel.AddListener(fModelListener); 1988f03a0f9SStephan Aßmus 19904c9d578SStephan Aßmus // Restore settings 20004c9d578SStephan Aßmus BMessage columnSettings; 20104c9d578SStephan Aßmus if (settings.FindMessage("column settings", &columnSettings) == B_OK) 20204c9d578SStephan Aßmus fPackageListView->LoadState(&columnSettings); 20304c9d578SStephan Aßmus 20404c9d578SStephan Aßmus bool showOption; 2052997e05bSStephan Aßmus if (settings.FindBool("show featured packages", &showOption) == B_OK) 2062997e05bSStephan Aßmus fModel.SetShowFeaturedPackages(showOption); 2072997e05bSStephan Aßmus if (settings.FindBool("show available packages", &showOption) == B_OK) 2082997e05bSStephan Aßmus fModel.SetShowAvailablePackages(showOption); 2092997e05bSStephan Aßmus if (settings.FindBool("show installed packages", &showOption) == B_OK) 2102997e05bSStephan Aßmus fModel.SetShowInstalledPackages(showOption); 21104c9d578SStephan Aßmus if (settings.FindBool("show develop packages", &showOption) == B_OK) 21204c9d578SStephan Aßmus fModel.SetShowDevelopPackages(showOption); 21304c9d578SStephan Aßmus if (settings.FindBool("show source packages", &showOption) == B_OK) 21404c9d578SStephan Aßmus fModel.SetShowSourcePackages(showOption); 21504c9d578SStephan Aßmus 2162997e05bSStephan Aßmus if (fModel.ShowFeaturedPackages()) 2172997e05bSStephan Aßmus fListLayout->SetVisibleItem((int32)0); 2182997e05bSStephan Aßmus else 2192997e05bSStephan Aßmus fListLayout->SetVisibleItem(1); 2202997e05bSStephan Aßmus 221f7c2983eSAxel Dörfler _RestoreUserName(settings); 222f7c2983eSAxel Dörfler _RestoreWindowFrame(settings); 223f7c2983eSAxel Dörfler 224*72fff6d3SJulian Harnath atomic_set(&fPackagesToShowListID, 0); 225*72fff6d3SJulian Harnath 2268f03a0f9SStephan Aßmus // start worker threads 22704c9d578SStephan Aßmus BPackageRoster().StartWatching(this, 22804c9d578SStephan Aßmus B_WATCH_PACKAGE_INSTALLATION_LOCATIONS); 22904c9d578SStephan Aßmus 23004c9d578SStephan Aßmus _StartRefreshWorker(); 23104c9d578SStephan Aßmus 23263975654SStephan Aßmus _InitWorkerThreads(); 23304c9d578SStephan Aßmus } 23404c9d578SStephan Aßmus 23504c9d578SStephan Aßmus 236f7c2983eSAxel Dörfler MainWindow::MainWindow(const BMessage& settings, const PackageInfoRef& package) 2376d519fd1SStephan Aßmus : 238f7c2983eSAxel Dörfler BWindow(BRect(50, 50, 650, 350), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"), 2396d519fd1SStephan Aßmus B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 2406d519fd1SStephan Aßmus B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 241d5ef985eSStephan Aßmus fScreenshotWindow(NULL), 242e0a26dceSStephan Aßmus fUserMenu(NULL), 243e0a26dceSStephan Aßmus fLogInItem(NULL), 2446d519fd1SStephan Aßmus fLogOutItem(NULL), 2456d519fd1SStephan Aßmus fModelListener(new MessageModelListener(BMessenger(this)), true), 2466d519fd1SStephan Aßmus fTerminating(false), 2476d519fd1SStephan Aßmus fSinglePackageMode(true), 2486d519fd1SStephan Aßmus fModelWorker(B_BAD_THREAD_ID) 2496d519fd1SStephan Aßmus { 2506d519fd1SStephan Aßmus fFilterView = new FilterView(); 2516d519fd1SStephan Aßmus fPackageListView = new PackageListView(fModel.Lock()); 2526d519fd1SStephan Aßmus fPackageInfoView = new PackageInfoView(fModel.Lock(), this); 2536d519fd1SStephan Aßmus 2546d519fd1SStephan Aßmus BLayoutBuilder::Group<>(this, B_VERTICAL) 2556d519fd1SStephan Aßmus .Add(fPackageInfoView) 2566d519fd1SStephan Aßmus .SetInsets(0, B_USE_WINDOW_INSETS, 0, 0) 2576d519fd1SStephan Aßmus ; 2586d519fd1SStephan Aßmus 2596d519fd1SStephan Aßmus fModel.AddListener(fModelListener); 2606d519fd1SStephan Aßmus 2616d519fd1SStephan Aßmus // Restore settings 262f7c2983eSAxel Dörfler _RestoreUserName(settings); 263f7c2983eSAxel Dörfler _RestoreWindowFrame(settings); 2646d519fd1SStephan Aßmus 2656d519fd1SStephan Aßmus fPackageInfoView->SetPackage(package); 26663975654SStephan Aßmus 26763975654SStephan Aßmus _InitWorkerThreads(); 2686d519fd1SStephan Aßmus } 2696d519fd1SStephan Aßmus 2706d519fd1SStephan Aßmus 27104c9d578SStephan Aßmus MainWindow::~MainWindow() 27204c9d578SStephan Aßmus { 27304c9d578SStephan Aßmus BPackageRoster().StopWatching(this); 27404c9d578SStephan Aßmus 27504c9d578SStephan Aßmus fTerminating = true; 27605bffa62SStephan Aßmus if (fModelWorker >= 0) 27704c9d578SStephan Aßmus wait_for_thread(fModelWorker, NULL); 27804c9d578SStephan Aßmus 27904c9d578SStephan Aßmus delete_sem(fPendingActionsSem); 28005bffa62SStephan Aßmus if (fPendingActionsWorker >= 0) 28104c9d578SStephan Aßmus wait_for_thread(fPendingActionsWorker, NULL); 28204c9d578SStephan Aßmus 28304c9d578SStephan Aßmus delete_sem(fPackageToPopulateSem); 28405bffa62SStephan Aßmus if (fPopulatePackageWorker >= 0) 28504c9d578SStephan Aßmus wait_for_thread(fPopulatePackageWorker, NULL); 286d5ef985eSStephan Aßmus 287*72fff6d3SJulian Harnath delete_sem(fNewPackagesToShowSem); 288*72fff6d3SJulian Harnath delete_sem(fShowPackagesAcknowledgeSem); 289*72fff6d3SJulian Harnath if (fShowPackagesWorker >= 0) 290*72fff6d3SJulian Harnath wait_for_thread(fShowPackagesWorker, NULL); 291*72fff6d3SJulian Harnath 292d5ef985eSStephan Aßmus if (fScreenshotWindow != NULL && fScreenshotWindow->Lock()) 293d5ef985eSStephan Aßmus fScreenshotWindow->Quit(); 29404c9d578SStephan Aßmus } 29504c9d578SStephan Aßmus 29604c9d578SStephan Aßmus 29704c9d578SStephan Aßmus bool 29804c9d578SStephan Aßmus MainWindow::QuitRequested() 29904c9d578SStephan Aßmus { 30004c9d578SStephan Aßmus BMessage settings; 30104c9d578SStephan Aßmus StoreSettings(settings); 30204c9d578SStephan Aßmus 30304c9d578SStephan Aßmus BMessage message(MSG_MAIN_WINDOW_CLOSED); 30404c9d578SStephan Aßmus message.AddMessage("window settings", &settings); 30504c9d578SStephan Aßmus 30604c9d578SStephan Aßmus be_app->PostMessage(&message); 30704c9d578SStephan Aßmus 30804c9d578SStephan Aßmus return true; 30904c9d578SStephan Aßmus } 31004c9d578SStephan Aßmus 31104c9d578SStephan Aßmus 31204c9d578SStephan Aßmus void 31304c9d578SStephan Aßmus MainWindow::MessageReceived(BMessage* message) 31404c9d578SStephan Aßmus { 31504c9d578SStephan Aßmus switch (message->what) { 31604c9d578SStephan Aßmus case MSG_MODEL_WORKER_DONE: 31704c9d578SStephan Aßmus { 31804c9d578SStephan Aßmus fModelWorker = B_BAD_THREAD_ID; 31904c9d578SStephan Aßmus _AdoptModel(); 32004c9d578SStephan Aßmus fFilterView->AdoptModel(fModel); 321125d42d9SJulian Harnath fWorkStatusView->SetIdle(); 32204c9d578SStephan Aßmus break; 32304c9d578SStephan Aßmus } 32404c9d578SStephan Aßmus case B_SIMPLE_DATA: 32504c9d578SStephan Aßmus case B_REFS_RECEIVED: 32604c9d578SStephan Aßmus // TODO: ? 32704c9d578SStephan Aßmus break; 32804c9d578SStephan Aßmus 32904c9d578SStephan Aßmus case B_PACKAGE_UPDATE: 33004c9d578SStephan Aßmus // TODO: We should do a more selective update depending on the 33104c9d578SStephan Aßmus // "event", "location", and "change count" fields! 33204c9d578SStephan Aßmus _StartRefreshWorker(false); 33304c9d578SStephan Aßmus break; 33404c9d578SStephan Aßmus 3355bf2b6ebSBrian Hill case MSG_REFRESH_REPOS: 33604c9d578SStephan Aßmus _StartRefreshWorker(true); 33704c9d578SStephan Aßmus break; 33804c9d578SStephan Aßmus 3395bf2b6ebSBrian Hill case MSG_MANAGE_REPOS: 3405bf2b6ebSBrian Hill be_roster->Launch("application/x-vnd.Haiku-Repositories"); 3415bf2b6ebSBrian Hill break; 3425bf2b6ebSBrian Hill 34304c9d578SStephan Aßmus case MSG_LOG_IN: 3441bbda92dSStephan Aßmus _OpenLoginWindow(BMessage()); 34504c9d578SStephan Aßmus break; 34604c9d578SStephan Aßmus 3478f03a0f9SStephan Aßmus case MSG_LOG_OUT: 3488f03a0f9SStephan Aßmus fModel.SetUsername(""); 3498f03a0f9SStephan Aßmus break; 3508f03a0f9SStephan Aßmus 3518f03a0f9SStephan Aßmus case MSG_AUTHORIZATION_CHANGED: 3528f03a0f9SStephan Aßmus _UpdateAuthorization(); 3538f03a0f9SStephan Aßmus break; 3548f03a0f9SStephan Aßmus 3554fade61fSStephan Aßmus case MSG_SHOW_FEATURED_PACKAGES: 3564fade61fSStephan Aßmus { 3574fade61fSStephan Aßmus BAutolock locker(fModel.Lock()); 3584fade61fSStephan Aßmus fModel.SetShowFeaturedPackages( 3594fade61fSStephan Aßmus !fModel.ShowFeaturedPackages()); 3604fade61fSStephan Aßmus } 3614fade61fSStephan Aßmus _AdoptModel(); 3624fade61fSStephan Aßmus break; 3634fade61fSStephan Aßmus 364fdec4227SStephan Aßmus case MSG_SHOW_AVAILABLE_PACKAGES: 365fdec4227SStephan Aßmus { 366fdec4227SStephan Aßmus BAutolock locker(fModel.Lock()); 367fdec4227SStephan Aßmus fModel.SetShowAvailablePackages( 368fdec4227SStephan Aßmus !fModel.ShowAvailablePackages()); 369fdec4227SStephan Aßmus } 370fdec4227SStephan Aßmus _AdoptModel(); 371fdec4227SStephan Aßmus break; 372fdec4227SStephan Aßmus 373fdec4227SStephan Aßmus case MSG_SHOW_INSTALLED_PACKAGES: 374fdec4227SStephan Aßmus { 375fdec4227SStephan Aßmus BAutolock locker(fModel.Lock()); 376fdec4227SStephan Aßmus fModel.SetShowInstalledPackages( 377fdec4227SStephan Aßmus !fModel.ShowInstalledPackages()); 378fdec4227SStephan Aßmus } 379fdec4227SStephan Aßmus _AdoptModel(); 380fdec4227SStephan Aßmus break; 381fdec4227SStephan Aßmus 38204c9d578SStephan Aßmus case MSG_SHOW_SOURCE_PACKAGES: 38304c9d578SStephan Aßmus { 38404c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 38504c9d578SStephan Aßmus fModel.SetShowSourcePackages(!fModel.ShowSourcePackages()); 38604c9d578SStephan Aßmus } 38704c9d578SStephan Aßmus _AdoptModel(); 38804c9d578SStephan Aßmus break; 38904c9d578SStephan Aßmus 39004c9d578SStephan Aßmus case MSG_SHOW_DEVELOP_PACKAGES: 39104c9d578SStephan Aßmus { 39204c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 39304c9d578SStephan Aßmus fModel.SetShowDevelopPackages(!fModel.ShowDevelopPackages()); 39404c9d578SStephan Aßmus } 39504c9d578SStephan Aßmus _AdoptModel(); 39604c9d578SStephan Aßmus break; 39704c9d578SStephan Aßmus 39804c9d578SStephan Aßmus case MSG_PACKAGE_SELECTED: 39904c9d578SStephan Aßmus { 40072992391SStephan Aßmus BString name; 40172992391SStephan Aßmus if (message->FindString("name", &name) == B_OK) { 40275ba9dbfSStephan Aßmus BAutolock locker(fModel.Lock()); 40304c9d578SStephan Aßmus int count = fVisiblePackages.CountItems(); 40404c9d578SStephan Aßmus for (int i = 0; i < count; i++) { 40504c9d578SStephan Aßmus const PackageInfoRef& package 40604c9d578SStephan Aßmus = fVisiblePackages.ItemAtFast(i); 40772992391SStephan Aßmus if (package.Get() != NULL && package->Name() == name) { 40875ba9dbfSStephan Aßmus locker.Unlock(); 40904c9d578SStephan Aßmus _AdoptPackage(package); 41004c9d578SStephan Aßmus break; 41104c9d578SStephan Aßmus } 41204c9d578SStephan Aßmus } 41304c9d578SStephan Aßmus } else { 41404c9d578SStephan Aßmus _ClearPackage(); 41504c9d578SStephan Aßmus } 41604c9d578SStephan Aßmus break; 41704c9d578SStephan Aßmus } 41804c9d578SStephan Aßmus 41904c9d578SStephan Aßmus case MSG_CATEGORY_SELECTED: 42004c9d578SStephan Aßmus { 42104c9d578SStephan Aßmus BString name; 42204c9d578SStephan Aßmus if (message->FindString("name", &name) != B_OK) 42304c9d578SStephan Aßmus name = ""; 42404c9d578SStephan Aßmus { 42504c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 42604c9d578SStephan Aßmus fModel.SetCategory(name); 42704c9d578SStephan Aßmus } 42804c9d578SStephan Aßmus _AdoptModel(); 42904c9d578SStephan Aßmus break; 43004c9d578SStephan Aßmus } 43104c9d578SStephan Aßmus 43204c9d578SStephan Aßmus case MSG_DEPOT_SELECTED: 43304c9d578SStephan Aßmus { 43404c9d578SStephan Aßmus BString name; 43504c9d578SStephan Aßmus if (message->FindString("name", &name) != B_OK) 43604c9d578SStephan Aßmus name = ""; 43704c9d578SStephan Aßmus { 43804c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 43904c9d578SStephan Aßmus fModel.SetDepot(name); 44004c9d578SStephan Aßmus } 44104c9d578SStephan Aßmus _AdoptModel(); 44204c9d578SStephan Aßmus break; 44304c9d578SStephan Aßmus } 44404c9d578SStephan Aßmus 44504c9d578SStephan Aßmus case MSG_SEARCH_TERMS_MODIFIED: 44604c9d578SStephan Aßmus { 44704c9d578SStephan Aßmus // TODO: Do this with a delay! 44804c9d578SStephan Aßmus BString searchTerms; 44904c9d578SStephan Aßmus if (message->FindString("search terms", &searchTerms) != B_OK) 45004c9d578SStephan Aßmus searchTerms = ""; 45104c9d578SStephan Aßmus { 45204c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 45304c9d578SStephan Aßmus fModel.SetSearchTerms(searchTerms); 45404c9d578SStephan Aßmus } 45504c9d578SStephan Aßmus _AdoptModel(); 45604c9d578SStephan Aßmus break; 45704c9d578SStephan Aßmus } 45804c9d578SStephan Aßmus 459da651104SStephan Aßmus case MSG_PACKAGE_CHANGED: 46004c9d578SStephan Aßmus { 46104c9d578SStephan Aßmus PackageInfo* info; 46204c9d578SStephan Aßmus if (message->FindPointer("package", (void**)&info) == B_OK) { 46304c9d578SStephan Aßmus PackageInfoRef ref(info, true); 464da651104SStephan Aßmus uint32 changes; 465da651104SStephan Aßmus if (message->FindUInt32("changes", &changes) != B_OK) 466da651104SStephan Aßmus changes = 0; 467da651104SStephan Aßmus if ((changes & PKG_CHANGED_STATE) != 0) { 46804c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 46904c9d578SStephan Aßmus fModel.SetPackageState(ref, ref->State()); 47004c9d578SStephan Aßmus } 47157e51fffSStephan Aßmus 47257e51fffSStephan Aßmus // Asynchronous updates to the package information 47357e51fffSStephan Aßmus // can mean that the package needs to be added or 47457e51fffSStephan Aßmus // removed to/from the visible packages when the current 47557e51fffSStephan Aßmus // filter parameters are re-evaluated on this package. 47657e51fffSStephan Aßmus bool wasVisible = fVisiblePackages.Contains(ref); 47757e51fffSStephan Aßmus bool isVisible; 47857e51fffSStephan Aßmus { 479da651104SStephan Aßmus BAutolock locker(fModel.Lock()); 4800c6df5d5SStephan Aßmus // The package didn't get a chance yet to be in the 4810c6df5d5SStephan Aßmus // visible package list 48257e51fffSStephan Aßmus PackageList visiblePackages = fModel.CreatePackageList(); 48357e51fffSStephan Aßmus isVisible = visiblePackages.Contains(ref); 48457e51fffSStephan Aßmus 48557e51fffSStephan Aßmus // Transfer this single package, otherwise we miss 48657e51fffSStephan Aßmus // other packages if they appear or disappear along 48757e51fffSStephan Aßmus // with this one before receive a notification for 48857e51fffSStephan Aßmus // them. 48957e51fffSStephan Aßmus if (isVisible) { 49057e51fffSStephan Aßmus fVisiblePackages.Add(ref); 49157e51fffSStephan Aßmus } else if (wasVisible) 49257e51fffSStephan Aßmus fVisiblePackages.Remove(ref); 49357e51fffSStephan Aßmus } 49457e51fffSStephan Aßmus 49557e51fffSStephan Aßmus if (wasVisible != isVisible) { 49657e51fffSStephan Aßmus if (!isVisible) { 49757e51fffSStephan Aßmus fPackageListView->RemovePackage(ref); 49857e51fffSStephan Aßmus fFeaturedPackagesView->RemovePackage(ref); 49957e51fffSStephan Aßmus } else { 50057e51fffSStephan Aßmus fPackageListView->AddPackage(ref); 50157e51fffSStephan Aßmus if (ref->IsProminent()) 502da651104SStephan Aßmus fFeaturedPackagesView->AddPackage(ref); 503da651104SStephan Aßmus } 504da651104SStephan Aßmus } 50557e51fffSStephan Aßmus } 50604c9d578SStephan Aßmus break; 50704c9d578SStephan Aßmus } 50804c9d578SStephan Aßmus 50904c9d578SStephan Aßmus case MSG_RATE_PACKAGE: 5101bbda92dSStephan Aßmus _RatePackage(); 51104c9d578SStephan Aßmus break; 51204c9d578SStephan Aßmus 513d5ef985eSStephan Aßmus case MSG_SHOW_SCREENSHOT: 514d5ef985eSStephan Aßmus _ShowScreenshot(); 515d5ef985eSStephan Aßmus break; 516d5ef985eSStephan Aßmus 517125d42d9SJulian Harnath case MSG_PACKAGE_WORKER_BUSY: 518125d42d9SJulian Harnath { 519125d42d9SJulian Harnath BString reason; 520125d42d9SJulian Harnath status_t status = message->FindString("reason", &reason); 521125d42d9SJulian Harnath if (status != B_OK) 522125d42d9SJulian Harnath break; 523125d42d9SJulian Harnath fWorkStatusView->SetBusy(reason); 524125d42d9SJulian Harnath break; 525125d42d9SJulian Harnath } 526125d42d9SJulian Harnath 527125d42d9SJulian Harnath case MSG_PACKAGE_WORKER_IDLE: 528125d42d9SJulian Harnath fWorkStatusView->SetIdle(); 529125d42d9SJulian Harnath break; 530125d42d9SJulian Harnath 531*72fff6d3SJulian Harnath case MSG_ADD_VISIBLE_PACKAGES: 532*72fff6d3SJulian Harnath { 533*72fff6d3SJulian Harnath struct SemaphoreReleaser { 534*72fff6d3SJulian Harnath SemaphoreReleaser(sem_id semaphore) 535*72fff6d3SJulian Harnath : 536*72fff6d3SJulian Harnath fSemaphore(semaphore) 537*72fff6d3SJulian Harnath { } 538*72fff6d3SJulian Harnath 539*72fff6d3SJulian Harnath ~SemaphoreReleaser() { release_sem(fSemaphore); } 540*72fff6d3SJulian Harnath 541*72fff6d3SJulian Harnath sem_id fSemaphore; 542*72fff6d3SJulian Harnath }; 543*72fff6d3SJulian Harnath 544*72fff6d3SJulian Harnath // Make sure acknowledge semaphore is released even on error, 545*72fff6d3SJulian Harnath // so the worker thread won't be blocked 546*72fff6d3SJulian Harnath SemaphoreReleaser acknowledger(fShowPackagesAcknowledgeSem); 547*72fff6d3SJulian Harnath 548*72fff6d3SJulian Harnath int32 numPackages = 0; 549*72fff6d3SJulian Harnath type_code unused; 550*72fff6d3SJulian Harnath status_t status = message->GetInfo("package_ref", &unused, 551*72fff6d3SJulian Harnath &numPackages); 552*72fff6d3SJulian Harnath if (status != B_OK || numPackages == 0) 553*72fff6d3SJulian Harnath break; 554*72fff6d3SJulian Harnath 555*72fff6d3SJulian Harnath int32 listID = 0; 556*72fff6d3SJulian Harnath status = message->FindInt32("list_id", &listID); 557*72fff6d3SJulian Harnath if (status != B_OK) 558*72fff6d3SJulian Harnath break; 559*72fff6d3SJulian Harnath if (listID != atomic_get(&fPackagesToShowListID)) { 560*72fff6d3SJulian Harnath // list is outdated, ignore 561*72fff6d3SJulian Harnath break; 562*72fff6d3SJulian Harnath } 563*72fff6d3SJulian Harnath 564*72fff6d3SJulian Harnath for (int i = 0; i < numPackages; i++) { 565*72fff6d3SJulian Harnath PackageInfo* packageRaw = NULL; 566*72fff6d3SJulian Harnath status = message->FindPointer("package_ref", i, 567*72fff6d3SJulian Harnath (void**)&packageRaw); 568*72fff6d3SJulian Harnath if (status != B_OK) 569*72fff6d3SJulian Harnath break; 570*72fff6d3SJulian Harnath PackageInfoRef package(packageRaw, true); 571*72fff6d3SJulian Harnath 572*72fff6d3SJulian Harnath fPackageListView->AddPackage(package); 573*72fff6d3SJulian Harnath if (package->IsProminent()) 574*72fff6d3SJulian Harnath fFeaturedPackagesView->AddPackage(package); 575*72fff6d3SJulian Harnath } 576*72fff6d3SJulian Harnath break; 577*72fff6d3SJulian Harnath } 578*72fff6d3SJulian Harnath 579*72fff6d3SJulian Harnath case MSG_UPDATE_SELECTED_PACKAGE: 580*72fff6d3SJulian Harnath { 581*72fff6d3SJulian Harnath const PackageInfoRef& selectedPackage = fPackageInfoView->Package(); 582*72fff6d3SJulian Harnath fFeaturedPackagesView->SelectPackage(selectedPackage, true); 583*72fff6d3SJulian Harnath fPackageListView->SelectPackage(selectedPackage); 584*72fff6d3SJulian Harnath 585*72fff6d3SJulian Harnath AutoLocker<BLocker> modelLocker(fModel.Lock()); 586*72fff6d3SJulian Harnath if (!fVisiblePackages.Contains(fPackageInfoView->Package())) 587*72fff6d3SJulian Harnath fPackageInfoView->Clear(); 588*72fff6d3SJulian Harnath break; 589*72fff6d3SJulian Harnath } 590*72fff6d3SJulian Harnath 59104c9d578SStephan Aßmus default: 59204c9d578SStephan Aßmus BWindow::MessageReceived(message); 59304c9d578SStephan Aßmus break; 59404c9d578SStephan Aßmus } 59504c9d578SStephan Aßmus } 59604c9d578SStephan Aßmus 59704c9d578SStephan Aßmus 59804c9d578SStephan Aßmus void 59904c9d578SStephan Aßmus MainWindow::StoreSettings(BMessage& settings) const 60004c9d578SStephan Aßmus { 601f7c2983eSAxel Dörfler settings.AddRect(_WindowFrameName(), Frame()); 602f7c2983eSAxel Dörfler if (!fSinglePackageMode) { 60304c9d578SStephan Aßmus settings.AddRect("window frame", Frame()); 60404c9d578SStephan Aßmus 60504c9d578SStephan Aßmus BMessage columnSettings; 60604c9d578SStephan Aßmus fPackageListView->SaveState(&columnSettings); 60704c9d578SStephan Aßmus 60804c9d578SStephan Aßmus settings.AddMessage("column settings", &columnSettings); 60904c9d578SStephan Aßmus 6102997e05bSStephan Aßmus settings.AddBool("show featured packages", 6112997e05bSStephan Aßmus fModel.ShowFeaturedPackages()); 6122997e05bSStephan Aßmus settings.AddBool("show available packages", 6132997e05bSStephan Aßmus fModel.ShowAvailablePackages()); 6142997e05bSStephan Aßmus settings.AddBool("show installed packages", 6152997e05bSStephan Aßmus fModel.ShowInstalledPackages()); 61604c9d578SStephan Aßmus settings.AddBool("show develop packages", fModel.ShowDevelopPackages()); 61704c9d578SStephan Aßmus settings.AddBool("show source packages", fModel.ShowSourcePackages()); 6186d519fd1SStephan Aßmus } 6198f03a0f9SStephan Aßmus 6208f03a0f9SStephan Aßmus settings.AddString("username", fModel.Username()); 62104c9d578SStephan Aßmus } 62204c9d578SStephan Aßmus 62304c9d578SStephan Aßmus 62404c9d578SStephan Aßmus void 62504c9d578SStephan Aßmus MainWindow::PackageChanged(const PackageInfoEvent& event) 62604c9d578SStephan Aßmus { 627da651104SStephan Aßmus uint32 whatchedChanges = PKG_CHANGED_STATE | PKG_CHANGED_PROMINENCE; 628da651104SStephan Aßmus if ((event.Changes() & whatchedChanges) != 0) { 62904c9d578SStephan Aßmus PackageInfoRef ref(event.Package()); 630da651104SStephan Aßmus BMessage message(MSG_PACKAGE_CHANGED); 63104c9d578SStephan Aßmus message.AddPointer("package", ref.Get()); 632da651104SStephan Aßmus message.AddUInt32("changes", event.Changes()); 63304c9d578SStephan Aßmus ref.Detach(); 63404c9d578SStephan Aßmus // reference needs to be released by MessageReceived(); 63504c9d578SStephan Aßmus PostMessage(&message); 63604c9d578SStephan Aßmus } 63704c9d578SStephan Aßmus } 63804c9d578SStephan Aßmus 63904c9d578SStephan Aßmus 64004c9d578SStephan Aßmus status_t 64104c9d578SStephan Aßmus MainWindow::SchedulePackageActions(PackageActionList& list) 64204c9d578SStephan Aßmus { 64304c9d578SStephan Aßmus AutoLocker<BLocker> lock(&fPendingActionsLock); 64404c9d578SStephan Aßmus for (int32 i = 0; i < list.CountItems(); i++) { 64504c9d578SStephan Aßmus if (!fPendingActions.Add(list.ItemAtFast(i))) 64604c9d578SStephan Aßmus return B_NO_MEMORY; 64704c9d578SStephan Aßmus } 64804c9d578SStephan Aßmus 64904c9d578SStephan Aßmus return release_sem_etc(fPendingActionsSem, list.CountItems(), 0); 65004c9d578SStephan Aßmus } 65104c9d578SStephan Aßmus 65204c9d578SStephan Aßmus 65304c9d578SStephan Aßmus Model* 65404c9d578SStephan Aßmus MainWindow::GetModel() 65504c9d578SStephan Aßmus { 65604c9d578SStephan Aßmus return &fModel; 65704c9d578SStephan Aßmus } 65804c9d578SStephan Aßmus 65904c9d578SStephan Aßmus 66004c9d578SStephan Aßmus void 66104c9d578SStephan Aßmus MainWindow::_BuildMenu(BMenuBar* menuBar) 66204c9d578SStephan Aßmus { 66304c9d578SStephan Aßmus BMenu* menu = new BMenu(B_TRANSLATE("Tools")); 6645bf2b6ebSBrian Hill menu->AddItem(new BMenuItem(B_TRANSLATE("Refresh repositories"), 6655bf2b6ebSBrian Hill new BMessage(MSG_REFRESH_REPOS))); 666d7f78130SHumdinger menu->AddItem(new BMenuItem(B_TRANSLATE("Manage repositories" 667d7f78130SHumdinger B_UTF8_ELLIPSIS), new BMessage(MSG_MANAGE_REPOS))); 668e0a26dceSStephan Aßmus 66904c9d578SStephan Aßmus menuBar->AddItem(menu); 67004c9d578SStephan Aßmus 6714fade61fSStephan Aßmus menu = new BMenu(B_TRANSLATE("Show")); 6724fade61fSStephan Aßmus 6734fade61fSStephan Aßmus fShowFeaturedPackagesItem = new BMenuItem( 6744fade61fSStephan Aßmus B_TRANSLATE("Only featured packages"), 6754fade61fSStephan Aßmus new BMessage(MSG_SHOW_FEATURED_PACKAGES)); 6764fade61fSStephan Aßmus menu->AddItem(fShowFeaturedPackagesItem); 6774fade61fSStephan Aßmus 6784fade61fSStephan Aßmus menu->AddSeparatorItem(); 679fdec4227SStephan Aßmus 680fdec4227SStephan Aßmus fShowAvailablePackagesItem = new BMenuItem( 6814fade61fSStephan Aßmus B_TRANSLATE("Available packages"), 682fdec4227SStephan Aßmus new BMessage(MSG_SHOW_AVAILABLE_PACKAGES)); 683fdec4227SStephan Aßmus menu->AddItem(fShowAvailablePackagesItem); 684fdec4227SStephan Aßmus 685fdec4227SStephan Aßmus fShowInstalledPackagesItem = new BMenuItem( 6864fade61fSStephan Aßmus B_TRANSLATE("Installed packages"), 687fdec4227SStephan Aßmus new BMessage(MSG_SHOW_INSTALLED_PACKAGES)); 688fdec4227SStephan Aßmus menu->AddItem(fShowInstalledPackagesItem); 689fdec4227SStephan Aßmus 690fdec4227SStephan Aßmus menu->AddSeparatorItem(); 691fdec4227SStephan Aßmus 692fdec4227SStephan Aßmus fShowDevelopPackagesItem = new BMenuItem( 6934fade61fSStephan Aßmus B_TRANSLATE("Develop packages"), 694fdec4227SStephan Aßmus new BMessage(MSG_SHOW_DEVELOP_PACKAGES)); 695fdec4227SStephan Aßmus menu->AddItem(fShowDevelopPackagesItem); 696fdec4227SStephan Aßmus 697fdec4227SStephan Aßmus fShowSourcePackagesItem = new BMenuItem( 6984fade61fSStephan Aßmus B_TRANSLATE("Source packages"), 699fdec4227SStephan Aßmus new BMessage(MSG_SHOW_SOURCE_PACKAGES)); 700fdec4227SStephan Aßmus menu->AddItem(fShowSourcePackagesItem); 701fdec4227SStephan Aßmus 702fdec4227SStephan Aßmus menuBar->AddItem(menu); 70304c9d578SStephan Aßmus } 70404c9d578SStephan Aßmus 70504c9d578SStephan Aßmus 70604c9d578SStephan Aßmus void 707e0a26dceSStephan Aßmus MainWindow::_BuildUserMenu(BMenuBar* menuBar) 708e0a26dceSStephan Aßmus { 709e0a26dceSStephan Aßmus fUserMenu = new BMenu(B_TRANSLATE("Not logged in")); 710e0a26dceSStephan Aßmus 711e0a26dceSStephan Aßmus fLogInItem = new BMenuItem(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS), 712e0a26dceSStephan Aßmus new BMessage(MSG_LOG_IN)); 713e0a26dceSStephan Aßmus fUserMenu->AddItem(fLogInItem); 714e0a26dceSStephan Aßmus 715e0a26dceSStephan Aßmus fLogOutItem = new BMenuItem(B_TRANSLATE("Log out"), 716e0a26dceSStephan Aßmus new BMessage(MSG_LOG_OUT)); 717e0a26dceSStephan Aßmus fUserMenu->AddItem(fLogOutItem); 718e0a26dceSStephan Aßmus 719e0a26dceSStephan Aßmus menuBar->AddItem(fUserMenu); 720e0a26dceSStephan Aßmus } 721e0a26dceSStephan Aßmus 722e0a26dceSStephan Aßmus 723e0a26dceSStephan Aßmus void 724f7c2983eSAxel Dörfler MainWindow::_RestoreUserName(const BMessage& settings) 725f7c2983eSAxel Dörfler { 726f7c2983eSAxel Dörfler BString username; 727f7c2983eSAxel Dörfler if (settings.FindString("username", &username) == B_OK 728f7c2983eSAxel Dörfler && username.Length() > 0) { 729f7c2983eSAxel Dörfler fModel.SetUsername(username); 730f7c2983eSAxel Dörfler } 731f7c2983eSAxel Dörfler } 732f7c2983eSAxel Dörfler 733f7c2983eSAxel Dörfler 734f7c2983eSAxel Dörfler const char* 735f7c2983eSAxel Dörfler MainWindow::_WindowFrameName() const 736f7c2983eSAxel Dörfler { 737f7c2983eSAxel Dörfler if (fSinglePackageMode) 738f7c2983eSAxel Dörfler return "small window frame"; 739f7c2983eSAxel Dörfler 740f7c2983eSAxel Dörfler return "window frame"; 741f7c2983eSAxel Dörfler } 742f7c2983eSAxel Dörfler 743f7c2983eSAxel Dörfler 744f7c2983eSAxel Dörfler void 745f7c2983eSAxel Dörfler MainWindow::_RestoreWindowFrame(const BMessage& settings) 746f7c2983eSAxel Dörfler { 747f7c2983eSAxel Dörfler BRect frame = Frame(); 748f7c2983eSAxel Dörfler 749f7c2983eSAxel Dörfler BRect windowFrame; 750f7c2983eSAxel Dörfler bool fromSettings = false; 751f7c2983eSAxel Dörfler if (settings.FindRect(_WindowFrameName(), &windowFrame) == B_OK) { 752f7c2983eSAxel Dörfler frame = windowFrame; 753f7c2983eSAxel Dörfler fromSettings = true; 754f7c2983eSAxel Dörfler } else if (!fSinglePackageMode) { 755f7c2983eSAxel Dörfler // Resize to occupy a certain screen size 756f7c2983eSAxel Dörfler BRect screenFrame = BScreen(this).Frame(); 757f7c2983eSAxel Dörfler float width = frame.Width(); 758f7c2983eSAxel Dörfler float height = frame.Height(); 759f7c2983eSAxel Dörfler if (width < screenFrame.Width() * .666f 760f7c2983eSAxel Dörfler && height < screenFrame.Height() * .666f) { 761f7c2983eSAxel Dörfler frame.bottom = frame.top + screenFrame.Height() * .666f; 762f7c2983eSAxel Dörfler frame.right = frame.left 763f7c2983eSAxel Dörfler + std::min(screenFrame.Width() * .666f, height * 7 / 5); 764f7c2983eSAxel Dörfler } 765f7c2983eSAxel Dörfler } 766f7c2983eSAxel Dörfler 767f7c2983eSAxel Dörfler MoveTo(frame.LeftTop()); 768f7c2983eSAxel Dörfler ResizeTo(frame.Width(), frame.Height()); 769f7c2983eSAxel Dörfler 770f7c2983eSAxel Dörfler if (fromSettings) 7718e96ec34SAxel Dörfler MoveOnScreen(); 772f7c2983eSAxel Dörfler else 773f7c2983eSAxel Dörfler CenterOnScreen(); 774f7c2983eSAxel Dörfler } 775f7c2983eSAxel Dörfler 776f7c2983eSAxel Dörfler 777f7c2983eSAxel Dörfler void 77863975654SStephan Aßmus MainWindow::_InitWorkerThreads() 77963975654SStephan Aßmus { 78063975654SStephan Aßmus fPendingActionsSem = create_sem(0, "PendingPackageActions"); 78163975654SStephan Aßmus if (fPendingActionsSem >= 0) { 78263975654SStephan Aßmus fPendingActionsWorker = spawn_thread(&_PackageActionWorker, 78363975654SStephan Aßmus "Planet Express", B_NORMAL_PRIORITY, this); 78463975654SStephan Aßmus if (fPendingActionsWorker >= 0) 78563975654SStephan Aßmus resume_thread(fPendingActionsWorker); 78609f82905SStephan Aßmus } else 78709f82905SStephan Aßmus fPendingActionsWorker = -1; 78863975654SStephan Aßmus 78963975654SStephan Aßmus fPackageToPopulateSem = create_sem(0, "PopulatePackage"); 79063975654SStephan Aßmus if (fPackageToPopulateSem >= 0) { 79163975654SStephan Aßmus fPopulatePackageWorker = spawn_thread(&_PopulatePackageWorker, 79263975654SStephan Aßmus "Package Populator", B_NORMAL_PRIORITY, this); 79363975654SStephan Aßmus if (fPopulatePackageWorker >= 0) 79463975654SStephan Aßmus resume_thread(fPopulatePackageWorker); 79509f82905SStephan Aßmus } else 79609f82905SStephan Aßmus fPopulatePackageWorker = -1; 797*72fff6d3SJulian Harnath 798*72fff6d3SJulian Harnath fNewPackagesToShowSem = create_sem(0, "ShowPackages"); 799*72fff6d3SJulian Harnath fShowPackagesAcknowledgeSem = create_sem(0, "ShowPackagesAck"); 800*72fff6d3SJulian Harnath if (fNewPackagesToShowSem >= 0 && fShowPackagesAcknowledgeSem >= 0) { 801*72fff6d3SJulian Harnath fShowPackagesWorker = spawn_thread(&_PackagesToShowWorker, 802*72fff6d3SJulian Harnath "Good news everyone", B_NORMAL_PRIORITY, this); 803*72fff6d3SJulian Harnath if (fShowPackagesWorker >= 0) 804*72fff6d3SJulian Harnath resume_thread(fShowPackagesWorker); 805*72fff6d3SJulian Harnath } else 806*72fff6d3SJulian Harnath fShowPackagesWorker = -1; 80763975654SStephan Aßmus } 80863975654SStephan Aßmus 80963975654SStephan Aßmus 81063975654SStephan Aßmus void 81104c9d578SStephan Aßmus MainWindow::_AdoptModel() 81204c9d578SStephan Aßmus { 81304c9d578SStephan Aßmus fVisiblePackages = fModel.CreatePackageList(); 81404c9d578SStephan Aßmus 815*72fff6d3SJulian Harnath { 816*72fff6d3SJulian Harnath AutoLocker<BLocker> modelLocker(fModel.Lock()); 817*72fff6d3SJulian Harnath AutoLocker<BLocker> listLocker(fPackagesToShowListLock); 818*72fff6d3SJulian Harnath fPackagesToShowList = fVisiblePackages; 819*72fff6d3SJulian Harnath atomic_add(&fPackagesToShowListID, 1); 820*72fff6d3SJulian Harnath } 821*72fff6d3SJulian Harnath 8224b930ccaSStephan Aßmus fFeaturedPackagesView->Clear(); 82304c9d578SStephan Aßmus fPackageListView->Clear(); 8244b930ccaSStephan Aßmus 825*72fff6d3SJulian Harnath release_sem(fNewPackagesToShowSem); 82604c9d578SStephan Aßmus 82704c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 8284fade61fSStephan Aßmus fShowFeaturedPackagesItem->SetMarked(fModel.ShowFeaturedPackages()); 8294fade61fSStephan Aßmus fShowFeaturedPackagesItem->SetEnabled(fModel.SearchTerms() == ""); 830fdec4227SStephan Aßmus fShowAvailablePackagesItem->SetMarked(fModel.ShowAvailablePackages()); 831fdec4227SStephan Aßmus fShowInstalledPackagesItem->SetMarked(fModel.ShowInstalledPackages()); 832fdec4227SStephan Aßmus fShowSourcePackagesItem->SetMarked(fModel.ShowSourcePackages()); 833fdec4227SStephan Aßmus fShowDevelopPackagesItem->SetMarked(fModel.ShowDevelopPackages()); 834da651104SStephan Aßmus 8354fade61fSStephan Aßmus if (fModel.ShowFeaturedPackages() && fModel.SearchTerms() == "") 836da651104SStephan Aßmus fListLayout->SetVisibleItem((int32)0); 8374fade61fSStephan Aßmus else 8384fade61fSStephan Aßmus fListLayout->SetVisibleItem((int32)1); 83904c9d578SStephan Aßmus } 84004c9d578SStephan Aßmus 84104c9d578SStephan Aßmus 84204c9d578SStephan Aßmus void 84304c9d578SStephan Aßmus MainWindow::_AdoptPackage(const PackageInfoRef& package) 84404c9d578SStephan Aßmus { 84575ba9dbfSStephan Aßmus { 84675ba9dbfSStephan Aßmus BAutolock locker(fModel.Lock()); 84704c9d578SStephan Aßmus fPackageInfoView->SetPackage(package); 8481986ab9fSStephan Aßmus 849664372abSStephan Aßmus if (fFeaturedPackagesView != NULL) 850664372abSStephan Aßmus fFeaturedPackagesView->SelectPackage(package); 8511986ab9fSStephan Aßmus if (fPackageListView != NULL) 8521986ab9fSStephan Aßmus fPackageListView->SelectPackage(package); 85375ba9dbfSStephan Aßmus } 85404c9d578SStephan Aßmus 85504c9d578SStephan Aßmus // Trigger asynchronous package population from the web-app 85604c9d578SStephan Aßmus { 85704c9d578SStephan Aßmus AutoLocker<BLocker> lock(&fPackageToPopulateLock); 85804c9d578SStephan Aßmus fPackageToPopulate = package; 85904c9d578SStephan Aßmus } 86004c9d578SStephan Aßmus release_sem_etc(fPackageToPopulateSem, 1, 0); 86104c9d578SStephan Aßmus } 86204c9d578SStephan Aßmus 86304c9d578SStephan Aßmus 86404c9d578SStephan Aßmus void 86504c9d578SStephan Aßmus MainWindow::_ClearPackage() 86604c9d578SStephan Aßmus { 86704c9d578SStephan Aßmus fPackageInfoView->Clear(); 86804c9d578SStephan Aßmus } 86904c9d578SStephan Aßmus 87004c9d578SStephan Aßmus 87104c9d578SStephan Aßmus void 87204c9d578SStephan Aßmus MainWindow::_RefreshRepositories(bool force) 87304c9d578SStephan Aßmus { 874448f707cSStephan Aßmus if (fSinglePackageMode) 875448f707cSStephan Aßmus return; 876448f707cSStephan Aßmus 87704c9d578SStephan Aßmus BPackageRoster roster; 87804c9d578SStephan Aßmus BStringList repositoryNames; 87904c9d578SStephan Aßmus 88004c9d578SStephan Aßmus status_t result = roster.GetRepositoryNames(repositoryNames); 88104c9d578SStephan Aßmus if (result != B_OK) 88204c9d578SStephan Aßmus return; 88304c9d578SStephan Aßmus 88404c9d578SStephan Aßmus DecisionProvider decisionProvider; 88504c9d578SStephan Aßmus JobStateListener listener; 88604c9d578SStephan Aßmus BContext context(decisionProvider, listener); 88704c9d578SStephan Aßmus 88804c9d578SStephan Aßmus BRepositoryCache cache; 88904c9d578SStephan Aßmus for (int32 i = 0; i < repositoryNames.CountStrings(); ++i) { 89004c9d578SStephan Aßmus const BString& repoName = repositoryNames.StringAt(i); 89104c9d578SStephan Aßmus BRepositoryConfig repoConfig; 89204c9d578SStephan Aßmus result = roster.GetRepositoryConfig(repoName, &repoConfig); 89304c9d578SStephan Aßmus if (result != B_OK) { 89404c9d578SStephan Aßmus // TODO: notify user 89504c9d578SStephan Aßmus continue; 89604c9d578SStephan Aßmus } 89704c9d578SStephan Aßmus 89804c9d578SStephan Aßmus if (roster.GetRepositoryCache(repoName, &cache) != B_OK || force) { 89904c9d578SStephan Aßmus try { 90004c9d578SStephan Aßmus BRefreshRepositoryRequest refreshRequest(context, repoConfig); 90104c9d578SStephan Aßmus 90204c9d578SStephan Aßmus result = refreshRequest.Process(); 90304c9d578SStephan Aßmus } catch (BFatalErrorException ex) { 90404c9d578SStephan Aßmus BString message(B_TRANSLATE("An error occurred while " 90504c9d578SStephan Aßmus "refreshing the repository: %error% (%details%)")); 90604c9d578SStephan Aßmus message.ReplaceFirst("%error%", ex.Message()); 90704c9d578SStephan Aßmus message.ReplaceFirst("%details%", ex.Details()); 90804c9d578SStephan Aßmus _NotifyUser("Error", message.String()); 90904c9d578SStephan Aßmus } catch (BException ex) { 91004c9d578SStephan Aßmus BString message(B_TRANSLATE("An error occurred while " 91104c9d578SStephan Aßmus "refreshing the repository: %error%")); 91204c9d578SStephan Aßmus message.ReplaceFirst("%error%", ex.Message()); 91304c9d578SStephan Aßmus _NotifyUser("Error", message.String()); 91404c9d578SStephan Aßmus } 91504c9d578SStephan Aßmus } 91604c9d578SStephan Aßmus } 91704c9d578SStephan Aßmus } 91804c9d578SStephan Aßmus 91904c9d578SStephan Aßmus 92004c9d578SStephan Aßmus void 9217b2c59b9SStephan Aßmus MainWindow::_RefreshPackageList(bool force) 92204c9d578SStephan Aßmus { 923448f707cSStephan Aßmus if (fSinglePackageMode) 924448f707cSStephan Aßmus return; 925448f707cSStephan Aßmus 92604c9d578SStephan Aßmus BPackageRoster roster; 92704c9d578SStephan Aßmus BStringList repositoryNames; 92804c9d578SStephan Aßmus 92904c9d578SStephan Aßmus status_t result = roster.GetRepositoryNames(repositoryNames); 93004c9d578SStephan Aßmus if (result != B_OK) 93104c9d578SStephan Aßmus return; 93204c9d578SStephan Aßmus 93304c9d578SStephan Aßmus DepotInfoMap depots; 93404c9d578SStephan Aßmus for (int32 i = 0; i < repositoryNames.CountStrings(); i++) { 93504c9d578SStephan Aßmus const BString& repoName = repositoryNames.StringAt(i); 936ebb1a01cSAndrew Lindesay DepotInfo depotInfo = DepotInfo(repoName); 937ebb1a01cSAndrew Lindesay 938ebb1a01cSAndrew Lindesay BRepositoryConfig repoConfig; 939ebb1a01cSAndrew Lindesay status_t getRepositoryConfigStatus = roster.GetRepositoryConfig( 940ebb1a01cSAndrew Lindesay repoName, &repoConfig); 941ebb1a01cSAndrew Lindesay 942ebb1a01cSAndrew Lindesay if (getRepositoryConfigStatus == B_OK) { 943ebb1a01cSAndrew Lindesay depotInfo.SetBaseURL(repoConfig.BaseURL()); 944ebb1a01cSAndrew Lindesay } else { 945ebb1a01cSAndrew Lindesay printf("unable to obtain the repository config for local " 946ebb1a01cSAndrew Lindesay "repository '%s'; %s\n", 947ebb1a01cSAndrew Lindesay repoName.String(), strerror(getRepositoryConfigStatus)); 948ebb1a01cSAndrew Lindesay } 949ebb1a01cSAndrew Lindesay 950ebb1a01cSAndrew Lindesay depots[repoName] = depotInfo; 95104c9d578SStephan Aßmus } 95204c9d578SStephan Aßmus 95304c9d578SStephan Aßmus PackageManager manager(B_PACKAGE_INSTALLATION_LOCATION_HOME); 95404c9d578SStephan Aßmus try { 95504c9d578SStephan Aßmus manager.Init(PackageManager::B_ADD_INSTALLED_REPOSITORIES 95604c9d578SStephan Aßmus | PackageManager::B_ADD_REMOTE_REPOSITORIES); 95704c9d578SStephan Aßmus } catch (BException ex) { 95804c9d578SStephan Aßmus BString message(B_TRANSLATE("An error occurred while " 95904c9d578SStephan Aßmus "initializing the package manager: %message%")); 96004c9d578SStephan Aßmus message.ReplaceFirst("%message%", ex.Message()); 96104c9d578SStephan Aßmus _NotifyUser("Error", message.String()); 96204c9d578SStephan Aßmus return; 96304c9d578SStephan Aßmus } 96404c9d578SStephan Aßmus 96504c9d578SStephan Aßmus BObjectList<BSolverPackage> packages; 96604c9d578SStephan Aßmus result = manager.Solver()->FindPackages("", 96704c9d578SStephan Aßmus BSolver::B_FIND_CASE_INSENSITIVE | BSolver::B_FIND_IN_NAME 96804c9d578SStephan Aßmus | BSolver::B_FIND_IN_SUMMARY | BSolver::B_FIND_IN_DESCRIPTION 96904c9d578SStephan Aßmus | BSolver::B_FIND_IN_PROVIDES, 97004c9d578SStephan Aßmus packages); 97104c9d578SStephan Aßmus if (result != B_OK) { 97204c9d578SStephan Aßmus BString message(B_TRANSLATE("An error occurred while " 97304c9d578SStephan Aßmus "obtaining the package list: %message%")); 97404c9d578SStephan Aßmus message.ReplaceFirst("%message%", strerror(result)); 97504c9d578SStephan Aßmus _NotifyUser("Error", message.String()); 97604c9d578SStephan Aßmus return; 97704c9d578SStephan Aßmus } 97804c9d578SStephan Aßmus 97904c9d578SStephan Aßmus if (packages.IsEmpty()) 98004c9d578SStephan Aßmus return; 98104c9d578SStephan Aßmus 98204c9d578SStephan Aßmus PackageInfoMap foundPackages; 98304c9d578SStephan Aßmus // if a given package is installed locally, we will potentially 98404c9d578SStephan Aßmus // get back multiple entries, one for each local installation 98504c9d578SStephan Aßmus // location, and one for each remote repository the package 98604c9d578SStephan Aßmus // is available in. The above map is used to ensure that in such 98704c9d578SStephan Aßmus // cases we consolidate the information, rather than displaying 98804c9d578SStephan Aßmus // duplicates 98904c9d578SStephan Aßmus PackageInfoMap remotePackages; 99004c9d578SStephan Aßmus // any package that we find in a remote repository goes in this map. 99104c9d578SStephan Aßmus // this is later used to discern which packages came from a local 99204c9d578SStephan Aßmus // installation only, as those must be handled a bit differently 99304c9d578SStephan Aßmus // upon uninstallation, since we'd no longer be able to pull them 99404c9d578SStephan Aßmus // down remotely. 99504c9d578SStephan Aßmus BStringList systemFlaggedPackages; 99604c9d578SStephan Aßmus // any packages flagged as a system package are added to this list. 99704c9d578SStephan Aßmus // such packages cannot be uninstalled, nor can any of their deps. 99804c9d578SStephan Aßmus PackageInfoMap systemInstalledPackages; 99904c9d578SStephan Aßmus // any packages installed in system are added to this list. 100004c9d578SStephan Aßmus // This is later used for dependency resolution of the actual 100104c9d578SStephan Aßmus // system packages in order to compute the list of protected 100204c9d578SStephan Aßmus // dependencies indicated above. 100304c9d578SStephan Aßmus 100404c9d578SStephan Aßmus for (int32 i = 0; i < packages.CountItems(); i++) { 100504c9d578SStephan Aßmus BSolverPackage* package = packages.ItemAt(i); 100604c9d578SStephan Aßmus const BPackageInfo& repoPackageInfo = package->Info(); 1007ebb1a01cSAndrew Lindesay const BString repositoryName = package->Repository()->Name(); 100804c9d578SStephan Aßmus PackageInfoRef modelInfo; 100904c9d578SStephan Aßmus PackageInfoMap::iterator it = foundPackages.find( 101004c9d578SStephan Aßmus repoPackageInfo.Name()); 101104c9d578SStephan Aßmus if (it != foundPackages.end()) 101204c9d578SStephan Aßmus modelInfo.SetTo(it->second); 101304c9d578SStephan Aßmus else { 101404c9d578SStephan Aßmus // Add new package info 10156d519fd1SStephan Aßmus modelInfo.SetTo(new(std::nothrow) PackageInfo(repoPackageInfo), 101604c9d578SStephan Aßmus true); 101704c9d578SStephan Aßmus 101804c9d578SStephan Aßmus if (modelInfo.Get() == NULL) 101904c9d578SStephan Aßmus return; 102004c9d578SStephan Aßmus 1021ebb1a01cSAndrew Lindesay modelInfo->SetDepotName(repositoryName); 1022ebb1a01cSAndrew Lindesay 102304c9d578SStephan Aßmus foundPackages[repoPackageInfo.Name()] = modelInfo; 102404c9d578SStephan Aßmus } 102504c9d578SStephan Aßmus 102604c9d578SStephan Aßmus modelInfo->AddListener(this); 102704c9d578SStephan Aßmus 102804c9d578SStephan Aßmus BSolverRepository* repository = package->Repository(); 102904c9d578SStephan Aßmus if (dynamic_cast<BPackageManager::RemoteRepository*>(repository) 103004c9d578SStephan Aßmus != NULL) { 103104c9d578SStephan Aßmus depots[repository->Name()].AddPackage(modelInfo); 103272992391SStephan Aßmus remotePackages[modelInfo->Name()] = modelInfo; 103304c9d578SStephan Aßmus } else { 103404c9d578SStephan Aßmus if (repository == static_cast<const BSolverRepository*>( 103504c9d578SStephan Aßmus manager.SystemRepository())) { 103604c9d578SStephan Aßmus modelInfo->AddInstallationLocation( 103704c9d578SStephan Aßmus B_PACKAGE_INSTALLATION_LOCATION_SYSTEM); 103804c9d578SStephan Aßmus if (!modelInfo->IsSystemPackage()) { 103904c9d578SStephan Aßmus systemInstalledPackages[repoPackageInfo.FileName()] 104004c9d578SStephan Aßmus = modelInfo; 104104c9d578SStephan Aßmus } 104204c9d578SStephan Aßmus } else if (repository == static_cast<const BSolverRepository*>( 104304c9d578SStephan Aßmus manager.HomeRepository())) { 104404c9d578SStephan Aßmus modelInfo->AddInstallationLocation( 104504c9d578SStephan Aßmus B_PACKAGE_INSTALLATION_LOCATION_HOME); 104604c9d578SStephan Aßmus } 104704c9d578SStephan Aßmus } 104804c9d578SStephan Aßmus 104904c9d578SStephan Aßmus if (modelInfo->IsSystemPackage()) 105004c9d578SStephan Aßmus systemFlaggedPackages.Add(repoPackageInfo.FileName()); 105104c9d578SStephan Aßmus } 105204c9d578SStephan Aßmus 10537b2c59b9SStephan Aßmus bool wasEmpty = fModel.Depots().IsEmpty(); 10547b2c59b9SStephan Aßmus if (force || wasEmpty) 10556b147523SStephan Aßmus fModel.StopPopulatingAllPackages(); 105604c9d578SStephan Aßmus 10576b147523SStephan Aßmus BAutolock lock(fModel.Lock()); 10587b2c59b9SStephan Aßmus 10597b2c59b9SStephan Aßmus if (force) 106004c9d578SStephan Aßmus fModel.Clear(); 106104c9d578SStephan Aßmus 106204c9d578SStephan Aßmus // filter remote packages from the found list 106304c9d578SStephan Aßmus // any packages remaining will be locally installed packages 106404c9d578SStephan Aßmus // that weren't acquired from a repository 106504c9d578SStephan Aßmus for (PackageInfoMap::iterator it = remotePackages.begin(); 106604c9d578SStephan Aßmus it != remotePackages.end(); it++) { 106704c9d578SStephan Aßmus foundPackages.erase(it->first); 106804c9d578SStephan Aßmus } 106904c9d578SStephan Aßmus 107004c9d578SStephan Aßmus if (!foundPackages.empty()) { 107104c9d578SStephan Aßmus BString repoName = B_TRANSLATE("Local"); 107204c9d578SStephan Aßmus depots[repoName] = DepotInfo(repoName); 107304c9d578SStephan Aßmus DepotInfoMap::iterator depot = depots.find(repoName); 107404c9d578SStephan Aßmus for (PackageInfoMap::iterator it = foundPackages.begin(); 107504c9d578SStephan Aßmus it != foundPackages.end(); ++it) { 107604c9d578SStephan Aßmus depot->second.AddPackage(it->second); 107704c9d578SStephan Aßmus } 107804c9d578SStephan Aßmus } 107904c9d578SStephan Aßmus 108004c9d578SStephan Aßmus for (DepotInfoMap::iterator it = depots.begin(); it != depots.end(); it++) { 10817b2c59b9SStephan Aßmus if (fModel.HasDepot(it->second.Name())) 10827b2c59b9SStephan Aßmus fModel.SyncDepot(it->second); 10837b2c59b9SStephan Aßmus else 108404c9d578SStephan Aßmus fModel.AddDepot(it->second); 108504c9d578SStephan Aßmus } 108604c9d578SStephan Aßmus 10873d528c4aSAndrew Lindesay fModel.PopulateWebAppRepositoryCodes(); 10883d528c4aSAndrew Lindesay 108904c9d578SStephan Aßmus // start retrieving package icons and average ratings 10907b2c59b9SStephan Aßmus if (force || wasEmpty) 109104c9d578SStephan Aßmus fModel.PopulateAllPackages(); 109204c9d578SStephan Aßmus 109304c9d578SStephan Aßmus // compute the OS package dependencies 109404c9d578SStephan Aßmus try { 109504c9d578SStephan Aßmus // create the solver 109604c9d578SStephan Aßmus BSolver* solver; 109704c9d578SStephan Aßmus status_t error = BSolver::Create(solver); 109804c9d578SStephan Aßmus if (error != B_OK) 109904c9d578SStephan Aßmus throw BFatalErrorException(error, "Failed to create solver."); 110004c9d578SStephan Aßmus 110104c9d578SStephan Aßmus ObjectDeleter<BSolver> solverDeleter(solver); 110204c9d578SStephan Aßmus BPath systemPath; 110304c9d578SStephan Aßmus error = find_directory(B_SYSTEM_PACKAGES_DIRECTORY, &systemPath); 110404c9d578SStephan Aßmus if (error != B_OK) { 110504c9d578SStephan Aßmus throw BFatalErrorException(error, 110604c9d578SStephan Aßmus "Unable to retrieve system packages directory."); 110704c9d578SStephan Aßmus } 110804c9d578SStephan Aßmus 110904c9d578SStephan Aßmus // add the "installed" repository with the given packages 111004c9d578SStephan Aßmus BSolverRepository installedRepository; 111104c9d578SStephan Aßmus { 111204c9d578SStephan Aßmus BRepositoryBuilder installedRepositoryBuilder(installedRepository, 111304c9d578SStephan Aßmus "installed"); 111404c9d578SStephan Aßmus for (int32 i = 0; i < systemFlaggedPackages.CountStrings(); i++) { 111504c9d578SStephan Aßmus BPath packagePath(systemPath); 111604c9d578SStephan Aßmus packagePath.Append(systemFlaggedPackages.StringAt(i)); 111704c9d578SStephan Aßmus installedRepositoryBuilder.AddPackage(packagePath.Path()); 111804c9d578SStephan Aßmus } 111904c9d578SStephan Aßmus installedRepositoryBuilder.AddToSolver(solver, true); 112004c9d578SStephan Aßmus } 112104c9d578SStephan Aßmus 112204c9d578SStephan Aßmus // add system repository 112304c9d578SStephan Aßmus BSolverRepository systemRepository; 112404c9d578SStephan Aßmus { 112504c9d578SStephan Aßmus BRepositoryBuilder systemRepositoryBuilder(systemRepository, 112604c9d578SStephan Aßmus "system"); 112704c9d578SStephan Aßmus for (PackageInfoMap::iterator it = systemInstalledPackages.begin(); 112804c9d578SStephan Aßmus it != systemInstalledPackages.end(); it++) { 112904c9d578SStephan Aßmus BPath packagePath(systemPath); 113004c9d578SStephan Aßmus packagePath.Append(it->first); 113104c9d578SStephan Aßmus systemRepositoryBuilder.AddPackage(packagePath.Path()); 113204c9d578SStephan Aßmus } 113304c9d578SStephan Aßmus systemRepositoryBuilder.AddToSolver(solver, false); 113404c9d578SStephan Aßmus } 113504c9d578SStephan Aßmus 113604c9d578SStephan Aßmus // solve 113704c9d578SStephan Aßmus error = solver->VerifyInstallation(); 113804c9d578SStephan Aßmus if (error != B_OK) { 113904c9d578SStephan Aßmus throw BFatalErrorException(error, "Failed to compute packages to " 114004c9d578SStephan Aßmus "install."); 114104c9d578SStephan Aßmus } 114204c9d578SStephan Aßmus 114304c9d578SStephan Aßmus BSolverResult solverResult; 114404c9d578SStephan Aßmus error = solver->GetResult(solverResult); 114504c9d578SStephan Aßmus if (error != B_OK) { 114604c9d578SStephan Aßmus throw BFatalErrorException(error, "Failed to retrieve system " 114704c9d578SStephan Aßmus "package dependency list."); 114804c9d578SStephan Aßmus } 114904c9d578SStephan Aßmus 115004c9d578SStephan Aßmus for (int32 i = 0; const BSolverResultElement* element 115104c9d578SStephan Aßmus = solverResult.ElementAt(i); i++) { 115204c9d578SStephan Aßmus BSolverPackage* package = element->Package(); 115304c9d578SStephan Aßmus if (element->Type() == BSolverResultElement::B_TYPE_INSTALL) { 115404c9d578SStephan Aßmus PackageInfoMap::iterator it = systemInstalledPackages.find( 115504c9d578SStephan Aßmus package->Info().FileName()); 115604c9d578SStephan Aßmus if (it != systemInstalledPackages.end()) 115704c9d578SStephan Aßmus it->second->SetSystemDependency(true); 115804c9d578SStephan Aßmus } 115904c9d578SStephan Aßmus } 116004c9d578SStephan Aßmus } catch (BFatalErrorException ex) { 116104c9d578SStephan Aßmus printf("Fatal exception occurred while resolving system dependencies: " 116204c9d578SStephan Aßmus "%s, details: %s\n", strerror(ex.Error()), ex.Details().String()); 116304c9d578SStephan Aßmus } catch (BNothingToDoException) { 116404c9d578SStephan Aßmus // do nothing 116504c9d578SStephan Aßmus } catch (BException ex) { 116604c9d578SStephan Aßmus printf("Exception occurred while resolving system dependencies: %s\n", 116704c9d578SStephan Aßmus ex.Message().String()); 116804c9d578SStephan Aßmus } catch (...) { 116904c9d578SStephan Aßmus printf("Unknown exception occurred while resolving system " 117004c9d578SStephan Aßmus "dependencies.\n"); 117104c9d578SStephan Aßmus } 117204c9d578SStephan Aßmus } 117304c9d578SStephan Aßmus 117404c9d578SStephan Aßmus 117504c9d578SStephan Aßmus void 117604c9d578SStephan Aßmus MainWindow::_StartRefreshWorker(bool force) 117704c9d578SStephan Aßmus { 117804c9d578SStephan Aßmus if (fModelWorker != B_BAD_THREAD_ID) 117904c9d578SStephan Aßmus return; 118004c9d578SStephan Aßmus 118104c9d578SStephan Aßmus RefreshWorkerParameters* parameters = new(std::nothrow) 118204c9d578SStephan Aßmus RefreshWorkerParameters(this, force); 118304c9d578SStephan Aßmus if (parameters == NULL) 118404c9d578SStephan Aßmus return; 118504c9d578SStephan Aßmus 1186125d42d9SJulian Harnath fWorkStatusView->SetBusy(B_TRANSLATE("Refreshing...")); 1187125d42d9SJulian Harnath 118804c9d578SStephan Aßmus ObjectDeleter<RefreshWorkerParameters> deleter(parameters); 118904c9d578SStephan Aßmus fModelWorker = spawn_thread(&_RefreshModelThreadWorker, "model loader", 119004c9d578SStephan Aßmus B_LOW_PRIORITY, parameters); 119104c9d578SStephan Aßmus 119204c9d578SStephan Aßmus if (fModelWorker > 0) { 119304c9d578SStephan Aßmus deleter.Detach(); 119404c9d578SStephan Aßmus resume_thread(fModelWorker); 119504c9d578SStephan Aßmus } 119604c9d578SStephan Aßmus } 119704c9d578SStephan Aßmus 119804c9d578SStephan Aßmus 119904c9d578SStephan Aßmus status_t 120004c9d578SStephan Aßmus MainWindow::_RefreshModelThreadWorker(void* arg) 120104c9d578SStephan Aßmus { 120204c9d578SStephan Aßmus RefreshWorkerParameters* parameters 120304c9d578SStephan Aßmus = reinterpret_cast<RefreshWorkerParameters*>(arg); 120404c9d578SStephan Aßmus MainWindow* mainWindow = parameters->window; 120504c9d578SStephan Aßmus ObjectDeleter<RefreshWorkerParameters> deleter(parameters); 120604c9d578SStephan Aßmus 120704c9d578SStephan Aßmus BMessenger messenger(mainWindow); 120804c9d578SStephan Aßmus 120904c9d578SStephan Aßmus mainWindow->_RefreshRepositories(parameters->forceRefresh); 121004c9d578SStephan Aßmus 121104c9d578SStephan Aßmus if (mainWindow->fTerminating) 121204c9d578SStephan Aßmus return B_OK; 121304c9d578SStephan Aßmus 12147b2c59b9SStephan Aßmus mainWindow->_RefreshPackageList(parameters->forceRefresh); 121504c9d578SStephan Aßmus 121604c9d578SStephan Aßmus messenger.SendMessage(MSG_MODEL_WORKER_DONE); 121704c9d578SStephan Aßmus 121804c9d578SStephan Aßmus return B_OK; 121904c9d578SStephan Aßmus } 122004c9d578SStephan Aßmus 122104c9d578SStephan Aßmus 122204c9d578SStephan Aßmus status_t 122304c9d578SStephan Aßmus MainWindow::_PackageActionWorker(void* arg) 122404c9d578SStephan Aßmus { 122504c9d578SStephan Aßmus MainWindow* window = reinterpret_cast<MainWindow*>(arg); 122604c9d578SStephan Aßmus 122704c9d578SStephan Aßmus while (acquire_sem(window->fPendingActionsSem) == B_OK) { 122804c9d578SStephan Aßmus PackageActionRef ref; 122904c9d578SStephan Aßmus { 123004c9d578SStephan Aßmus AutoLocker<BLocker> lock(&window->fPendingActionsLock); 123104c9d578SStephan Aßmus ref = window->fPendingActions.ItemAt(0); 123204c9d578SStephan Aßmus if (ref.Get() == NULL) 123304c9d578SStephan Aßmus break; 123404c9d578SStephan Aßmus window->fPendingActions.Remove(0); 123504c9d578SStephan Aßmus } 123604c9d578SStephan Aßmus 1237125d42d9SJulian Harnath BMessenger messenger(window); 1238125d42d9SJulian Harnath BMessage busyMessage(MSG_PACKAGE_WORKER_BUSY); 1239125d42d9SJulian Harnath BString text(ref->Label()); 1240125d42d9SJulian Harnath text << "..."; 1241125d42d9SJulian Harnath busyMessage.AddString("reason", text); 1242125d42d9SJulian Harnath 1243125d42d9SJulian Harnath messenger.SendMessage(&busyMessage); 124404c9d578SStephan Aßmus ref->Perform(); 1245125d42d9SJulian Harnath messenger.SendMessage(MSG_PACKAGE_WORKER_IDLE); 124604c9d578SStephan Aßmus } 124704c9d578SStephan Aßmus 124804c9d578SStephan Aßmus return 0; 124904c9d578SStephan Aßmus } 125004c9d578SStephan Aßmus 125104c9d578SStephan Aßmus 125204c9d578SStephan Aßmus status_t 125304c9d578SStephan Aßmus MainWindow::_PopulatePackageWorker(void* arg) 125404c9d578SStephan Aßmus { 125504c9d578SStephan Aßmus MainWindow* window = reinterpret_cast<MainWindow*>(arg); 125604c9d578SStephan Aßmus 125704c9d578SStephan Aßmus while (acquire_sem(window->fPackageToPopulateSem) == B_OK) { 125804c9d578SStephan Aßmus PackageInfoRef package; 125904c9d578SStephan Aßmus { 126004c9d578SStephan Aßmus AutoLocker<BLocker> lock(&window->fPackageToPopulateLock); 126104c9d578SStephan Aßmus package = window->fPackageToPopulate; 126204c9d578SStephan Aßmus } 126304c9d578SStephan Aßmus 126404c9d578SStephan Aßmus if (package.Get() != NULL) { 126504c9d578SStephan Aßmus window->fModel.PopulatePackage(package, 126604c9d578SStephan Aßmus Model::POPULATE_USER_RATINGS | Model::POPULATE_SCREEN_SHOTS 126704c9d578SStephan Aßmus | Model::POPULATE_CHANGELOG); 126804c9d578SStephan Aßmus } 126904c9d578SStephan Aßmus } 127004c9d578SStephan Aßmus 127104c9d578SStephan Aßmus return 0; 127204c9d578SStephan Aßmus } 127304c9d578SStephan Aßmus 127404c9d578SStephan Aßmus 1275*72fff6d3SJulian Harnath /* static */ status_t 1276*72fff6d3SJulian Harnath MainWindow::_PackagesToShowWorker(void* arg) 1277*72fff6d3SJulian Harnath { 1278*72fff6d3SJulian Harnath MainWindow* window = reinterpret_cast<MainWindow*>(arg); 1279*72fff6d3SJulian Harnath 1280*72fff6d3SJulian Harnath while (acquire_sem(window->fNewPackagesToShowSem) == B_OK) { 1281*72fff6d3SJulian Harnath PackageList packageList; 1282*72fff6d3SJulian Harnath int32 listID = 0; 1283*72fff6d3SJulian Harnath { 1284*72fff6d3SJulian Harnath AutoLocker<BLocker> lock(&window->fPackagesToShowListLock); 1285*72fff6d3SJulian Harnath packageList = window->fPackagesToShowList; 1286*72fff6d3SJulian Harnath listID = atomic_get(&window->fPackagesToShowListID); 1287*72fff6d3SJulian Harnath window->fPackagesToShowList.Clear(); 1288*72fff6d3SJulian Harnath } 1289*72fff6d3SJulian Harnath 1290*72fff6d3SJulian Harnath // Add packages to list views in batches of kPackagesPerUpdate so we 1291*72fff6d3SJulian Harnath // don't block the window thread for long with each iteration 1292*72fff6d3SJulian Harnath enum { 1293*72fff6d3SJulian Harnath kPackagesPerUpdate = 20 1294*72fff6d3SJulian Harnath }; 1295*72fff6d3SJulian Harnath uint32 packagesInMessage = 0; 1296*72fff6d3SJulian Harnath BMessage message(MSG_ADD_VISIBLE_PACKAGES); 1297*72fff6d3SJulian Harnath BMessenger messenger(window); 1298*72fff6d3SJulian Harnath bool listIsOutdated = false; 1299*72fff6d3SJulian Harnath 1300*72fff6d3SJulian Harnath for (int i = 0; i < packageList.CountItems(); i++) { 1301*72fff6d3SJulian Harnath const PackageInfoRef& package = packageList.ItemAtFast(i); 1302*72fff6d3SJulian Harnath 1303*72fff6d3SJulian Harnath if (packagesInMessage >= kPackagesPerUpdate) { 1304*72fff6d3SJulian Harnath if (listID != atomic_get(&window->fPackagesToShowListID)) { 1305*72fff6d3SJulian Harnath // The model was changed again in the meantime, and thus 1306*72fff6d3SJulian Harnath // our package list isn't current anymore. Send no further 1307*72fff6d3SJulian Harnath // messags based on this list and go back to start. 1308*72fff6d3SJulian Harnath listIsOutdated = true; 1309*72fff6d3SJulian Harnath break; 1310*72fff6d3SJulian Harnath } 1311*72fff6d3SJulian Harnath 1312*72fff6d3SJulian Harnath message.AddInt32("list_id", listID); 1313*72fff6d3SJulian Harnath messenger.SendMessage(&message); 1314*72fff6d3SJulian Harnath message.MakeEmpty(); 1315*72fff6d3SJulian Harnath packagesInMessage = 0; 1316*72fff6d3SJulian Harnath 1317*72fff6d3SJulian Harnath // Don't spam the window's message queue, which would make it 1318*72fff6d3SJulian Harnath // unresponsive (i.e. allows UI messages to get in between our 1319*72fff6d3SJulian Harnath // messages). When it has processed the message we just sent, 1320*72fff6d3SJulian Harnath // it will let us know by releasing the semaphore. 1321*72fff6d3SJulian Harnath acquire_sem(window->fShowPackagesAcknowledgeSem); 1322*72fff6d3SJulian Harnath } 1323*72fff6d3SJulian Harnath package->AcquireReference(); 1324*72fff6d3SJulian Harnath message.AddPointer("package_ref", package.Get()); 1325*72fff6d3SJulian Harnath packagesInMessage++; 1326*72fff6d3SJulian Harnath } 1327*72fff6d3SJulian Harnath 1328*72fff6d3SJulian Harnath if (listIsOutdated) 1329*72fff6d3SJulian Harnath continue; 1330*72fff6d3SJulian Harnath 1331*72fff6d3SJulian Harnath // Send remaining package infos, if any, which didn't make it into 1332*72fff6d3SJulian Harnath // the last message (count < kPackagesPerUpdate) 1333*72fff6d3SJulian Harnath if (packagesInMessage > 0) { 1334*72fff6d3SJulian Harnath message.AddInt32("list_id", listID); 1335*72fff6d3SJulian Harnath messenger.SendMessage(&message); 1336*72fff6d3SJulian Harnath acquire_sem(window->fShowPackagesAcknowledgeSem); 1337*72fff6d3SJulian Harnath } 1338*72fff6d3SJulian Harnath 1339*72fff6d3SJulian Harnath // Update selected package in list views 1340*72fff6d3SJulian Harnath messenger.SendMessage(MSG_UPDATE_SELECTED_PACKAGE); 1341*72fff6d3SJulian Harnath } 1342*72fff6d3SJulian Harnath 1343*72fff6d3SJulian Harnath return 0; 1344*72fff6d3SJulian Harnath } 1345*72fff6d3SJulian Harnath 1346*72fff6d3SJulian Harnath 134704c9d578SStephan Aßmus void 134804c9d578SStephan Aßmus MainWindow::_NotifyUser(const char* title, const char* message) 134904c9d578SStephan Aßmus { 135004c9d578SStephan Aßmus BAlert* alert = new(std::nothrow) BAlert(title, message, 135104c9d578SStephan Aßmus B_TRANSLATE("Close")); 135204c9d578SStephan Aßmus 135304c9d578SStephan Aßmus if (alert != NULL) 135404c9d578SStephan Aßmus alert->Go(); 135504c9d578SStephan Aßmus } 135604c9d578SStephan Aßmus 135704c9d578SStephan Aßmus 135804c9d578SStephan Aßmus void 13591bbda92dSStephan Aßmus MainWindow::_OpenLoginWindow(const BMessage& onSuccessMessage) 136004c9d578SStephan Aßmus { 136104c9d578SStephan Aßmus UserLoginWindow* window = new UserLoginWindow(this, 136204c9d578SStephan Aßmus BRect(0, 0, 500, 400), fModel); 13631bbda92dSStephan Aßmus 13641bbda92dSStephan Aßmus if (onSuccessMessage.what != 0) 13651bbda92dSStephan Aßmus window->SetOnSuccessMessage(BMessenger(this), onSuccessMessage); 13661bbda92dSStephan Aßmus 136704c9d578SStephan Aßmus window->Show(); 136804c9d578SStephan Aßmus } 136904c9d578SStephan Aßmus 13708f03a0f9SStephan Aßmus 13718f03a0f9SStephan Aßmus void 13728f03a0f9SStephan Aßmus MainWindow::_UpdateAuthorization() 13738f03a0f9SStephan Aßmus { 13748f03a0f9SStephan Aßmus BString username(fModel.Username()); 1375e0a26dceSStephan Aßmus bool hasUser = !username.IsEmpty(); 1376e0a26dceSStephan Aßmus 13776d519fd1SStephan Aßmus if (fLogOutItem != NULL) 1378e0a26dceSStephan Aßmus fLogOutItem->SetEnabled(hasUser); 1379e0a26dceSStephan Aßmus if (fLogInItem != NULL) { 1380e0a26dceSStephan Aßmus if (hasUser) 1381e0a26dceSStephan Aßmus fLogInItem->SetLabel(B_TRANSLATE("Switch account" B_UTF8_ELLIPSIS)); 1382e0a26dceSStephan Aßmus else 1383e0a26dceSStephan Aßmus fLogInItem->SetLabel(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS)); 1384e0a26dceSStephan Aßmus } 1385e0a26dceSStephan Aßmus 1386e0a26dceSStephan Aßmus if (fUserMenu != NULL) { 1387e0a26dceSStephan Aßmus BString label; 1388e0a26dceSStephan Aßmus if (username.Length() == 0) { 1389e0a26dceSStephan Aßmus label = B_TRANSLATE("Not logged in"); 1390e0a26dceSStephan Aßmus } else { 1391e0a26dceSStephan Aßmus label = B_TRANSLATE("Logged in as %User%"); 1392e0a26dceSStephan Aßmus label.ReplaceAll("%User%", username); 1393e0a26dceSStephan Aßmus } 1394e0a26dceSStephan Aßmus fUserMenu->Superitem()->SetLabel(label); 1395e0a26dceSStephan Aßmus } 13968f03a0f9SStephan Aßmus } 13971bbda92dSStephan Aßmus 13981bbda92dSStephan Aßmus 13991bbda92dSStephan Aßmus void 14001bbda92dSStephan Aßmus MainWindow::_RatePackage() 14011bbda92dSStephan Aßmus { 14021bbda92dSStephan Aßmus if (fModel.Username().IsEmpty()) { 14031bbda92dSStephan Aßmus BAlert* alert = new(std::nothrow) BAlert( 14041bbda92dSStephan Aßmus B_TRANSLATE("Not logged in"), 14051bbda92dSStephan Aßmus B_TRANSLATE("You need to be logged into an account before you " 14061bbda92dSStephan Aßmus "can rate packages."), 14071bbda92dSStephan Aßmus B_TRANSLATE("Cancel"), 14081bbda92dSStephan Aßmus B_TRANSLATE("Login or Create account")); 14091bbda92dSStephan Aßmus 14101bbda92dSStephan Aßmus if (alert == NULL) 14111bbda92dSStephan Aßmus return; 14121bbda92dSStephan Aßmus 14131bbda92dSStephan Aßmus int32 choice = alert->Go(); 14141bbda92dSStephan Aßmus if (choice == 1) 14151bbda92dSStephan Aßmus _OpenLoginWindow(BMessage(MSG_RATE_PACKAGE)); 14161bbda92dSStephan Aßmus return; 14171bbda92dSStephan Aßmus } 14181bbda92dSStephan Aßmus 14191bbda92dSStephan Aßmus // TODO: Allow only one RatePackageWindow 14201bbda92dSStephan Aßmus // TODO: Mechanism for remembering the window frame 14211bbda92dSStephan Aßmus RatePackageWindow* window = new RatePackageWindow(this, 14221bbda92dSStephan Aßmus BRect(0, 0, 500, 400), fModel); 14231bbda92dSStephan Aßmus window->SetPackage(fPackageInfoView->Package()); 14241bbda92dSStephan Aßmus window->Show(); 14251bbda92dSStephan Aßmus } 1426d5ef985eSStephan Aßmus 1427d5ef985eSStephan Aßmus 1428d5ef985eSStephan Aßmus void 1429d5ef985eSStephan Aßmus MainWindow::_ShowScreenshot() 1430d5ef985eSStephan Aßmus { 1431d5ef985eSStephan Aßmus // TODO: Mechanism for remembering the window frame 1432d5ef985eSStephan Aßmus if (fScreenshotWindow == NULL) 1433d5ef985eSStephan Aßmus fScreenshotWindow = new ScreenshotWindow(this, BRect(0, 0, 500, 400)); 1434d5ef985eSStephan Aßmus 1435d5ef985eSStephan Aßmus if (fScreenshotWindow->LockWithTimeout(1000) != B_OK) 1436d5ef985eSStephan Aßmus return; 1437d5ef985eSStephan Aßmus 1438d5ef985eSStephan Aßmus fScreenshotWindow->SetPackage(fPackageInfoView->Package()); 1439d5ef985eSStephan Aßmus 1440d5ef985eSStephan Aßmus if (fScreenshotWindow->IsHidden()) 1441d5ef985eSStephan Aßmus fScreenshotWindow->Show(); 1442d5ef985eSStephan Aßmus else 1443d5ef985eSStephan Aßmus fScreenshotWindow->Activate(); 1444d5ef985eSStephan Aßmus 1445d5ef985eSStephan Aßmus fScreenshotWindow->Unlock(); 1446d5ef985eSStephan Aßmus } 1447