104c9d578SStephan Aßmus /* 204c9d578SStephan Aßmus * Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>. 304c9d578SStephan Aßmus * Copyright 2013, Rene Gollent, rene@gollent.com. 404c9d578SStephan Aßmus * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. 504c9d578SStephan Aßmus * All rights reserved. Distributed under the terms of the MIT License. 604c9d578SStephan Aßmus */ 704c9d578SStephan Aßmus 804c9d578SStephan Aßmus #include "MainWindow.h" 904c9d578SStephan Aßmus 1004c9d578SStephan Aßmus #include <map> 1104c9d578SStephan Aßmus 1204c9d578SStephan Aßmus #include <stdio.h> 1304c9d578SStephan Aßmus 1404c9d578SStephan Aßmus #include <Alert.h> 1504c9d578SStephan Aßmus #include <Autolock.h> 1604c9d578SStephan Aßmus #include <Application.h> 1704c9d578SStephan Aßmus #include <Button.h> 1804c9d578SStephan Aßmus #include <Catalog.h> 194b930ccaSStephan Aßmus #include <CardLayout.h> 2004c9d578SStephan Aßmus #include <LayoutBuilder.h> 2104c9d578SStephan Aßmus #include <MenuBar.h> 2204c9d578SStephan Aßmus #include <MenuItem.h> 2304c9d578SStephan Aßmus #include <Messenger.h> 2404c9d578SStephan Aßmus #include <ScrollView.h> 2504c9d578SStephan Aßmus #include <StringList.h> 260a9c9029SStephan Aßmus #include <StringView.h> 2704c9d578SStephan Aßmus #include <TabView.h> 2804c9d578SStephan Aßmus 2904c9d578SStephan Aßmus #include <package/Context.h> 3004c9d578SStephan Aßmus #include <package/manager/Exceptions.h> 3104c9d578SStephan Aßmus #include <package/manager/RepositoryBuilder.h> 3204c9d578SStephan Aßmus #include <package/RefreshRepositoryRequest.h> 3304c9d578SStephan Aßmus #include <package/PackageRoster.h> 3404c9d578SStephan Aßmus #include "package/RepositoryCache.h" 3504c9d578SStephan Aßmus #include <package/solver/SolverPackage.h> 3604c9d578SStephan Aßmus #include <package/solver/SolverProblem.h> 3704c9d578SStephan Aßmus #include <package/solver/SolverProblemSolution.h> 3804c9d578SStephan Aßmus #include <package/solver/SolverRepository.h> 3904c9d578SStephan Aßmus #include <package/solver/SolverResult.h> 4004c9d578SStephan Aßmus 4104c9d578SStephan Aßmus #include "AutoDeleter.h" 4204c9d578SStephan Aßmus #include "AutoLocker.h" 4304c9d578SStephan Aßmus #include "DecisionProvider.h" 444b930ccaSStephan Aßmus #include "FeaturedPackagesView.h" 4504c9d578SStephan Aßmus #include "FilterView.h" 4604c9d578SStephan Aßmus #include "JobStateListener.h" 4704c9d578SStephan Aßmus #include "PackageInfoView.h" 4804c9d578SStephan Aßmus #include "PackageListView.h" 4904c9d578SStephan Aßmus #include "PackageManager.h" 5004c9d578SStephan Aßmus #include "RatePackageWindow.h" 51e0a26dceSStephan Aßmus #include "support.h" 5204c9d578SStephan Aßmus #include "UserLoginWindow.h" 5304c9d578SStephan Aßmus 5404c9d578SStephan Aßmus 5504c9d578SStephan Aßmus #undef B_TRANSLATION_CONTEXT 5604c9d578SStephan Aßmus #define B_TRANSLATION_CONTEXT "MainWindow" 5704c9d578SStephan Aßmus 5804c9d578SStephan Aßmus 5904c9d578SStephan Aßmus enum { 6004c9d578SStephan Aßmus MSG_MODEL_WORKER_DONE = 'mmwd', 6104c9d578SStephan Aßmus MSG_REFRESH_DEPOTS = 'mrdp', 6204c9d578SStephan Aßmus MSG_LOG_IN = 'lgin', 638f03a0f9SStephan Aßmus MSG_LOG_OUT = 'lgot', 648f03a0f9SStephan Aßmus MSG_AUTHORIZATION_CHANGED = 'athc', 65da651104SStephan Aßmus MSG_PACKAGE_CHANGED = 'pchd', 66fdec4227SStephan Aßmus 67fdec4227SStephan Aßmus MSG_SHOW_AVAILABLE_PACKAGES = 'savl', 68fdec4227SStephan Aßmus MSG_SHOW_INSTALLED_PACKAGES = 'sins', 6904c9d578SStephan Aßmus MSG_SHOW_SOURCE_PACKAGES = 'ssrc', 7004c9d578SStephan Aßmus MSG_SHOW_DEVELOP_PACKAGES = 'sdvl' 7104c9d578SStephan Aßmus }; 7204c9d578SStephan Aßmus 7304c9d578SStephan Aßmus 7404c9d578SStephan Aßmus using namespace BPackageKit; 7504c9d578SStephan Aßmus using namespace BPackageKit::BManager::BPrivate; 7604c9d578SStephan Aßmus 7704c9d578SStephan Aßmus 7804c9d578SStephan Aßmus typedef std::map<BString, PackageInfoRef> PackageInfoMap; 7904c9d578SStephan Aßmus typedef std::map<BString, DepotInfo> DepotInfoMap; 8004c9d578SStephan Aßmus 8104c9d578SStephan Aßmus 8204c9d578SStephan Aßmus struct RefreshWorkerParameters { 8304c9d578SStephan Aßmus MainWindow* window; 8404c9d578SStephan Aßmus bool forceRefresh; 8504c9d578SStephan Aßmus 8604c9d578SStephan Aßmus RefreshWorkerParameters(MainWindow* window, bool forceRefresh) 8704c9d578SStephan Aßmus : 8804c9d578SStephan Aßmus window(window), 8904c9d578SStephan Aßmus forceRefresh(forceRefresh) 9004c9d578SStephan Aßmus { 9104c9d578SStephan Aßmus } 9204c9d578SStephan Aßmus }; 9304c9d578SStephan Aßmus 9404c9d578SStephan Aßmus 958f03a0f9SStephan Aßmus class MessageModelListener : public ModelListener { 968f03a0f9SStephan Aßmus public: 978f03a0f9SStephan Aßmus MessageModelListener(const BMessenger& messenger) 988f03a0f9SStephan Aßmus : 998f03a0f9SStephan Aßmus fMessenger(messenger) 1008f03a0f9SStephan Aßmus { 1018f03a0f9SStephan Aßmus } 1028f03a0f9SStephan Aßmus 1038f03a0f9SStephan Aßmus virtual void AuthorizationChanged() 1048f03a0f9SStephan Aßmus { 1058f03a0f9SStephan Aßmus if (fMessenger.IsValid()) 1068f03a0f9SStephan Aßmus fMessenger.SendMessage(MSG_AUTHORIZATION_CHANGED); 1078f03a0f9SStephan Aßmus } 1088f03a0f9SStephan Aßmus 1098f03a0f9SStephan Aßmus private: 1108f03a0f9SStephan Aßmus BMessenger fMessenger; 1118f03a0f9SStephan Aßmus }; 1128f03a0f9SStephan Aßmus 1138f03a0f9SStephan Aßmus 11404c9d578SStephan Aßmus MainWindow::MainWindow(BRect frame, const BMessage& settings) 11504c9d578SStephan Aßmus : 11604c9d578SStephan Aßmus BWindow(frame, B_TRANSLATE_SYSTEM_NAME("HaikuDepot"), 11704c9d578SStephan Aßmus B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 11804c9d578SStephan Aßmus B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 119e0a26dceSStephan Aßmus fUserMenu(NULL), 120e0a26dceSStephan Aßmus fLogInItem(NULL), 121e0a26dceSStephan Aßmus fLogOutItem(NULL), 1228f03a0f9SStephan Aßmus fModelListener(new MessageModelListener(BMessenger(this)), true), 12304c9d578SStephan Aßmus fTerminating(false), 1246d519fd1SStephan Aßmus fSinglePackageMode(false), 12504c9d578SStephan Aßmus fModelWorker(B_BAD_THREAD_ID) 12604c9d578SStephan Aßmus { 12704c9d578SStephan Aßmus BMenuBar* menuBar = new BMenuBar(B_TRANSLATE("Main Menu")); 12804c9d578SStephan Aßmus _BuildMenu(menuBar); 12904c9d578SStephan Aßmus 130e0a26dceSStephan Aßmus BMenuBar* userMenuBar = new BMenuBar(B_TRANSLATE("User Menu")); 131e0a26dceSStephan Aßmus _BuildUserMenu(userMenuBar); 132e0a26dceSStephan Aßmus set_small_font(userMenuBar); 133e0a26dceSStephan Aßmus userMenuBar->SetExplicitMaxSize(BSize(B_SIZE_UNSET, 134e0a26dceSStephan Aßmus menuBar->MaxSize().height)); 135e0a26dceSStephan Aßmus 13604c9d578SStephan Aßmus fFilterView = new FilterView(); 1374b930ccaSStephan Aßmus fFeaturedPackagesView = new FeaturedPackagesView(); 13804c9d578SStephan Aßmus fPackageListView = new PackageListView(fModel.Lock()); 13904c9d578SStephan Aßmus fPackageInfoView = new PackageInfoView(fModel.Lock(), this); 14004c9d578SStephan Aßmus 14104c9d578SStephan Aßmus fSplitView = new BSplitView(B_VERTICAL, 5.0f); 14204c9d578SStephan Aßmus 1430a9c9029SStephan Aßmus BGroupView* featuredPackagesGroup = new BGroupView(B_VERTICAL); 1440a9c9029SStephan Aßmus BStringView* featuredPackagesTitle = new BStringView( 1450a9c9029SStephan Aßmus "featured packages title", B_TRANSLATE("Featured packages")); 1460a9c9029SStephan Aßmus BFont font(be_bold_font); 1470a9c9029SStephan Aßmus font.SetSize(font.Size() * 1.3f); 1480a9c9029SStephan Aßmus featuredPackagesTitle->SetFont(&font); 1490a9c9029SStephan Aßmus featuredPackagesGroup->SetExplicitMaxSize( 1500a9c9029SStephan Aßmus BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 1510a9c9029SStephan Aßmus BLayoutBuilder::Group<>(featuredPackagesGroup) 1520a9c9029SStephan Aßmus .Add(featuredPackagesTitle) 1530a9c9029SStephan Aßmus .Add(fFeaturedPackagesView) 1540a9c9029SStephan Aßmus ; 1554b930ccaSStephan Aßmus 1560a9c9029SStephan Aßmus BView* listArea = new BView("list area", 0); 1574b930ccaSStephan Aßmus fListLayout = new BCardLayout(); 1584b930ccaSStephan Aßmus listArea->SetLayout(fListLayout); 1590a9c9029SStephan Aßmus listArea->AddChild(featuredPackagesGroup); 1604b930ccaSStephan Aßmus listArea->AddChild(fPackageListView); 161da651104SStephan Aßmus fListLayout->SetVisibleItem((int32)0); 1624b930ccaSStephan Aßmus 16304c9d578SStephan Aßmus BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f) 164e0a26dceSStephan Aßmus .AddGroup(B_HORIZONTAL, 0.0f) 165e0a26dceSStephan Aßmus .Add(menuBar, 1.0f) 166e0a26dceSStephan Aßmus .Add(userMenuBar, 0.0f) 167e0a26dceSStephan Aßmus .End() 16804c9d578SStephan Aßmus .Add(fFilterView) 16904c9d578SStephan Aßmus .AddSplit(fSplitView) 17004c9d578SStephan Aßmus .AddGroup(B_VERTICAL) 1714b930ccaSStephan Aßmus .Add(listArea) 17204c9d578SStephan Aßmus .SetInsets( 17304c9d578SStephan Aßmus B_USE_DEFAULT_SPACING, 0.0f, 17404c9d578SStephan Aßmus B_USE_DEFAULT_SPACING, 0.0f) 17504c9d578SStephan Aßmus .End() 17604c9d578SStephan Aßmus .Add(fPackageInfoView) 17704c9d578SStephan Aßmus .End() 17804c9d578SStephan Aßmus ; 17904c9d578SStephan Aßmus 18004c9d578SStephan Aßmus fSplitView->SetCollapsible(0, false); 18104c9d578SStephan Aßmus fSplitView->SetCollapsible(1, false); 18204c9d578SStephan Aßmus 1838f03a0f9SStephan Aßmus fModel.AddListener(fModelListener); 1848f03a0f9SStephan Aßmus 18504c9d578SStephan Aßmus // Restore settings 18604c9d578SStephan Aßmus BMessage columnSettings; 18704c9d578SStephan Aßmus if (settings.FindMessage("column settings", &columnSettings) == B_OK) 18804c9d578SStephan Aßmus fPackageListView->LoadState(&columnSettings); 18904c9d578SStephan Aßmus 19004c9d578SStephan Aßmus bool showOption; 19104c9d578SStephan Aßmus if (settings.FindBool("show develop packages", &showOption) == B_OK) 19204c9d578SStephan Aßmus fModel.SetShowDevelopPackages(showOption); 19304c9d578SStephan Aßmus if (settings.FindBool("show source packages", &showOption) == B_OK) 19404c9d578SStephan Aßmus fModel.SetShowSourcePackages(showOption); 19504c9d578SStephan Aßmus 1968f03a0f9SStephan Aßmus BString username; 1978f03a0f9SStephan Aßmus if (settings.FindString("username", &username) == B_OK 1988f03a0f9SStephan Aßmus && username.Length() > 0) { 1998f03a0f9SStephan Aßmus fModel.SetUsername(username); 2008f03a0f9SStephan Aßmus } 2018f03a0f9SStephan Aßmus 2028f03a0f9SStephan Aßmus // start worker threads 20304c9d578SStephan Aßmus BPackageRoster().StartWatching(this, 20404c9d578SStephan Aßmus B_WATCH_PACKAGE_INSTALLATION_LOCATIONS); 20504c9d578SStephan Aßmus 20604c9d578SStephan Aßmus _StartRefreshWorker(); 20704c9d578SStephan Aßmus 20863975654SStephan Aßmus _InitWorkerThreads(); 20904c9d578SStephan Aßmus } 21004c9d578SStephan Aßmus 21104c9d578SStephan Aßmus 2126d519fd1SStephan Aßmus MainWindow::MainWindow(BRect frame, const BMessage& settings, 2136d519fd1SStephan Aßmus const PackageInfoRef& package) 2146d519fd1SStephan Aßmus : 2156d519fd1SStephan Aßmus BWindow(frame, B_TRANSLATE_SYSTEM_NAME("HaikuDepot"), 2166d519fd1SStephan Aßmus B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 2176d519fd1SStephan Aßmus B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 218e0a26dceSStephan Aßmus fUserMenu(NULL), 219e0a26dceSStephan Aßmus fLogInItem(NULL), 2206d519fd1SStephan Aßmus fLogOutItem(NULL), 2216d519fd1SStephan Aßmus fModelListener(new MessageModelListener(BMessenger(this)), true), 2226d519fd1SStephan Aßmus fTerminating(false), 2236d519fd1SStephan Aßmus fSinglePackageMode(true), 2246d519fd1SStephan Aßmus fModelWorker(B_BAD_THREAD_ID) 2256d519fd1SStephan Aßmus { 2266d519fd1SStephan Aßmus fFilterView = new FilterView(); 2276d519fd1SStephan Aßmus fPackageListView = new PackageListView(fModel.Lock()); 2286d519fd1SStephan Aßmus fPackageInfoView = new PackageInfoView(fModel.Lock(), this); 2296d519fd1SStephan Aßmus 2306d519fd1SStephan Aßmus BLayoutBuilder::Group<>(this, B_VERTICAL) 2316d519fd1SStephan Aßmus .Add(fPackageInfoView) 2326d519fd1SStephan Aßmus .SetInsets(0, B_USE_WINDOW_INSETS, 0, 0) 2336d519fd1SStephan Aßmus ; 2346d519fd1SStephan Aßmus 2356d519fd1SStephan Aßmus fModel.AddListener(fModelListener); 2366d519fd1SStephan Aßmus 2376d519fd1SStephan Aßmus // Restore settings 2386d519fd1SStephan Aßmus BString username; 2396d519fd1SStephan Aßmus if (settings.FindString("username", &username) == B_OK 2406d519fd1SStephan Aßmus && username.Length() > 0) { 2416d519fd1SStephan Aßmus fModel.SetUsername(username); 2426d519fd1SStephan Aßmus } 2436d519fd1SStephan Aßmus 2446d519fd1SStephan Aßmus fPackageInfoView->SetPackage(package); 24563975654SStephan Aßmus 24663975654SStephan Aßmus _InitWorkerThreads(); 2476d519fd1SStephan Aßmus } 2486d519fd1SStephan Aßmus 2496d519fd1SStephan Aßmus 25004c9d578SStephan Aßmus MainWindow::~MainWindow() 25104c9d578SStephan Aßmus { 25204c9d578SStephan Aßmus BPackageRoster().StopWatching(this); 25304c9d578SStephan Aßmus 25404c9d578SStephan Aßmus fTerminating = true; 25504c9d578SStephan Aßmus if (fModelWorker > 0) 25604c9d578SStephan Aßmus wait_for_thread(fModelWorker, NULL); 25704c9d578SStephan Aßmus 25804c9d578SStephan Aßmus delete_sem(fPendingActionsSem); 25904c9d578SStephan Aßmus wait_for_thread(fPendingActionsWorker, NULL); 26004c9d578SStephan Aßmus 26104c9d578SStephan Aßmus delete_sem(fPackageToPopulateSem); 26204c9d578SStephan Aßmus wait_for_thread(fPopulatePackageWorker, NULL); 26304c9d578SStephan Aßmus } 26404c9d578SStephan Aßmus 26504c9d578SStephan Aßmus 26604c9d578SStephan Aßmus bool 26704c9d578SStephan Aßmus MainWindow::QuitRequested() 26804c9d578SStephan Aßmus { 26904c9d578SStephan Aßmus BMessage settings; 27004c9d578SStephan Aßmus StoreSettings(settings); 27104c9d578SStephan Aßmus 27204c9d578SStephan Aßmus BMessage message(MSG_MAIN_WINDOW_CLOSED); 27304c9d578SStephan Aßmus message.AddMessage("window settings", &settings); 27404c9d578SStephan Aßmus 27504c9d578SStephan Aßmus be_app->PostMessage(&message); 27604c9d578SStephan Aßmus 27704c9d578SStephan Aßmus return true; 27804c9d578SStephan Aßmus } 27904c9d578SStephan Aßmus 28004c9d578SStephan Aßmus 28104c9d578SStephan Aßmus void 28204c9d578SStephan Aßmus MainWindow::MessageReceived(BMessage* message) 28304c9d578SStephan Aßmus { 28404c9d578SStephan Aßmus switch (message->what) { 28504c9d578SStephan Aßmus case MSG_MODEL_WORKER_DONE: 28604c9d578SStephan Aßmus { 28704c9d578SStephan Aßmus fModelWorker = B_BAD_THREAD_ID; 28804c9d578SStephan Aßmus _AdoptModel(); 28904c9d578SStephan Aßmus fFilterView->AdoptModel(fModel); 29004c9d578SStephan Aßmus break; 29104c9d578SStephan Aßmus } 29204c9d578SStephan Aßmus case B_SIMPLE_DATA: 29304c9d578SStephan Aßmus case B_REFS_RECEIVED: 29404c9d578SStephan Aßmus // TODO: ? 29504c9d578SStephan Aßmus break; 29604c9d578SStephan Aßmus 29704c9d578SStephan Aßmus case B_PACKAGE_UPDATE: 29804c9d578SStephan Aßmus // TODO: We should do a more selective update depending on the 29904c9d578SStephan Aßmus // "event", "location", and "change count" fields! 30004c9d578SStephan Aßmus _StartRefreshWorker(false); 30104c9d578SStephan Aßmus break; 30204c9d578SStephan Aßmus 30304c9d578SStephan Aßmus case MSG_REFRESH_DEPOTS: 30404c9d578SStephan Aßmus _StartRefreshWorker(true); 30504c9d578SStephan Aßmus break; 30604c9d578SStephan Aßmus 30704c9d578SStephan Aßmus case MSG_LOG_IN: 3081bbda92dSStephan Aßmus _OpenLoginWindow(BMessage()); 30904c9d578SStephan Aßmus break; 31004c9d578SStephan Aßmus 3118f03a0f9SStephan Aßmus case MSG_LOG_OUT: 3128f03a0f9SStephan Aßmus fModel.SetUsername(""); 3138f03a0f9SStephan Aßmus break; 3148f03a0f9SStephan Aßmus 3158f03a0f9SStephan Aßmus case MSG_AUTHORIZATION_CHANGED: 3168f03a0f9SStephan Aßmus _UpdateAuthorization(); 3178f03a0f9SStephan Aßmus break; 3188f03a0f9SStephan Aßmus 319fdec4227SStephan Aßmus case MSG_SHOW_AVAILABLE_PACKAGES: 320fdec4227SStephan Aßmus { 321fdec4227SStephan Aßmus BAutolock locker(fModel.Lock()); 322fdec4227SStephan Aßmus fModel.SetShowAvailablePackages( 323fdec4227SStephan Aßmus !fModel.ShowAvailablePackages()); 324fdec4227SStephan Aßmus } 325fdec4227SStephan Aßmus _AdoptModel(); 326fdec4227SStephan Aßmus break; 327fdec4227SStephan Aßmus 328fdec4227SStephan Aßmus case MSG_SHOW_INSTALLED_PACKAGES: 329fdec4227SStephan Aßmus { 330fdec4227SStephan Aßmus BAutolock locker(fModel.Lock()); 331fdec4227SStephan Aßmus fModel.SetShowInstalledPackages( 332fdec4227SStephan Aßmus !fModel.ShowInstalledPackages()); 333fdec4227SStephan Aßmus } 334fdec4227SStephan Aßmus _AdoptModel(); 335fdec4227SStephan Aßmus break; 336fdec4227SStephan Aßmus 33704c9d578SStephan Aßmus case MSG_SHOW_SOURCE_PACKAGES: 33804c9d578SStephan Aßmus { 33904c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 34004c9d578SStephan Aßmus fModel.SetShowSourcePackages(!fModel.ShowSourcePackages()); 34104c9d578SStephan Aßmus } 34204c9d578SStephan Aßmus _AdoptModel(); 34304c9d578SStephan Aßmus break; 34404c9d578SStephan Aßmus 34504c9d578SStephan Aßmus case MSG_SHOW_DEVELOP_PACKAGES: 34604c9d578SStephan Aßmus { 34704c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 34804c9d578SStephan Aßmus fModel.SetShowDevelopPackages(!fModel.ShowDevelopPackages()); 34904c9d578SStephan Aßmus } 35004c9d578SStephan Aßmus _AdoptModel(); 35104c9d578SStephan Aßmus break; 35204c9d578SStephan Aßmus 35304c9d578SStephan Aßmus case MSG_PACKAGE_SELECTED: 35404c9d578SStephan Aßmus { 35504c9d578SStephan Aßmus BString title; 35604c9d578SStephan Aßmus if (message->FindString("title", &title) == B_OK) { 35704c9d578SStephan Aßmus int count = fVisiblePackages.CountItems(); 35804c9d578SStephan Aßmus for (int i = 0; i < count; i++) { 35904c9d578SStephan Aßmus const PackageInfoRef& package 36004c9d578SStephan Aßmus = fVisiblePackages.ItemAtFast(i); 36104c9d578SStephan Aßmus if (package.Get() != NULL && package->Title() == title) { 36204c9d578SStephan Aßmus _AdoptPackage(package); 36304c9d578SStephan Aßmus break; 36404c9d578SStephan Aßmus } 36504c9d578SStephan Aßmus } 36604c9d578SStephan Aßmus } else { 36704c9d578SStephan Aßmus _ClearPackage(); 36804c9d578SStephan Aßmus } 36904c9d578SStephan Aßmus break; 37004c9d578SStephan Aßmus } 37104c9d578SStephan Aßmus 37204c9d578SStephan Aßmus case MSG_CATEGORY_SELECTED: 37304c9d578SStephan Aßmus { 37404c9d578SStephan Aßmus BString name; 37504c9d578SStephan Aßmus if (message->FindString("name", &name) != B_OK) 37604c9d578SStephan Aßmus name = ""; 37704c9d578SStephan Aßmus { 37804c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 37904c9d578SStephan Aßmus fModel.SetCategory(name); 38004c9d578SStephan Aßmus } 38104c9d578SStephan Aßmus _AdoptModel(); 38204c9d578SStephan Aßmus break; 38304c9d578SStephan Aßmus } 38404c9d578SStephan Aßmus 38504c9d578SStephan Aßmus case MSG_DEPOT_SELECTED: 38604c9d578SStephan Aßmus { 38704c9d578SStephan Aßmus BString name; 38804c9d578SStephan Aßmus if (message->FindString("name", &name) != B_OK) 38904c9d578SStephan Aßmus name = ""; 39004c9d578SStephan Aßmus { 39104c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 39204c9d578SStephan Aßmus fModel.SetDepot(name); 39304c9d578SStephan Aßmus } 39404c9d578SStephan Aßmus _AdoptModel(); 39504c9d578SStephan Aßmus break; 39604c9d578SStephan Aßmus } 39704c9d578SStephan Aßmus 39804c9d578SStephan Aßmus case MSG_SEARCH_TERMS_MODIFIED: 39904c9d578SStephan Aßmus { 40004c9d578SStephan Aßmus // TODO: Do this with a delay! 40104c9d578SStephan Aßmus BString searchTerms; 40204c9d578SStephan Aßmus if (message->FindString("search terms", &searchTerms) != B_OK) 40304c9d578SStephan Aßmus searchTerms = ""; 40404c9d578SStephan Aßmus { 40504c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 40604c9d578SStephan Aßmus fModel.SetSearchTerms(searchTerms); 40704c9d578SStephan Aßmus } 40804c9d578SStephan Aßmus _AdoptModel(); 40904c9d578SStephan Aßmus break; 41004c9d578SStephan Aßmus } 41104c9d578SStephan Aßmus 412da651104SStephan Aßmus case MSG_PACKAGE_CHANGED: 41304c9d578SStephan Aßmus { 41404c9d578SStephan Aßmus PackageInfo* info; 41504c9d578SStephan Aßmus if (message->FindPointer("package", (void**)&info) == B_OK) { 41604c9d578SStephan Aßmus PackageInfoRef ref(info, true); 417da651104SStephan Aßmus uint32 changes; 418da651104SStephan Aßmus if (message->FindUInt32("changes", &changes) != B_OK) 419da651104SStephan Aßmus changes = 0; 420da651104SStephan Aßmus if ((changes & PKG_CHANGED_STATE) != 0) { 42104c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 42204c9d578SStephan Aßmus fModel.SetPackageState(ref, ref->State()); 42304c9d578SStephan Aßmus } 424da651104SStephan Aßmus if ((changes & PKG_CHANGED_PROMINENCE) != 0) { 425da651104SStephan Aßmus BAutolock locker(fModel.Lock()); 426da651104SStephan Aßmus if (_IsProminentPackage(ref)) 427da651104SStephan Aßmus fFeaturedPackagesView->AddPackage(ref); 428da651104SStephan Aßmus } 429da651104SStephan Aßmus } 43004c9d578SStephan Aßmus break; 43104c9d578SStephan Aßmus } 43204c9d578SStephan Aßmus 43304c9d578SStephan Aßmus case MSG_RATE_PACKAGE: 4341bbda92dSStephan Aßmus _RatePackage(); 43504c9d578SStephan Aßmus break; 43604c9d578SStephan Aßmus 43704c9d578SStephan Aßmus default: 43804c9d578SStephan Aßmus BWindow::MessageReceived(message); 43904c9d578SStephan Aßmus break; 44004c9d578SStephan Aßmus } 44104c9d578SStephan Aßmus } 44204c9d578SStephan Aßmus 44304c9d578SStephan Aßmus 44404c9d578SStephan Aßmus void 44504c9d578SStephan Aßmus MainWindow::StoreSettings(BMessage& settings) const 44604c9d578SStephan Aßmus { 4476d519fd1SStephan Aßmus if (fSinglePackageMode) 4486d519fd1SStephan Aßmus settings.AddRect("small window frame", Frame()); 4496d519fd1SStephan Aßmus else { 45004c9d578SStephan Aßmus settings.AddRect("window frame", Frame()); 45104c9d578SStephan Aßmus 45204c9d578SStephan Aßmus BMessage columnSettings; 45304c9d578SStephan Aßmus fPackageListView->SaveState(&columnSettings); 45404c9d578SStephan Aßmus 45504c9d578SStephan Aßmus settings.AddMessage("column settings", &columnSettings); 45604c9d578SStephan Aßmus 45704c9d578SStephan Aßmus settings.AddBool("show develop packages", fModel.ShowDevelopPackages()); 45804c9d578SStephan Aßmus settings.AddBool("show source packages", fModel.ShowSourcePackages()); 4596d519fd1SStephan Aßmus } 4608f03a0f9SStephan Aßmus 4618f03a0f9SStephan Aßmus settings.AddString("username", fModel.Username()); 46204c9d578SStephan Aßmus } 46304c9d578SStephan Aßmus 46404c9d578SStephan Aßmus 46504c9d578SStephan Aßmus void 46604c9d578SStephan Aßmus MainWindow::PackageChanged(const PackageInfoEvent& event) 46704c9d578SStephan Aßmus { 468da651104SStephan Aßmus uint32 whatchedChanges = PKG_CHANGED_STATE | PKG_CHANGED_PROMINENCE; 469da651104SStephan Aßmus if ((event.Changes() & whatchedChanges) != 0) { 47004c9d578SStephan Aßmus PackageInfoRef ref(event.Package()); 471da651104SStephan Aßmus BMessage message(MSG_PACKAGE_CHANGED); 47204c9d578SStephan Aßmus message.AddPointer("package", ref.Get()); 473da651104SStephan Aßmus message.AddUInt32("changes", event.Changes()); 47404c9d578SStephan Aßmus ref.Detach(); 47504c9d578SStephan Aßmus // reference needs to be released by MessageReceived(); 47604c9d578SStephan Aßmus PostMessage(&message); 47704c9d578SStephan Aßmus } 47804c9d578SStephan Aßmus } 47904c9d578SStephan Aßmus 48004c9d578SStephan Aßmus 48104c9d578SStephan Aßmus status_t 48204c9d578SStephan Aßmus MainWindow::SchedulePackageActions(PackageActionList& list) 48304c9d578SStephan Aßmus { 48404c9d578SStephan Aßmus AutoLocker<BLocker> lock(&fPendingActionsLock); 48504c9d578SStephan Aßmus for (int32 i = 0; i < list.CountItems(); i++) { 48604c9d578SStephan Aßmus if (!fPendingActions.Add(list.ItemAtFast(i))) 48704c9d578SStephan Aßmus return B_NO_MEMORY; 48804c9d578SStephan Aßmus } 48904c9d578SStephan Aßmus 49004c9d578SStephan Aßmus return release_sem_etc(fPendingActionsSem, list.CountItems(), 0); 49104c9d578SStephan Aßmus } 49204c9d578SStephan Aßmus 49304c9d578SStephan Aßmus 49404c9d578SStephan Aßmus Model* 49504c9d578SStephan Aßmus MainWindow::GetModel() 49604c9d578SStephan Aßmus { 49704c9d578SStephan Aßmus return &fModel; 49804c9d578SStephan Aßmus } 49904c9d578SStephan Aßmus 50004c9d578SStephan Aßmus 50104c9d578SStephan Aßmus void 50204c9d578SStephan Aßmus MainWindow::_BuildMenu(BMenuBar* menuBar) 50304c9d578SStephan Aßmus { 50404c9d578SStephan Aßmus BMenu* menu = new BMenu(B_TRANSLATE("Tools")); 50504c9d578SStephan Aßmus menu->AddItem(new BMenuItem(B_TRANSLATE("Refresh depots"), 50604c9d578SStephan Aßmus new BMessage(MSG_REFRESH_DEPOTS))); 507e0a26dceSStephan Aßmus 50804c9d578SStephan Aßmus menuBar->AddItem(menu); 50904c9d578SStephan Aßmus 510fdec4227SStephan Aßmus menu = new BMenu(B_TRANSLATE("Options")); 511fdec4227SStephan Aßmus 512fdec4227SStephan Aßmus fShowAvailablePackagesItem = new BMenuItem( 513fdec4227SStephan Aßmus B_TRANSLATE("Show available packages"), 514fdec4227SStephan Aßmus new BMessage(MSG_SHOW_AVAILABLE_PACKAGES)); 515fdec4227SStephan Aßmus menu->AddItem(fShowAvailablePackagesItem); 516fdec4227SStephan Aßmus 517fdec4227SStephan Aßmus fShowInstalledPackagesItem = new BMenuItem( 518fdec4227SStephan Aßmus B_TRANSLATE("Show installed packages"), 519fdec4227SStephan Aßmus new BMessage(MSG_SHOW_INSTALLED_PACKAGES)); 520fdec4227SStephan Aßmus menu->AddItem(fShowInstalledPackagesItem); 521fdec4227SStephan Aßmus 522fdec4227SStephan Aßmus menu->AddSeparatorItem(); 523fdec4227SStephan Aßmus 524fdec4227SStephan Aßmus fShowDevelopPackagesItem = new BMenuItem( 525fdec4227SStephan Aßmus B_TRANSLATE("Show develop packages"), 526fdec4227SStephan Aßmus new BMessage(MSG_SHOW_DEVELOP_PACKAGES)); 527fdec4227SStephan Aßmus menu->AddItem(fShowDevelopPackagesItem); 528fdec4227SStephan Aßmus 529fdec4227SStephan Aßmus fShowSourcePackagesItem = new BMenuItem( 530fdec4227SStephan Aßmus B_TRANSLATE("Show source packages"), 531fdec4227SStephan Aßmus new BMessage(MSG_SHOW_SOURCE_PACKAGES)); 532fdec4227SStephan Aßmus menu->AddItem(fShowSourcePackagesItem); 533fdec4227SStephan Aßmus 534fdec4227SStephan Aßmus menuBar->AddItem(menu); 53504c9d578SStephan Aßmus } 53604c9d578SStephan Aßmus 53704c9d578SStephan Aßmus 53804c9d578SStephan Aßmus void 539e0a26dceSStephan Aßmus MainWindow::_BuildUserMenu(BMenuBar* menuBar) 540e0a26dceSStephan Aßmus { 541e0a26dceSStephan Aßmus fUserMenu = new BMenu(B_TRANSLATE("Not logged in")); 542e0a26dceSStephan Aßmus 543e0a26dceSStephan Aßmus fLogInItem = new BMenuItem(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS), 544e0a26dceSStephan Aßmus new BMessage(MSG_LOG_IN)); 545e0a26dceSStephan Aßmus fUserMenu->AddItem(fLogInItem); 546e0a26dceSStephan Aßmus 547e0a26dceSStephan Aßmus fLogOutItem = new BMenuItem(B_TRANSLATE("Log out"), 548e0a26dceSStephan Aßmus new BMessage(MSG_LOG_OUT)); 549e0a26dceSStephan Aßmus fUserMenu->AddItem(fLogOutItem); 550e0a26dceSStephan Aßmus 551e0a26dceSStephan Aßmus menuBar->AddItem(fUserMenu); 552e0a26dceSStephan Aßmus } 553e0a26dceSStephan Aßmus 554e0a26dceSStephan Aßmus 555e0a26dceSStephan Aßmus void 55663975654SStephan Aßmus MainWindow::_InitWorkerThreads() 55763975654SStephan Aßmus { 55863975654SStephan Aßmus fPendingActionsSem = create_sem(0, "PendingPackageActions"); 55963975654SStephan Aßmus if (fPendingActionsSem >= 0) { 56063975654SStephan Aßmus fPendingActionsWorker = spawn_thread(&_PackageActionWorker, 56163975654SStephan Aßmus "Planet Express", B_NORMAL_PRIORITY, this); 56263975654SStephan Aßmus if (fPendingActionsWorker >= 0) 56363975654SStephan Aßmus resume_thread(fPendingActionsWorker); 56463975654SStephan Aßmus } 56563975654SStephan Aßmus 56663975654SStephan Aßmus fPackageToPopulateSem = create_sem(0, "PopulatePackage"); 56763975654SStephan Aßmus if (fPackageToPopulateSem >= 0) { 56863975654SStephan Aßmus fPopulatePackageWorker = spawn_thread(&_PopulatePackageWorker, 56963975654SStephan Aßmus "Package Populator", B_NORMAL_PRIORITY, this); 57063975654SStephan Aßmus if (fPopulatePackageWorker >= 0) 57163975654SStephan Aßmus resume_thread(fPopulatePackageWorker); 57263975654SStephan Aßmus } 57363975654SStephan Aßmus } 57463975654SStephan Aßmus 57563975654SStephan Aßmus 57663975654SStephan Aßmus void 57704c9d578SStephan Aßmus MainWindow::_AdoptModel() 57804c9d578SStephan Aßmus { 57904c9d578SStephan Aßmus fVisiblePackages = fModel.CreatePackageList(); 58004c9d578SStephan Aßmus 5814b930ccaSStephan Aßmus fFeaturedPackagesView->Clear(); 58204c9d578SStephan Aßmus fPackageListView->Clear(); 58304c9d578SStephan Aßmus for (int32 i = 0; i < fVisiblePackages.CountItems(); i++) { 58404c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 5854b930ccaSStephan Aßmus 5864b930ccaSStephan Aßmus const PackageInfoRef& package = fVisiblePackages.ItemAtFast(i); 5874b930ccaSStephan Aßmus fPackageListView->AddPackage(package); 5884b930ccaSStephan Aßmus 589da651104SStephan Aßmus if (_IsProminentPackage(package)) 5904b930ccaSStephan Aßmus fFeaturedPackagesView->AddPackage(package); 59104c9d578SStephan Aßmus } 59204c9d578SStephan Aßmus 59304c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 594fdec4227SStephan Aßmus fShowAvailablePackagesItem->SetMarked(fModel.ShowAvailablePackages()); 595fdec4227SStephan Aßmus fShowInstalledPackagesItem->SetMarked(fModel.ShowInstalledPackages()); 596fdec4227SStephan Aßmus fShowSourcePackagesItem->SetMarked(fModel.ShowSourcePackages()); 597fdec4227SStephan Aßmus fShowDevelopPackagesItem->SetMarked(fModel.ShowDevelopPackages()); 598da651104SStephan Aßmus 599da651104SStephan Aßmus if (fModel.Category() != "" 600da651104SStephan Aßmus || fModel.Depot() != "" 601da651104SStephan Aßmus || fModel.SearchTerms() != "" 602da651104SStephan Aßmus || fModel.ShowInstalledPackages()) { 603da651104SStephan Aßmus fListLayout->SetVisibleItem((int32)1); 604da651104SStephan Aßmus } else { 605da651104SStephan Aßmus fListLayout->SetVisibleItem((int32)0); 606da651104SStephan Aßmus } 607da651104SStephan Aßmus } 608da651104SStephan Aßmus 609da651104SStephan Aßmus 610da651104SStephan Aßmus bool 611da651104SStephan Aßmus MainWindow::_IsProminentPackage(const PackageInfoRef& package) const 612da651104SStephan Aßmus { 613419dc642SStephan Aßmus return package->HasProminence() && package->Prominence() <= 200 614da651104SStephan Aßmus && package->State() != ACTIVATED; 61504c9d578SStephan Aßmus } 61604c9d578SStephan Aßmus 61704c9d578SStephan Aßmus 61804c9d578SStephan Aßmus void 61904c9d578SStephan Aßmus MainWindow::_AdoptPackage(const PackageInfoRef& package) 62004c9d578SStephan Aßmus { 62104c9d578SStephan Aßmus fPackageInfoView->SetPackage(package); 622*664372abSStephan Aßmus if (fFeaturedPackagesView != NULL) 623*664372abSStephan Aßmus fFeaturedPackagesView->SelectPackage(package); 62404c9d578SStephan Aßmus 62504c9d578SStephan Aßmus // Trigger asynchronous package population from the web-app 62604c9d578SStephan Aßmus { 62704c9d578SStephan Aßmus AutoLocker<BLocker> lock(&fPackageToPopulateLock); 62804c9d578SStephan Aßmus fPackageToPopulate = package; 62904c9d578SStephan Aßmus } 63004c9d578SStephan Aßmus release_sem_etc(fPackageToPopulateSem, 1, 0); 63104c9d578SStephan Aßmus } 63204c9d578SStephan Aßmus 63304c9d578SStephan Aßmus 63404c9d578SStephan Aßmus void 63504c9d578SStephan Aßmus MainWindow::_ClearPackage() 63604c9d578SStephan Aßmus { 63704c9d578SStephan Aßmus fPackageInfoView->Clear(); 63804c9d578SStephan Aßmus } 63904c9d578SStephan Aßmus 64004c9d578SStephan Aßmus 64104c9d578SStephan Aßmus void 64204c9d578SStephan Aßmus MainWindow::_RefreshRepositories(bool force) 64304c9d578SStephan Aßmus { 644448f707cSStephan Aßmus if (fSinglePackageMode) 645448f707cSStephan Aßmus return; 646448f707cSStephan Aßmus 64704c9d578SStephan Aßmus BPackageRoster roster; 64804c9d578SStephan Aßmus BStringList repositoryNames; 64904c9d578SStephan Aßmus 65004c9d578SStephan Aßmus status_t result = roster.GetRepositoryNames(repositoryNames); 65104c9d578SStephan Aßmus if (result != B_OK) 65204c9d578SStephan Aßmus return; 65304c9d578SStephan Aßmus 65404c9d578SStephan Aßmus DecisionProvider decisionProvider; 65504c9d578SStephan Aßmus JobStateListener listener; 65604c9d578SStephan Aßmus BContext context(decisionProvider, listener); 65704c9d578SStephan Aßmus 65804c9d578SStephan Aßmus BRepositoryCache cache; 65904c9d578SStephan Aßmus for (int32 i = 0; i < repositoryNames.CountStrings(); ++i) { 66004c9d578SStephan Aßmus const BString& repoName = repositoryNames.StringAt(i); 66104c9d578SStephan Aßmus BRepositoryConfig repoConfig; 66204c9d578SStephan Aßmus result = roster.GetRepositoryConfig(repoName, &repoConfig); 66304c9d578SStephan Aßmus if (result != B_OK) { 66404c9d578SStephan Aßmus // TODO: notify user 66504c9d578SStephan Aßmus continue; 66604c9d578SStephan Aßmus } 66704c9d578SStephan Aßmus 66804c9d578SStephan Aßmus if (roster.GetRepositoryCache(repoName, &cache) != B_OK || force) { 66904c9d578SStephan Aßmus try { 67004c9d578SStephan Aßmus BRefreshRepositoryRequest refreshRequest(context, repoConfig); 67104c9d578SStephan Aßmus 67204c9d578SStephan Aßmus result = refreshRequest.Process(); 67304c9d578SStephan Aßmus } catch (BFatalErrorException ex) { 67404c9d578SStephan Aßmus BString message(B_TRANSLATE("An error occurred while " 67504c9d578SStephan Aßmus "refreshing the repository: %error% (%details%)")); 67604c9d578SStephan Aßmus message.ReplaceFirst("%error%", ex.Message()); 67704c9d578SStephan Aßmus message.ReplaceFirst("%details%", ex.Details()); 67804c9d578SStephan Aßmus _NotifyUser("Error", message.String()); 67904c9d578SStephan Aßmus } catch (BException ex) { 68004c9d578SStephan Aßmus BString message(B_TRANSLATE("An error occurred while " 68104c9d578SStephan Aßmus "refreshing the repository: %error%")); 68204c9d578SStephan Aßmus message.ReplaceFirst("%error%", ex.Message()); 68304c9d578SStephan Aßmus _NotifyUser("Error", message.String()); 68404c9d578SStephan Aßmus } 68504c9d578SStephan Aßmus } 68604c9d578SStephan Aßmus } 68704c9d578SStephan Aßmus } 68804c9d578SStephan Aßmus 68904c9d578SStephan Aßmus 69004c9d578SStephan Aßmus void 69104c9d578SStephan Aßmus MainWindow::_RefreshPackageList() 69204c9d578SStephan Aßmus { 693448f707cSStephan Aßmus if (fSinglePackageMode) 694448f707cSStephan Aßmus return; 695448f707cSStephan Aßmus 69604c9d578SStephan Aßmus BPackageRoster roster; 69704c9d578SStephan Aßmus BStringList repositoryNames; 69804c9d578SStephan Aßmus 69904c9d578SStephan Aßmus status_t result = roster.GetRepositoryNames(repositoryNames); 70004c9d578SStephan Aßmus if (result != B_OK) 70104c9d578SStephan Aßmus return; 70204c9d578SStephan Aßmus 70304c9d578SStephan Aßmus DepotInfoMap depots; 70404c9d578SStephan Aßmus for (int32 i = 0; i < repositoryNames.CountStrings(); i++) { 70504c9d578SStephan Aßmus const BString& repoName = repositoryNames.StringAt(i); 70604c9d578SStephan Aßmus depots[repoName] = DepotInfo(repoName); 70704c9d578SStephan Aßmus } 70804c9d578SStephan Aßmus 70904c9d578SStephan Aßmus PackageManager manager(B_PACKAGE_INSTALLATION_LOCATION_HOME); 71004c9d578SStephan Aßmus try { 71104c9d578SStephan Aßmus manager.Init(PackageManager::B_ADD_INSTALLED_REPOSITORIES 71204c9d578SStephan Aßmus | PackageManager::B_ADD_REMOTE_REPOSITORIES); 71304c9d578SStephan Aßmus } catch (BException ex) { 71404c9d578SStephan Aßmus BString message(B_TRANSLATE("An error occurred while " 71504c9d578SStephan Aßmus "initializing the package manager: %message%")); 71604c9d578SStephan Aßmus message.ReplaceFirst("%message%", ex.Message()); 71704c9d578SStephan Aßmus _NotifyUser("Error", message.String()); 71804c9d578SStephan Aßmus return; 71904c9d578SStephan Aßmus } 72004c9d578SStephan Aßmus 72104c9d578SStephan Aßmus BObjectList<BSolverPackage> packages; 72204c9d578SStephan Aßmus result = manager.Solver()->FindPackages("", 72304c9d578SStephan Aßmus BSolver::B_FIND_CASE_INSENSITIVE | BSolver::B_FIND_IN_NAME 72404c9d578SStephan Aßmus | BSolver::B_FIND_IN_SUMMARY | BSolver::B_FIND_IN_DESCRIPTION 72504c9d578SStephan Aßmus | BSolver::B_FIND_IN_PROVIDES, 72604c9d578SStephan Aßmus packages); 72704c9d578SStephan Aßmus if (result != B_OK) { 72804c9d578SStephan Aßmus BString message(B_TRANSLATE("An error occurred while " 72904c9d578SStephan Aßmus "obtaining the package list: %message%")); 73004c9d578SStephan Aßmus message.ReplaceFirst("%message%", strerror(result)); 73104c9d578SStephan Aßmus _NotifyUser("Error", message.String()); 73204c9d578SStephan Aßmus return; 73304c9d578SStephan Aßmus } 73404c9d578SStephan Aßmus 73504c9d578SStephan Aßmus if (packages.IsEmpty()) 73604c9d578SStephan Aßmus return; 73704c9d578SStephan Aßmus 73804c9d578SStephan Aßmus PackageInfoMap foundPackages; 73904c9d578SStephan Aßmus // if a given package is installed locally, we will potentially 74004c9d578SStephan Aßmus // get back multiple entries, one for each local installation 74104c9d578SStephan Aßmus // location, and one for each remote repository the package 74204c9d578SStephan Aßmus // is available in. The above map is used to ensure that in such 74304c9d578SStephan Aßmus // cases we consolidate the information, rather than displaying 74404c9d578SStephan Aßmus // duplicates 74504c9d578SStephan Aßmus PackageInfoMap remotePackages; 74604c9d578SStephan Aßmus // any package that we find in a remote repository goes in this map. 74704c9d578SStephan Aßmus // this is later used to discern which packages came from a local 74804c9d578SStephan Aßmus // installation only, as those must be handled a bit differently 74904c9d578SStephan Aßmus // upon uninstallation, since we'd no longer be able to pull them 75004c9d578SStephan Aßmus // down remotely. 75104c9d578SStephan Aßmus BStringList systemFlaggedPackages; 75204c9d578SStephan Aßmus // any packages flagged as a system package are added to this list. 75304c9d578SStephan Aßmus // such packages cannot be uninstalled, nor can any of their deps. 75404c9d578SStephan Aßmus PackageInfoMap systemInstalledPackages; 75504c9d578SStephan Aßmus // any packages installed in system are added to this list. 75604c9d578SStephan Aßmus // This is later used for dependency resolution of the actual 75704c9d578SStephan Aßmus // system packages in order to compute the list of protected 75804c9d578SStephan Aßmus // dependencies indicated above. 75904c9d578SStephan Aßmus 76004c9d578SStephan Aßmus for (int32 i = 0; i < packages.CountItems(); i++) { 76104c9d578SStephan Aßmus BSolverPackage* package = packages.ItemAt(i); 76204c9d578SStephan Aßmus const BPackageInfo& repoPackageInfo = package->Info(); 76304c9d578SStephan Aßmus PackageInfoRef modelInfo; 76404c9d578SStephan Aßmus PackageInfoMap::iterator it = foundPackages.find( 76504c9d578SStephan Aßmus repoPackageInfo.Name()); 76604c9d578SStephan Aßmus if (it != foundPackages.end()) 76704c9d578SStephan Aßmus modelInfo.SetTo(it->second); 76804c9d578SStephan Aßmus else { 76904c9d578SStephan Aßmus // Add new package info 7706d519fd1SStephan Aßmus modelInfo.SetTo(new(std::nothrow) PackageInfo(repoPackageInfo), 77104c9d578SStephan Aßmus true); 77204c9d578SStephan Aßmus 77304c9d578SStephan Aßmus if (modelInfo.Get() == NULL) 77404c9d578SStephan Aßmus return; 77504c9d578SStephan Aßmus 77604c9d578SStephan Aßmus foundPackages[repoPackageInfo.Name()] = modelInfo; 77704c9d578SStephan Aßmus } 77804c9d578SStephan Aßmus 77904c9d578SStephan Aßmus modelInfo->AddListener(this); 78004c9d578SStephan Aßmus 78104c9d578SStephan Aßmus BSolverRepository* repository = package->Repository(); 78204c9d578SStephan Aßmus if (dynamic_cast<BPackageManager::RemoteRepository*>(repository) 78304c9d578SStephan Aßmus != NULL) { 78404c9d578SStephan Aßmus depots[repository->Name()].AddPackage(modelInfo); 78504c9d578SStephan Aßmus remotePackages[modelInfo->Title()] = modelInfo; 78604c9d578SStephan Aßmus } else { 78704c9d578SStephan Aßmus if (repository == static_cast<const BSolverRepository*>( 78804c9d578SStephan Aßmus manager.SystemRepository())) { 78904c9d578SStephan Aßmus modelInfo->AddInstallationLocation( 79004c9d578SStephan Aßmus B_PACKAGE_INSTALLATION_LOCATION_SYSTEM); 79104c9d578SStephan Aßmus if (!modelInfo->IsSystemPackage()) { 79204c9d578SStephan Aßmus systemInstalledPackages[repoPackageInfo.FileName()] 79304c9d578SStephan Aßmus = modelInfo; 79404c9d578SStephan Aßmus } 79504c9d578SStephan Aßmus } else if (repository == static_cast<const BSolverRepository*>( 79604c9d578SStephan Aßmus manager.HomeRepository())) { 79704c9d578SStephan Aßmus modelInfo->AddInstallationLocation( 79804c9d578SStephan Aßmus B_PACKAGE_INSTALLATION_LOCATION_HOME); 79904c9d578SStephan Aßmus } 80004c9d578SStephan Aßmus } 80104c9d578SStephan Aßmus 80204c9d578SStephan Aßmus if (modelInfo->IsSystemPackage()) 80304c9d578SStephan Aßmus systemFlaggedPackages.Add(repoPackageInfo.FileName()); 80404c9d578SStephan Aßmus } 80504c9d578SStephan Aßmus 8066b147523SStephan Aßmus fModel.StopPopulatingAllPackages(); 80704c9d578SStephan Aßmus 8086b147523SStephan Aßmus BAutolock lock(fModel.Lock()); 80904c9d578SStephan Aßmus fModel.Clear(); 81004c9d578SStephan Aßmus 81104c9d578SStephan Aßmus // filter remote packages from the found list 81204c9d578SStephan Aßmus // any packages remaining will be locally installed packages 81304c9d578SStephan Aßmus // that weren't acquired from a repository 81404c9d578SStephan Aßmus for (PackageInfoMap::iterator it = remotePackages.begin(); 81504c9d578SStephan Aßmus it != remotePackages.end(); it++) { 81604c9d578SStephan Aßmus foundPackages.erase(it->first); 81704c9d578SStephan Aßmus } 81804c9d578SStephan Aßmus 81904c9d578SStephan Aßmus if (!foundPackages.empty()) { 82004c9d578SStephan Aßmus BString repoName = B_TRANSLATE("Local"); 82104c9d578SStephan Aßmus depots[repoName] = DepotInfo(repoName); 82204c9d578SStephan Aßmus DepotInfoMap::iterator depot = depots.find(repoName); 82304c9d578SStephan Aßmus for (PackageInfoMap::iterator it = foundPackages.begin(); 82404c9d578SStephan Aßmus it != foundPackages.end(); ++it) { 82504c9d578SStephan Aßmus depot->second.AddPackage(it->second); 82604c9d578SStephan Aßmus } 82704c9d578SStephan Aßmus } 82804c9d578SStephan Aßmus 82904c9d578SStephan Aßmus for (DepotInfoMap::iterator it = depots.begin(); it != depots.end(); it++) { 83004c9d578SStephan Aßmus fModel.AddDepot(it->second); 83104c9d578SStephan Aßmus } 83204c9d578SStephan Aßmus 83304c9d578SStephan Aßmus // start retrieving package icons and average ratings 83404c9d578SStephan Aßmus fModel.PopulateAllPackages(); 83504c9d578SStephan Aßmus 83604c9d578SStephan Aßmus // compute the OS package dependencies 83704c9d578SStephan Aßmus try { 83804c9d578SStephan Aßmus // create the solver 83904c9d578SStephan Aßmus BSolver* solver; 84004c9d578SStephan Aßmus status_t error = BSolver::Create(solver); 84104c9d578SStephan Aßmus if (error != B_OK) 84204c9d578SStephan Aßmus throw BFatalErrorException(error, "Failed to create solver."); 84304c9d578SStephan Aßmus 84404c9d578SStephan Aßmus ObjectDeleter<BSolver> solverDeleter(solver); 84504c9d578SStephan Aßmus BPath systemPath; 84604c9d578SStephan Aßmus error = find_directory(B_SYSTEM_PACKAGES_DIRECTORY, &systemPath); 84704c9d578SStephan Aßmus if (error != B_OK) { 84804c9d578SStephan Aßmus throw BFatalErrorException(error, 84904c9d578SStephan Aßmus "Unable to retrieve system packages directory."); 85004c9d578SStephan Aßmus } 85104c9d578SStephan Aßmus 85204c9d578SStephan Aßmus // add the "installed" repository with the given packages 85304c9d578SStephan Aßmus BSolverRepository installedRepository; 85404c9d578SStephan Aßmus { 85504c9d578SStephan Aßmus BRepositoryBuilder installedRepositoryBuilder(installedRepository, 85604c9d578SStephan Aßmus "installed"); 85704c9d578SStephan Aßmus for (int32 i = 0; i < systemFlaggedPackages.CountStrings(); i++) { 85804c9d578SStephan Aßmus BPath packagePath(systemPath); 85904c9d578SStephan Aßmus packagePath.Append(systemFlaggedPackages.StringAt(i)); 86004c9d578SStephan Aßmus installedRepositoryBuilder.AddPackage(packagePath.Path()); 86104c9d578SStephan Aßmus } 86204c9d578SStephan Aßmus installedRepositoryBuilder.AddToSolver(solver, true); 86304c9d578SStephan Aßmus } 86404c9d578SStephan Aßmus 86504c9d578SStephan Aßmus // add system repository 86604c9d578SStephan Aßmus BSolverRepository systemRepository; 86704c9d578SStephan Aßmus { 86804c9d578SStephan Aßmus BRepositoryBuilder systemRepositoryBuilder(systemRepository, 86904c9d578SStephan Aßmus "system"); 87004c9d578SStephan Aßmus for (PackageInfoMap::iterator it = systemInstalledPackages.begin(); 87104c9d578SStephan Aßmus it != systemInstalledPackages.end(); it++) { 87204c9d578SStephan Aßmus BPath packagePath(systemPath); 87304c9d578SStephan Aßmus packagePath.Append(it->first); 87404c9d578SStephan Aßmus systemRepositoryBuilder.AddPackage(packagePath.Path()); 87504c9d578SStephan Aßmus } 87604c9d578SStephan Aßmus systemRepositoryBuilder.AddToSolver(solver, false); 87704c9d578SStephan Aßmus } 87804c9d578SStephan Aßmus 87904c9d578SStephan Aßmus // solve 88004c9d578SStephan Aßmus error = solver->VerifyInstallation(); 88104c9d578SStephan Aßmus if (error != B_OK) { 88204c9d578SStephan Aßmus throw BFatalErrorException(error, "Failed to compute packages to " 88304c9d578SStephan Aßmus "install."); 88404c9d578SStephan Aßmus } 88504c9d578SStephan Aßmus 88604c9d578SStephan Aßmus BSolverResult solverResult; 88704c9d578SStephan Aßmus error = solver->GetResult(solverResult); 88804c9d578SStephan Aßmus if (error != B_OK) { 88904c9d578SStephan Aßmus throw BFatalErrorException(error, "Failed to retrieve system " 89004c9d578SStephan Aßmus "package dependency list."); 89104c9d578SStephan Aßmus } 89204c9d578SStephan Aßmus 89304c9d578SStephan Aßmus for (int32 i = 0; const BSolverResultElement* element 89404c9d578SStephan Aßmus = solverResult.ElementAt(i); i++) { 89504c9d578SStephan Aßmus BSolverPackage* package = element->Package(); 89604c9d578SStephan Aßmus if (element->Type() == BSolverResultElement::B_TYPE_INSTALL) { 89704c9d578SStephan Aßmus PackageInfoMap::iterator it = systemInstalledPackages.find( 89804c9d578SStephan Aßmus package->Info().FileName()); 89904c9d578SStephan Aßmus if (it != systemInstalledPackages.end()) 90004c9d578SStephan Aßmus it->second->SetSystemDependency(true); 90104c9d578SStephan Aßmus } 90204c9d578SStephan Aßmus } 90304c9d578SStephan Aßmus } catch (BFatalErrorException ex) { 90404c9d578SStephan Aßmus printf("Fatal exception occurred while resolving system dependencies: " 90504c9d578SStephan Aßmus "%s, details: %s\n", strerror(ex.Error()), ex.Details().String()); 90604c9d578SStephan Aßmus } catch (BNothingToDoException) { 90704c9d578SStephan Aßmus // do nothing 90804c9d578SStephan Aßmus } catch (BException ex) { 90904c9d578SStephan Aßmus printf("Exception occurred while resolving system dependencies: %s\n", 91004c9d578SStephan Aßmus ex.Message().String()); 91104c9d578SStephan Aßmus } catch (...) { 91204c9d578SStephan Aßmus printf("Unknown exception occurred while resolving system " 91304c9d578SStephan Aßmus "dependencies.\n"); 91404c9d578SStephan Aßmus } 91504c9d578SStephan Aßmus } 91604c9d578SStephan Aßmus 91704c9d578SStephan Aßmus 91804c9d578SStephan Aßmus void 91904c9d578SStephan Aßmus MainWindow::_StartRefreshWorker(bool force) 92004c9d578SStephan Aßmus { 92104c9d578SStephan Aßmus if (fModelWorker != B_BAD_THREAD_ID) 92204c9d578SStephan Aßmus return; 92304c9d578SStephan Aßmus 92404c9d578SStephan Aßmus RefreshWorkerParameters* parameters = new(std::nothrow) 92504c9d578SStephan Aßmus RefreshWorkerParameters(this, force); 92604c9d578SStephan Aßmus if (parameters == NULL) 92704c9d578SStephan Aßmus return; 92804c9d578SStephan Aßmus 92904c9d578SStephan Aßmus ObjectDeleter<RefreshWorkerParameters> deleter(parameters); 93004c9d578SStephan Aßmus fModelWorker = spawn_thread(&_RefreshModelThreadWorker, "model loader", 93104c9d578SStephan Aßmus B_LOW_PRIORITY, parameters); 93204c9d578SStephan Aßmus 93304c9d578SStephan Aßmus if (fModelWorker > 0) { 93404c9d578SStephan Aßmus deleter.Detach(); 93504c9d578SStephan Aßmus resume_thread(fModelWorker); 93604c9d578SStephan Aßmus } 93704c9d578SStephan Aßmus } 93804c9d578SStephan Aßmus 93904c9d578SStephan Aßmus 94004c9d578SStephan Aßmus status_t 94104c9d578SStephan Aßmus MainWindow::_RefreshModelThreadWorker(void* arg) 94204c9d578SStephan Aßmus { 94304c9d578SStephan Aßmus RefreshWorkerParameters* parameters 94404c9d578SStephan Aßmus = reinterpret_cast<RefreshWorkerParameters*>(arg); 94504c9d578SStephan Aßmus MainWindow* mainWindow = parameters->window; 94604c9d578SStephan Aßmus ObjectDeleter<RefreshWorkerParameters> deleter(parameters); 94704c9d578SStephan Aßmus 94804c9d578SStephan Aßmus BMessenger messenger(mainWindow); 94904c9d578SStephan Aßmus 95004c9d578SStephan Aßmus mainWindow->_RefreshRepositories(parameters->forceRefresh); 95104c9d578SStephan Aßmus 95204c9d578SStephan Aßmus if (mainWindow->fTerminating) 95304c9d578SStephan Aßmus return B_OK; 95404c9d578SStephan Aßmus 95504c9d578SStephan Aßmus mainWindow->_RefreshPackageList(); 95604c9d578SStephan Aßmus 95704c9d578SStephan Aßmus messenger.SendMessage(MSG_MODEL_WORKER_DONE); 95804c9d578SStephan Aßmus 95904c9d578SStephan Aßmus return B_OK; 96004c9d578SStephan Aßmus } 96104c9d578SStephan Aßmus 96204c9d578SStephan Aßmus 96304c9d578SStephan Aßmus status_t 96404c9d578SStephan Aßmus MainWindow::_PackageActionWorker(void* arg) 96504c9d578SStephan Aßmus { 96604c9d578SStephan Aßmus MainWindow* window = reinterpret_cast<MainWindow*>(arg); 96704c9d578SStephan Aßmus 96804c9d578SStephan Aßmus while (acquire_sem(window->fPendingActionsSem) == B_OK) { 96904c9d578SStephan Aßmus PackageActionRef ref; 97004c9d578SStephan Aßmus { 97104c9d578SStephan Aßmus AutoLocker<BLocker> lock(&window->fPendingActionsLock); 97204c9d578SStephan Aßmus ref = window->fPendingActions.ItemAt(0); 97304c9d578SStephan Aßmus if (ref.Get() == NULL) 97404c9d578SStephan Aßmus break; 97504c9d578SStephan Aßmus window->fPendingActions.Remove(0); 97604c9d578SStephan Aßmus } 97704c9d578SStephan Aßmus 97804c9d578SStephan Aßmus ref->Perform(); 97904c9d578SStephan Aßmus } 98004c9d578SStephan Aßmus 98104c9d578SStephan Aßmus return 0; 98204c9d578SStephan Aßmus } 98304c9d578SStephan Aßmus 98404c9d578SStephan Aßmus 98504c9d578SStephan Aßmus status_t 98604c9d578SStephan Aßmus MainWindow::_PopulatePackageWorker(void* arg) 98704c9d578SStephan Aßmus { 98804c9d578SStephan Aßmus MainWindow* window = reinterpret_cast<MainWindow*>(arg); 98904c9d578SStephan Aßmus 99004c9d578SStephan Aßmus while (acquire_sem(window->fPackageToPopulateSem) == B_OK) { 99104c9d578SStephan Aßmus PackageInfoRef package; 99204c9d578SStephan Aßmus { 99304c9d578SStephan Aßmus AutoLocker<BLocker> lock(&window->fPackageToPopulateLock); 99404c9d578SStephan Aßmus package = window->fPackageToPopulate; 99504c9d578SStephan Aßmus } 99604c9d578SStephan Aßmus 99704c9d578SStephan Aßmus if (package.Get() != NULL) { 99804c9d578SStephan Aßmus window->fModel.PopulatePackage(package, 99904c9d578SStephan Aßmus Model::POPULATE_USER_RATINGS | Model::POPULATE_SCREEN_SHOTS 100004c9d578SStephan Aßmus | Model::POPULATE_CHANGELOG); 100104c9d578SStephan Aßmus } 100204c9d578SStephan Aßmus } 100304c9d578SStephan Aßmus 100404c9d578SStephan Aßmus return 0; 100504c9d578SStephan Aßmus } 100604c9d578SStephan Aßmus 100704c9d578SStephan Aßmus 100804c9d578SStephan Aßmus void 100904c9d578SStephan Aßmus MainWindow::_NotifyUser(const char* title, const char* message) 101004c9d578SStephan Aßmus { 101104c9d578SStephan Aßmus BAlert* alert = new(std::nothrow) BAlert(title, message, 101204c9d578SStephan Aßmus B_TRANSLATE("Close")); 101304c9d578SStephan Aßmus 101404c9d578SStephan Aßmus if (alert != NULL) 101504c9d578SStephan Aßmus alert->Go(); 101604c9d578SStephan Aßmus } 101704c9d578SStephan Aßmus 101804c9d578SStephan Aßmus 101904c9d578SStephan Aßmus void 10201bbda92dSStephan Aßmus MainWindow::_OpenLoginWindow(const BMessage& onSuccessMessage) 102104c9d578SStephan Aßmus { 102204c9d578SStephan Aßmus UserLoginWindow* window = new UserLoginWindow(this, 102304c9d578SStephan Aßmus BRect(0, 0, 500, 400), fModel); 10241bbda92dSStephan Aßmus 10251bbda92dSStephan Aßmus if (onSuccessMessage.what != 0) 10261bbda92dSStephan Aßmus window->SetOnSuccessMessage(BMessenger(this), onSuccessMessage); 10271bbda92dSStephan Aßmus 102804c9d578SStephan Aßmus window->Show(); 102904c9d578SStephan Aßmus } 103004c9d578SStephan Aßmus 10318f03a0f9SStephan Aßmus 10328f03a0f9SStephan Aßmus void 10338f03a0f9SStephan Aßmus MainWindow::_UpdateAuthorization() 10348f03a0f9SStephan Aßmus { 10358f03a0f9SStephan Aßmus BString username(fModel.Username()); 1036e0a26dceSStephan Aßmus bool hasUser = !username.IsEmpty(); 1037e0a26dceSStephan Aßmus 10386d519fd1SStephan Aßmus if (fLogOutItem != NULL) 1039e0a26dceSStephan Aßmus fLogOutItem->SetEnabled(hasUser); 1040e0a26dceSStephan Aßmus if (fLogInItem != NULL) { 1041e0a26dceSStephan Aßmus if (hasUser) 1042e0a26dceSStephan Aßmus fLogInItem->SetLabel(B_TRANSLATE("Switch account" B_UTF8_ELLIPSIS)); 1043e0a26dceSStephan Aßmus else 1044e0a26dceSStephan Aßmus fLogInItem->SetLabel(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS)); 1045e0a26dceSStephan Aßmus } 1046e0a26dceSStephan Aßmus 1047e0a26dceSStephan Aßmus if (fUserMenu != NULL) { 1048e0a26dceSStephan Aßmus BString label; 1049e0a26dceSStephan Aßmus if (username.Length() == 0) { 1050e0a26dceSStephan Aßmus label = B_TRANSLATE("Not logged in"); 1051e0a26dceSStephan Aßmus } else { 1052e0a26dceSStephan Aßmus label = B_TRANSLATE("Logged in as %User%"); 1053e0a26dceSStephan Aßmus label.ReplaceAll("%User%", username); 1054e0a26dceSStephan Aßmus } 1055e0a26dceSStephan Aßmus fUserMenu->Superitem()->SetLabel(label); 1056e0a26dceSStephan Aßmus } 10578f03a0f9SStephan Aßmus } 10581bbda92dSStephan Aßmus 10591bbda92dSStephan Aßmus 10601bbda92dSStephan Aßmus void 10611bbda92dSStephan Aßmus MainWindow::_RatePackage() 10621bbda92dSStephan Aßmus { 10631bbda92dSStephan Aßmus if (fModel.Username().IsEmpty()) { 10641bbda92dSStephan Aßmus BAlert* alert = new(std::nothrow) BAlert( 10651bbda92dSStephan Aßmus B_TRANSLATE("Not logged in"), 10661bbda92dSStephan Aßmus B_TRANSLATE("You need to be logged into an account before you " 10671bbda92dSStephan Aßmus "can rate packages."), 10681bbda92dSStephan Aßmus B_TRANSLATE("Cancel"), 10691bbda92dSStephan Aßmus B_TRANSLATE("Login or Create account")); 10701bbda92dSStephan Aßmus 10711bbda92dSStephan Aßmus if (alert == NULL) 10721bbda92dSStephan Aßmus return; 10731bbda92dSStephan Aßmus 10741bbda92dSStephan Aßmus int32 choice = alert->Go(); 10751bbda92dSStephan Aßmus if (choice == 1) 10761bbda92dSStephan Aßmus _OpenLoginWindow(BMessage(MSG_RATE_PACKAGE)); 10771bbda92dSStephan Aßmus return; 10781bbda92dSStephan Aßmus } 10791bbda92dSStephan Aßmus 10801bbda92dSStephan Aßmus // TODO: Allow only one RatePackageWindow 10811bbda92dSStephan Aßmus // TODO: Mechanism for remembering the window frame 10821bbda92dSStephan Aßmus RatePackageWindow* window = new RatePackageWindow(this, 10831bbda92dSStephan Aßmus BRect(0, 0, 500, 400), fModel); 10841bbda92dSStephan Aßmus window->SetPackage(fPackageInfoView->Package()); 10851bbda92dSStephan Aßmus window->Show(); 10861bbda92dSStephan Aßmus } 1087