104c9d578SStephan Aßmus /* 2*f7c2983eSAxel 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. 604c9d578SStephan Aßmus * All rights reserved. Distributed under the terms of the MIT License. 704c9d578SStephan Aßmus */ 804c9d578SStephan Aßmus 9*f7c2983eSAxel Dörfler 1004c9d578SStephan Aßmus #include "MainWindow.h" 1104c9d578SStephan Aßmus 1204c9d578SStephan Aßmus #include <map> 1304c9d578SStephan Aßmus 1404c9d578SStephan Aßmus #include <stdio.h> 1504c9d578SStephan Aßmus 1604c9d578SStephan Aßmus #include <Alert.h> 1704c9d578SStephan Aßmus #include <Autolock.h> 1804c9d578SStephan Aßmus #include <Application.h> 1904c9d578SStephan Aßmus #include <Button.h> 2004c9d578SStephan Aßmus #include <Catalog.h> 214b930ccaSStephan Aßmus #include <CardLayout.h> 2204c9d578SStephan Aßmus #include <LayoutBuilder.h> 2304c9d578SStephan Aßmus #include <MenuBar.h> 2404c9d578SStephan Aßmus #include <MenuItem.h> 2504c9d578SStephan Aßmus #include <Messenger.h> 26*f7c2983eSAxel Dörfler #include <Screen.h> 2704c9d578SStephan Aßmus #include <ScrollView.h> 2804c9d578SStephan Aßmus #include <StringList.h> 290a9c9029SStephan Aßmus #include <StringView.h> 3004c9d578SStephan Aßmus #include <TabView.h> 3104c9d578SStephan Aßmus 3204c9d578SStephan Aßmus #include <package/Context.h> 3304c9d578SStephan Aßmus #include <package/manager/Exceptions.h> 3404c9d578SStephan Aßmus #include <package/manager/RepositoryBuilder.h> 3504c9d578SStephan Aßmus #include <package/RefreshRepositoryRequest.h> 3604c9d578SStephan Aßmus #include <package/PackageRoster.h> 3704c9d578SStephan Aßmus #include "package/RepositoryCache.h" 3804c9d578SStephan Aßmus #include <package/solver/SolverPackage.h> 3904c9d578SStephan Aßmus #include <package/solver/SolverProblem.h> 4004c9d578SStephan Aßmus #include <package/solver/SolverProblemSolution.h> 4104c9d578SStephan Aßmus #include <package/solver/SolverRepository.h> 4204c9d578SStephan Aßmus #include <package/solver/SolverResult.h> 4304c9d578SStephan Aßmus 4404c9d578SStephan Aßmus #include "AutoDeleter.h" 4504c9d578SStephan Aßmus #include "AutoLocker.h" 4604c9d578SStephan Aßmus #include "DecisionProvider.h" 474b930ccaSStephan Aßmus #include "FeaturedPackagesView.h" 4804c9d578SStephan Aßmus #include "FilterView.h" 4904c9d578SStephan Aßmus #include "JobStateListener.h" 5004c9d578SStephan Aßmus #include "PackageInfoView.h" 5104c9d578SStephan Aßmus #include "PackageListView.h" 5204c9d578SStephan Aßmus #include "PackageManager.h" 5304c9d578SStephan Aßmus #include "RatePackageWindow.h" 54e0a26dceSStephan Aßmus #include "support.h" 55d5ef985eSStephan Aßmus #include "ScreenshotWindow.h" 5604c9d578SStephan Aßmus #include "UserLoginWindow.h" 5704c9d578SStephan Aßmus 5804c9d578SStephan Aßmus 5904c9d578SStephan Aßmus #undef B_TRANSLATION_CONTEXT 6004c9d578SStephan Aßmus #define B_TRANSLATION_CONTEXT "MainWindow" 6104c9d578SStephan Aßmus 6204c9d578SStephan Aßmus 6304c9d578SStephan Aßmus enum { 6404c9d578SStephan Aßmus MSG_MODEL_WORKER_DONE = 'mmwd', 6504c9d578SStephan Aßmus MSG_REFRESH_DEPOTS = 'mrdp', 6604c9d578SStephan Aßmus MSG_LOG_IN = 'lgin', 678f03a0f9SStephan Aßmus MSG_LOG_OUT = 'lgot', 688f03a0f9SStephan Aßmus MSG_AUTHORIZATION_CHANGED = 'athc', 69da651104SStephan Aßmus MSG_PACKAGE_CHANGED = 'pchd', 70fdec4227SStephan Aßmus 714fade61fSStephan Aßmus MSG_SHOW_FEATURED_PACKAGES = 'sofp', 72fdec4227SStephan Aßmus MSG_SHOW_AVAILABLE_PACKAGES = 'savl', 73fdec4227SStephan Aßmus MSG_SHOW_INSTALLED_PACKAGES = 'sins', 7404c9d578SStephan Aßmus MSG_SHOW_SOURCE_PACKAGES = 'ssrc', 7504c9d578SStephan Aßmus MSG_SHOW_DEVELOP_PACKAGES = 'sdvl' 7604c9d578SStephan Aßmus }; 7704c9d578SStephan Aßmus 7804c9d578SStephan Aßmus 7904c9d578SStephan Aßmus using namespace BPackageKit; 8004c9d578SStephan Aßmus using namespace BPackageKit::BManager::BPrivate; 8104c9d578SStephan Aßmus 8204c9d578SStephan Aßmus 8304c9d578SStephan Aßmus typedef std::map<BString, PackageInfoRef> PackageInfoMap; 8404c9d578SStephan Aßmus typedef std::map<BString, DepotInfo> DepotInfoMap; 8504c9d578SStephan Aßmus 8604c9d578SStephan Aßmus 8704c9d578SStephan Aßmus struct RefreshWorkerParameters { 8804c9d578SStephan Aßmus MainWindow* window; 8904c9d578SStephan Aßmus bool forceRefresh; 9004c9d578SStephan Aßmus 9104c9d578SStephan Aßmus RefreshWorkerParameters(MainWindow* window, bool forceRefresh) 9204c9d578SStephan Aßmus : 9304c9d578SStephan Aßmus window(window), 9404c9d578SStephan Aßmus forceRefresh(forceRefresh) 9504c9d578SStephan Aßmus { 9604c9d578SStephan Aßmus } 9704c9d578SStephan Aßmus }; 9804c9d578SStephan Aßmus 9904c9d578SStephan Aßmus 1008f03a0f9SStephan Aßmus class MessageModelListener : public ModelListener { 1018f03a0f9SStephan Aßmus public: 1028f03a0f9SStephan Aßmus MessageModelListener(const BMessenger& messenger) 1038f03a0f9SStephan Aßmus : 1048f03a0f9SStephan Aßmus fMessenger(messenger) 1058f03a0f9SStephan Aßmus { 1068f03a0f9SStephan Aßmus } 1078f03a0f9SStephan Aßmus 1088f03a0f9SStephan Aßmus virtual void AuthorizationChanged() 1098f03a0f9SStephan Aßmus { 1108f03a0f9SStephan Aßmus if (fMessenger.IsValid()) 1118f03a0f9SStephan Aßmus fMessenger.SendMessage(MSG_AUTHORIZATION_CHANGED); 1128f03a0f9SStephan Aßmus } 1138f03a0f9SStephan Aßmus 1148f03a0f9SStephan Aßmus private: 1158f03a0f9SStephan Aßmus BMessenger fMessenger; 1168f03a0f9SStephan Aßmus }; 1178f03a0f9SStephan Aßmus 1188f03a0f9SStephan Aßmus 119*f7c2983eSAxel Dörfler MainWindow::MainWindow(const BMessage& settings) 12004c9d578SStephan Aßmus : 121*f7c2983eSAxel Dörfler BWindow(BRect(50, 50, 650, 550), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"), 12204c9d578SStephan Aßmus B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 12304c9d578SStephan Aßmus B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 124d5ef985eSStephan Aßmus fScreenshotWindow(NULL), 125e0a26dceSStephan Aßmus fUserMenu(NULL), 126e0a26dceSStephan Aßmus fLogInItem(NULL), 127e0a26dceSStephan Aßmus fLogOutItem(NULL), 1288f03a0f9SStephan Aßmus fModelListener(new MessageModelListener(BMessenger(this)), true), 12904c9d578SStephan Aßmus fTerminating(false), 1306d519fd1SStephan Aßmus fSinglePackageMode(false), 13104c9d578SStephan Aßmus fModelWorker(B_BAD_THREAD_ID) 13204c9d578SStephan Aßmus { 13304c9d578SStephan Aßmus BMenuBar* menuBar = new BMenuBar(B_TRANSLATE("Main Menu")); 13404c9d578SStephan Aßmus _BuildMenu(menuBar); 13504c9d578SStephan Aßmus 136e0a26dceSStephan Aßmus BMenuBar* userMenuBar = new BMenuBar(B_TRANSLATE("User Menu")); 137e0a26dceSStephan Aßmus _BuildUserMenu(userMenuBar); 138e0a26dceSStephan Aßmus set_small_font(userMenuBar); 139e0a26dceSStephan Aßmus userMenuBar->SetExplicitMaxSize(BSize(B_SIZE_UNSET, 140e0a26dceSStephan Aßmus menuBar->MaxSize().height)); 141e0a26dceSStephan Aßmus 14204c9d578SStephan Aßmus fFilterView = new FilterView(); 1434b930ccaSStephan Aßmus fFeaturedPackagesView = new FeaturedPackagesView(); 14404c9d578SStephan Aßmus fPackageListView = new PackageListView(fModel.Lock()); 14504c9d578SStephan Aßmus fPackageInfoView = new PackageInfoView(fModel.Lock(), this); 14604c9d578SStephan Aßmus 14704c9d578SStephan Aßmus fSplitView = new BSplitView(B_VERTICAL, 5.0f); 14804c9d578SStephan Aßmus 1490a9c9029SStephan Aßmus BGroupView* featuredPackagesGroup = new BGroupView(B_VERTICAL); 1500a9c9029SStephan Aßmus BStringView* featuredPackagesTitle = new BStringView( 1510a9c9029SStephan Aßmus "featured packages title", B_TRANSLATE("Featured packages")); 1520a9c9029SStephan Aßmus BFont font(be_bold_font); 1530a9c9029SStephan Aßmus font.SetSize(font.Size() * 1.3f); 1540a9c9029SStephan Aßmus featuredPackagesTitle->SetFont(&font); 1550a9c9029SStephan Aßmus featuredPackagesGroup->SetExplicitMaxSize( 1560a9c9029SStephan Aßmus BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 1570a9c9029SStephan Aßmus BLayoutBuilder::Group<>(featuredPackagesGroup) 1580a9c9029SStephan Aßmus .Add(featuredPackagesTitle) 1590a9c9029SStephan Aßmus .Add(fFeaturedPackagesView) 1600a9c9029SStephan Aßmus ; 1614b930ccaSStephan Aßmus 1620a9c9029SStephan Aßmus BView* listArea = new BView("list area", 0); 1634b930ccaSStephan Aßmus fListLayout = new BCardLayout(); 1644b930ccaSStephan Aßmus listArea->SetLayout(fListLayout); 1650a9c9029SStephan Aßmus listArea->AddChild(featuredPackagesGroup); 1664b930ccaSStephan Aßmus listArea->AddChild(fPackageListView); 1674b930ccaSStephan Aßmus 16804c9d578SStephan Aßmus BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f) 169e0a26dceSStephan Aßmus .AddGroup(B_HORIZONTAL, 0.0f) 170e0a26dceSStephan Aßmus .Add(menuBar, 1.0f) 171e0a26dceSStephan Aßmus .Add(userMenuBar, 0.0f) 172e0a26dceSStephan Aßmus .End() 17304c9d578SStephan Aßmus .Add(fFilterView) 17404c9d578SStephan Aßmus .AddSplit(fSplitView) 17504c9d578SStephan Aßmus .AddGroup(B_VERTICAL) 1764b930ccaSStephan Aßmus .Add(listArea) 17704c9d578SStephan Aßmus .SetInsets( 17804c9d578SStephan Aßmus B_USE_DEFAULT_SPACING, 0.0f, 17904c9d578SStephan Aßmus B_USE_DEFAULT_SPACING, 0.0f) 18004c9d578SStephan Aßmus .End() 18104c9d578SStephan Aßmus .Add(fPackageInfoView) 18204c9d578SStephan Aßmus .End() 18304c9d578SStephan Aßmus ; 18404c9d578SStephan Aßmus 18504c9d578SStephan Aßmus fSplitView->SetCollapsible(0, false); 18604c9d578SStephan Aßmus fSplitView->SetCollapsible(1, false); 18704c9d578SStephan Aßmus 1888f03a0f9SStephan Aßmus fModel.AddListener(fModelListener); 1898f03a0f9SStephan Aßmus 19004c9d578SStephan Aßmus // Restore settings 19104c9d578SStephan Aßmus BMessage columnSettings; 19204c9d578SStephan Aßmus if (settings.FindMessage("column settings", &columnSettings) == B_OK) 19304c9d578SStephan Aßmus fPackageListView->LoadState(&columnSettings); 19404c9d578SStephan Aßmus 19504c9d578SStephan Aßmus bool showOption; 1962997e05bSStephan Aßmus if (settings.FindBool("show featured packages", &showOption) == B_OK) 1972997e05bSStephan Aßmus fModel.SetShowFeaturedPackages(showOption); 1982997e05bSStephan Aßmus if (settings.FindBool("show available packages", &showOption) == B_OK) 1992997e05bSStephan Aßmus fModel.SetShowAvailablePackages(showOption); 2002997e05bSStephan Aßmus if (settings.FindBool("show installed packages", &showOption) == B_OK) 2012997e05bSStephan Aßmus fModel.SetShowInstalledPackages(showOption); 20204c9d578SStephan Aßmus if (settings.FindBool("show develop packages", &showOption) == B_OK) 20304c9d578SStephan Aßmus fModel.SetShowDevelopPackages(showOption); 20404c9d578SStephan Aßmus if (settings.FindBool("show source packages", &showOption) == B_OK) 20504c9d578SStephan Aßmus fModel.SetShowSourcePackages(showOption); 20604c9d578SStephan Aßmus 2072997e05bSStephan Aßmus if (fModel.ShowFeaturedPackages()) 2082997e05bSStephan Aßmus fListLayout->SetVisibleItem((int32)0); 2092997e05bSStephan Aßmus else 2102997e05bSStephan Aßmus fListLayout->SetVisibleItem(1); 2112997e05bSStephan Aßmus 212*f7c2983eSAxel Dörfler _RestoreUserName(settings); 213*f7c2983eSAxel Dörfler _RestoreWindowFrame(settings); 214*f7c2983eSAxel Dörfler 2158f03a0f9SStephan Aßmus // start worker threads 21604c9d578SStephan Aßmus BPackageRoster().StartWatching(this, 21704c9d578SStephan Aßmus B_WATCH_PACKAGE_INSTALLATION_LOCATIONS); 21804c9d578SStephan Aßmus 21904c9d578SStephan Aßmus _StartRefreshWorker(); 22004c9d578SStephan Aßmus 22163975654SStephan Aßmus _InitWorkerThreads(); 22204c9d578SStephan Aßmus } 22304c9d578SStephan Aßmus 22404c9d578SStephan Aßmus 225*f7c2983eSAxel Dörfler MainWindow::MainWindow(const BMessage& settings, const PackageInfoRef& package) 2266d519fd1SStephan Aßmus : 227*f7c2983eSAxel Dörfler BWindow(BRect(50, 50, 650, 350), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"), 2286d519fd1SStephan Aßmus B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 2296d519fd1SStephan Aßmus B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 230d5ef985eSStephan Aßmus fScreenshotWindow(NULL), 231e0a26dceSStephan Aßmus fUserMenu(NULL), 232e0a26dceSStephan Aßmus fLogInItem(NULL), 2336d519fd1SStephan Aßmus fLogOutItem(NULL), 2346d519fd1SStephan Aßmus fModelListener(new MessageModelListener(BMessenger(this)), true), 2356d519fd1SStephan Aßmus fTerminating(false), 2366d519fd1SStephan Aßmus fSinglePackageMode(true), 2376d519fd1SStephan Aßmus fModelWorker(B_BAD_THREAD_ID) 2386d519fd1SStephan Aßmus { 2396d519fd1SStephan Aßmus fFilterView = new FilterView(); 2406d519fd1SStephan Aßmus fPackageListView = new PackageListView(fModel.Lock()); 2416d519fd1SStephan Aßmus fPackageInfoView = new PackageInfoView(fModel.Lock(), this); 2426d519fd1SStephan Aßmus 2436d519fd1SStephan Aßmus BLayoutBuilder::Group<>(this, B_VERTICAL) 2446d519fd1SStephan Aßmus .Add(fPackageInfoView) 2456d519fd1SStephan Aßmus .SetInsets(0, B_USE_WINDOW_INSETS, 0, 0) 2466d519fd1SStephan Aßmus ; 2476d519fd1SStephan Aßmus 2486d519fd1SStephan Aßmus fModel.AddListener(fModelListener); 2496d519fd1SStephan Aßmus 2506d519fd1SStephan Aßmus // Restore settings 251*f7c2983eSAxel Dörfler _RestoreUserName(settings); 252*f7c2983eSAxel Dörfler _RestoreWindowFrame(settings); 2536d519fd1SStephan Aßmus 2546d519fd1SStephan Aßmus fPackageInfoView->SetPackage(package); 25563975654SStephan Aßmus 25663975654SStephan Aßmus _InitWorkerThreads(); 2576d519fd1SStephan Aßmus } 2586d519fd1SStephan Aßmus 2596d519fd1SStephan Aßmus 26004c9d578SStephan Aßmus MainWindow::~MainWindow() 26104c9d578SStephan Aßmus { 26204c9d578SStephan Aßmus BPackageRoster().StopWatching(this); 26304c9d578SStephan Aßmus 26404c9d578SStephan Aßmus fTerminating = true; 26505bffa62SStephan Aßmus if (fModelWorker >= 0) 26604c9d578SStephan Aßmus wait_for_thread(fModelWorker, NULL); 26704c9d578SStephan Aßmus 26804c9d578SStephan Aßmus delete_sem(fPendingActionsSem); 26905bffa62SStephan Aßmus if (fPendingActionsWorker >= 0) 27004c9d578SStephan Aßmus wait_for_thread(fPendingActionsWorker, NULL); 27104c9d578SStephan Aßmus 27204c9d578SStephan Aßmus delete_sem(fPackageToPopulateSem); 27305bffa62SStephan Aßmus if (fPopulatePackageWorker >= 0) 27404c9d578SStephan Aßmus wait_for_thread(fPopulatePackageWorker, NULL); 275d5ef985eSStephan Aßmus 276d5ef985eSStephan Aßmus if (fScreenshotWindow != NULL && fScreenshotWindow->Lock()) 277d5ef985eSStephan Aßmus fScreenshotWindow->Quit(); 27804c9d578SStephan Aßmus } 27904c9d578SStephan Aßmus 28004c9d578SStephan Aßmus 28104c9d578SStephan Aßmus bool 28204c9d578SStephan Aßmus MainWindow::QuitRequested() 28304c9d578SStephan Aßmus { 28404c9d578SStephan Aßmus BMessage settings; 28504c9d578SStephan Aßmus StoreSettings(settings); 28604c9d578SStephan Aßmus 28704c9d578SStephan Aßmus BMessage message(MSG_MAIN_WINDOW_CLOSED); 28804c9d578SStephan Aßmus message.AddMessage("window settings", &settings); 28904c9d578SStephan Aßmus 29004c9d578SStephan Aßmus be_app->PostMessage(&message); 29104c9d578SStephan Aßmus 29204c9d578SStephan Aßmus return true; 29304c9d578SStephan Aßmus } 29404c9d578SStephan Aßmus 29504c9d578SStephan Aßmus 29604c9d578SStephan Aßmus void 29704c9d578SStephan Aßmus MainWindow::MessageReceived(BMessage* message) 29804c9d578SStephan Aßmus { 29904c9d578SStephan Aßmus switch (message->what) { 30004c9d578SStephan Aßmus case MSG_MODEL_WORKER_DONE: 30104c9d578SStephan Aßmus { 30204c9d578SStephan Aßmus fModelWorker = B_BAD_THREAD_ID; 30304c9d578SStephan Aßmus _AdoptModel(); 30404c9d578SStephan Aßmus fFilterView->AdoptModel(fModel); 30504c9d578SStephan Aßmus break; 30604c9d578SStephan Aßmus } 30704c9d578SStephan Aßmus case B_SIMPLE_DATA: 30804c9d578SStephan Aßmus case B_REFS_RECEIVED: 30904c9d578SStephan Aßmus // TODO: ? 31004c9d578SStephan Aßmus break; 31104c9d578SStephan Aßmus 31204c9d578SStephan Aßmus case B_PACKAGE_UPDATE: 31304c9d578SStephan Aßmus // TODO: We should do a more selective update depending on the 31404c9d578SStephan Aßmus // "event", "location", and "change count" fields! 31504c9d578SStephan Aßmus _StartRefreshWorker(false); 31604c9d578SStephan Aßmus break; 31704c9d578SStephan Aßmus 31804c9d578SStephan Aßmus case MSG_REFRESH_DEPOTS: 31904c9d578SStephan Aßmus _StartRefreshWorker(true); 32004c9d578SStephan Aßmus break; 32104c9d578SStephan Aßmus 32204c9d578SStephan Aßmus case MSG_LOG_IN: 3231bbda92dSStephan Aßmus _OpenLoginWindow(BMessage()); 32404c9d578SStephan Aßmus break; 32504c9d578SStephan Aßmus 3268f03a0f9SStephan Aßmus case MSG_LOG_OUT: 3278f03a0f9SStephan Aßmus fModel.SetUsername(""); 3288f03a0f9SStephan Aßmus break; 3298f03a0f9SStephan Aßmus 3308f03a0f9SStephan Aßmus case MSG_AUTHORIZATION_CHANGED: 3318f03a0f9SStephan Aßmus _UpdateAuthorization(); 3328f03a0f9SStephan Aßmus break; 3338f03a0f9SStephan Aßmus 3344fade61fSStephan Aßmus case MSG_SHOW_FEATURED_PACKAGES: 3354fade61fSStephan Aßmus { 3364fade61fSStephan Aßmus BAutolock locker(fModel.Lock()); 3374fade61fSStephan Aßmus fModel.SetShowFeaturedPackages( 3384fade61fSStephan Aßmus !fModel.ShowFeaturedPackages()); 3394fade61fSStephan Aßmus } 3404fade61fSStephan Aßmus _AdoptModel(); 3414fade61fSStephan Aßmus break; 3424fade61fSStephan Aßmus 343fdec4227SStephan Aßmus case MSG_SHOW_AVAILABLE_PACKAGES: 344fdec4227SStephan Aßmus { 345fdec4227SStephan Aßmus BAutolock locker(fModel.Lock()); 346fdec4227SStephan Aßmus fModel.SetShowAvailablePackages( 347fdec4227SStephan Aßmus !fModel.ShowAvailablePackages()); 348fdec4227SStephan Aßmus } 349fdec4227SStephan Aßmus _AdoptModel(); 350fdec4227SStephan Aßmus break; 351fdec4227SStephan Aßmus 352fdec4227SStephan Aßmus case MSG_SHOW_INSTALLED_PACKAGES: 353fdec4227SStephan Aßmus { 354fdec4227SStephan Aßmus BAutolock locker(fModel.Lock()); 355fdec4227SStephan Aßmus fModel.SetShowInstalledPackages( 356fdec4227SStephan Aßmus !fModel.ShowInstalledPackages()); 357fdec4227SStephan Aßmus } 358fdec4227SStephan Aßmus _AdoptModel(); 359fdec4227SStephan Aßmus break; 360fdec4227SStephan Aßmus 36104c9d578SStephan Aßmus case MSG_SHOW_SOURCE_PACKAGES: 36204c9d578SStephan Aßmus { 36304c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 36404c9d578SStephan Aßmus fModel.SetShowSourcePackages(!fModel.ShowSourcePackages()); 36504c9d578SStephan Aßmus } 36604c9d578SStephan Aßmus _AdoptModel(); 36704c9d578SStephan Aßmus break; 36804c9d578SStephan Aßmus 36904c9d578SStephan Aßmus case MSG_SHOW_DEVELOP_PACKAGES: 37004c9d578SStephan Aßmus { 37104c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 37204c9d578SStephan Aßmus fModel.SetShowDevelopPackages(!fModel.ShowDevelopPackages()); 37304c9d578SStephan Aßmus } 37404c9d578SStephan Aßmus _AdoptModel(); 37504c9d578SStephan Aßmus break; 37604c9d578SStephan Aßmus 37704c9d578SStephan Aßmus case MSG_PACKAGE_SELECTED: 37804c9d578SStephan Aßmus { 37972992391SStephan Aßmus BString name; 38072992391SStephan Aßmus if (message->FindString("name", &name) == B_OK) { 38175ba9dbfSStephan Aßmus BAutolock locker(fModel.Lock()); 38204c9d578SStephan Aßmus int count = fVisiblePackages.CountItems(); 38304c9d578SStephan Aßmus for (int i = 0; i < count; i++) { 38404c9d578SStephan Aßmus const PackageInfoRef& package 38504c9d578SStephan Aßmus = fVisiblePackages.ItemAtFast(i); 38672992391SStephan Aßmus if (package.Get() != NULL && package->Name() == name) { 38775ba9dbfSStephan Aßmus locker.Unlock(); 38804c9d578SStephan Aßmus _AdoptPackage(package); 38904c9d578SStephan Aßmus break; 39004c9d578SStephan Aßmus } 39104c9d578SStephan Aßmus } 39204c9d578SStephan Aßmus } else { 39304c9d578SStephan Aßmus _ClearPackage(); 39404c9d578SStephan Aßmus } 39504c9d578SStephan Aßmus break; 39604c9d578SStephan Aßmus } 39704c9d578SStephan Aßmus 39804c9d578SStephan Aßmus case MSG_CATEGORY_SELECTED: 39904c9d578SStephan Aßmus { 40004c9d578SStephan Aßmus BString name; 40104c9d578SStephan Aßmus if (message->FindString("name", &name) != B_OK) 40204c9d578SStephan Aßmus name = ""; 40304c9d578SStephan Aßmus { 40404c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 40504c9d578SStephan Aßmus fModel.SetCategory(name); 40604c9d578SStephan Aßmus } 40704c9d578SStephan Aßmus _AdoptModel(); 40804c9d578SStephan Aßmus break; 40904c9d578SStephan Aßmus } 41004c9d578SStephan Aßmus 41104c9d578SStephan Aßmus case MSG_DEPOT_SELECTED: 41204c9d578SStephan Aßmus { 41304c9d578SStephan Aßmus BString name; 41404c9d578SStephan Aßmus if (message->FindString("name", &name) != B_OK) 41504c9d578SStephan Aßmus name = ""; 41604c9d578SStephan Aßmus { 41704c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 41804c9d578SStephan Aßmus fModel.SetDepot(name); 41904c9d578SStephan Aßmus } 42004c9d578SStephan Aßmus _AdoptModel(); 42104c9d578SStephan Aßmus break; 42204c9d578SStephan Aßmus } 42304c9d578SStephan Aßmus 42404c9d578SStephan Aßmus case MSG_SEARCH_TERMS_MODIFIED: 42504c9d578SStephan Aßmus { 42604c9d578SStephan Aßmus // TODO: Do this with a delay! 42704c9d578SStephan Aßmus BString searchTerms; 42804c9d578SStephan Aßmus if (message->FindString("search terms", &searchTerms) != B_OK) 42904c9d578SStephan Aßmus searchTerms = ""; 43004c9d578SStephan Aßmus { 43104c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 43204c9d578SStephan Aßmus fModel.SetSearchTerms(searchTerms); 43304c9d578SStephan Aßmus } 43404c9d578SStephan Aßmus _AdoptModel(); 43504c9d578SStephan Aßmus break; 43604c9d578SStephan Aßmus } 43704c9d578SStephan Aßmus 438da651104SStephan Aßmus case MSG_PACKAGE_CHANGED: 43904c9d578SStephan Aßmus { 44004c9d578SStephan Aßmus PackageInfo* info; 44104c9d578SStephan Aßmus if (message->FindPointer("package", (void**)&info) == B_OK) { 44204c9d578SStephan Aßmus PackageInfoRef ref(info, true); 443da651104SStephan Aßmus uint32 changes; 444da651104SStephan Aßmus if (message->FindUInt32("changes", &changes) != B_OK) 445da651104SStephan Aßmus changes = 0; 446da651104SStephan Aßmus if ((changes & PKG_CHANGED_STATE) != 0) { 44704c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 44804c9d578SStephan Aßmus fModel.SetPackageState(ref, ref->State()); 44904c9d578SStephan Aßmus } 45057e51fffSStephan Aßmus 45157e51fffSStephan Aßmus // Asynchronous updates to the package information 45257e51fffSStephan Aßmus // can mean that the package needs to be added or 45357e51fffSStephan Aßmus // removed to/from the visible packages when the current 45457e51fffSStephan Aßmus // filter parameters are re-evaluated on this package. 45557e51fffSStephan Aßmus bool wasVisible = fVisiblePackages.Contains(ref); 45657e51fffSStephan Aßmus bool isVisible; 45757e51fffSStephan Aßmus { 458da651104SStephan Aßmus BAutolock locker(fModel.Lock()); 4590c6df5d5SStephan Aßmus // The package didn't get a chance yet to be in the 4600c6df5d5SStephan Aßmus // visible package list 46157e51fffSStephan Aßmus PackageList visiblePackages = fModel.CreatePackageList(); 46257e51fffSStephan Aßmus isVisible = visiblePackages.Contains(ref); 46357e51fffSStephan Aßmus 46457e51fffSStephan Aßmus // Transfer this single package, otherwise we miss 46557e51fffSStephan Aßmus // other packages if they appear or disappear along 46657e51fffSStephan Aßmus // with this one before receive a notification for 46757e51fffSStephan Aßmus // them. 46857e51fffSStephan Aßmus if (isVisible) { 46957e51fffSStephan Aßmus fVisiblePackages.Add(ref); 47057e51fffSStephan Aßmus } else if (wasVisible) 47157e51fffSStephan Aßmus fVisiblePackages.Remove(ref); 47257e51fffSStephan Aßmus } 47357e51fffSStephan Aßmus 47457e51fffSStephan Aßmus if (wasVisible != isVisible) { 47557e51fffSStephan Aßmus if (!isVisible) { 47657e51fffSStephan Aßmus fPackageListView->RemovePackage(ref); 47757e51fffSStephan Aßmus fFeaturedPackagesView->RemovePackage(ref); 47857e51fffSStephan Aßmus } else { 47957e51fffSStephan Aßmus fPackageListView->AddPackage(ref); 48057e51fffSStephan Aßmus if (ref->IsProminent()) 481da651104SStephan Aßmus fFeaturedPackagesView->AddPackage(ref); 482da651104SStephan Aßmus } 483da651104SStephan Aßmus } 48457e51fffSStephan Aßmus } 48504c9d578SStephan Aßmus break; 48604c9d578SStephan Aßmus } 48704c9d578SStephan Aßmus 48804c9d578SStephan Aßmus case MSG_RATE_PACKAGE: 4891bbda92dSStephan Aßmus _RatePackage(); 49004c9d578SStephan Aßmus break; 49104c9d578SStephan Aßmus 492d5ef985eSStephan Aßmus case MSG_SHOW_SCREENSHOT: 493d5ef985eSStephan Aßmus _ShowScreenshot(); 494d5ef985eSStephan Aßmus break; 495d5ef985eSStephan Aßmus 49604c9d578SStephan Aßmus default: 49704c9d578SStephan Aßmus BWindow::MessageReceived(message); 49804c9d578SStephan Aßmus break; 49904c9d578SStephan Aßmus } 50004c9d578SStephan Aßmus } 50104c9d578SStephan Aßmus 50204c9d578SStephan Aßmus 50304c9d578SStephan Aßmus void 50404c9d578SStephan Aßmus MainWindow::StoreSettings(BMessage& settings) const 50504c9d578SStephan Aßmus { 506*f7c2983eSAxel Dörfler settings.AddRect(_WindowFrameName(), Frame()); 507*f7c2983eSAxel Dörfler if (!fSinglePackageMode) { 50804c9d578SStephan Aßmus settings.AddRect("window frame", Frame()); 50904c9d578SStephan Aßmus 51004c9d578SStephan Aßmus BMessage columnSettings; 51104c9d578SStephan Aßmus fPackageListView->SaveState(&columnSettings); 51204c9d578SStephan Aßmus 51304c9d578SStephan Aßmus settings.AddMessage("column settings", &columnSettings); 51404c9d578SStephan Aßmus 5152997e05bSStephan Aßmus settings.AddBool("show featured packages", 5162997e05bSStephan Aßmus fModel.ShowFeaturedPackages()); 5172997e05bSStephan Aßmus settings.AddBool("show available packages", 5182997e05bSStephan Aßmus fModel.ShowAvailablePackages()); 5192997e05bSStephan Aßmus settings.AddBool("show installed packages", 5202997e05bSStephan Aßmus fModel.ShowInstalledPackages()); 52104c9d578SStephan Aßmus settings.AddBool("show develop packages", fModel.ShowDevelopPackages()); 52204c9d578SStephan Aßmus settings.AddBool("show source packages", fModel.ShowSourcePackages()); 5236d519fd1SStephan Aßmus } 5248f03a0f9SStephan Aßmus 5258f03a0f9SStephan Aßmus settings.AddString("username", fModel.Username()); 52604c9d578SStephan Aßmus } 52704c9d578SStephan Aßmus 52804c9d578SStephan Aßmus 52904c9d578SStephan Aßmus void 53004c9d578SStephan Aßmus MainWindow::PackageChanged(const PackageInfoEvent& event) 53104c9d578SStephan Aßmus { 532da651104SStephan Aßmus uint32 whatchedChanges = PKG_CHANGED_STATE | PKG_CHANGED_PROMINENCE; 533da651104SStephan Aßmus if ((event.Changes() & whatchedChanges) != 0) { 53404c9d578SStephan Aßmus PackageInfoRef ref(event.Package()); 535da651104SStephan Aßmus BMessage message(MSG_PACKAGE_CHANGED); 53604c9d578SStephan Aßmus message.AddPointer("package", ref.Get()); 537da651104SStephan Aßmus message.AddUInt32("changes", event.Changes()); 53804c9d578SStephan Aßmus ref.Detach(); 53904c9d578SStephan Aßmus // reference needs to be released by MessageReceived(); 54004c9d578SStephan Aßmus PostMessage(&message); 54104c9d578SStephan Aßmus } 54204c9d578SStephan Aßmus } 54304c9d578SStephan Aßmus 54404c9d578SStephan Aßmus 54504c9d578SStephan Aßmus status_t 54604c9d578SStephan Aßmus MainWindow::SchedulePackageActions(PackageActionList& list) 54704c9d578SStephan Aßmus { 54804c9d578SStephan Aßmus AutoLocker<BLocker> lock(&fPendingActionsLock); 54904c9d578SStephan Aßmus for (int32 i = 0; i < list.CountItems(); i++) { 55004c9d578SStephan Aßmus if (!fPendingActions.Add(list.ItemAtFast(i))) 55104c9d578SStephan Aßmus return B_NO_MEMORY; 55204c9d578SStephan Aßmus } 55304c9d578SStephan Aßmus 55404c9d578SStephan Aßmus return release_sem_etc(fPendingActionsSem, list.CountItems(), 0); 55504c9d578SStephan Aßmus } 55604c9d578SStephan Aßmus 55704c9d578SStephan Aßmus 55804c9d578SStephan Aßmus Model* 55904c9d578SStephan Aßmus MainWindow::GetModel() 56004c9d578SStephan Aßmus { 56104c9d578SStephan Aßmus return &fModel; 56204c9d578SStephan Aßmus } 56304c9d578SStephan Aßmus 56404c9d578SStephan Aßmus 56504c9d578SStephan Aßmus void 56604c9d578SStephan Aßmus MainWindow::_BuildMenu(BMenuBar* menuBar) 56704c9d578SStephan Aßmus { 56804c9d578SStephan Aßmus BMenu* menu = new BMenu(B_TRANSLATE("Tools")); 56904c9d578SStephan Aßmus menu->AddItem(new BMenuItem(B_TRANSLATE("Refresh depots"), 57004c9d578SStephan Aßmus new BMessage(MSG_REFRESH_DEPOTS))); 571e0a26dceSStephan Aßmus 57204c9d578SStephan Aßmus menuBar->AddItem(menu); 57304c9d578SStephan Aßmus 5744fade61fSStephan Aßmus menu = new BMenu(B_TRANSLATE("Show")); 5754fade61fSStephan Aßmus 5764fade61fSStephan Aßmus fShowFeaturedPackagesItem = new BMenuItem( 5774fade61fSStephan Aßmus B_TRANSLATE("Only featured packages"), 5784fade61fSStephan Aßmus new BMessage(MSG_SHOW_FEATURED_PACKAGES)); 5794fade61fSStephan Aßmus menu->AddItem(fShowFeaturedPackagesItem); 5804fade61fSStephan Aßmus 5814fade61fSStephan Aßmus menu->AddSeparatorItem(); 582fdec4227SStephan Aßmus 583fdec4227SStephan Aßmus fShowAvailablePackagesItem = new BMenuItem( 5844fade61fSStephan Aßmus B_TRANSLATE("Available packages"), 585fdec4227SStephan Aßmus new BMessage(MSG_SHOW_AVAILABLE_PACKAGES)); 586fdec4227SStephan Aßmus menu->AddItem(fShowAvailablePackagesItem); 587fdec4227SStephan Aßmus 588fdec4227SStephan Aßmus fShowInstalledPackagesItem = new BMenuItem( 5894fade61fSStephan Aßmus B_TRANSLATE("Installed packages"), 590fdec4227SStephan Aßmus new BMessage(MSG_SHOW_INSTALLED_PACKAGES)); 591fdec4227SStephan Aßmus menu->AddItem(fShowInstalledPackagesItem); 592fdec4227SStephan Aßmus 593fdec4227SStephan Aßmus menu->AddSeparatorItem(); 594fdec4227SStephan Aßmus 595fdec4227SStephan Aßmus fShowDevelopPackagesItem = new BMenuItem( 5964fade61fSStephan Aßmus B_TRANSLATE("Develop packages"), 597fdec4227SStephan Aßmus new BMessage(MSG_SHOW_DEVELOP_PACKAGES)); 598fdec4227SStephan Aßmus menu->AddItem(fShowDevelopPackagesItem); 599fdec4227SStephan Aßmus 600fdec4227SStephan Aßmus fShowSourcePackagesItem = new BMenuItem( 6014fade61fSStephan Aßmus B_TRANSLATE("Source packages"), 602fdec4227SStephan Aßmus new BMessage(MSG_SHOW_SOURCE_PACKAGES)); 603fdec4227SStephan Aßmus menu->AddItem(fShowSourcePackagesItem); 604fdec4227SStephan Aßmus 605fdec4227SStephan Aßmus menuBar->AddItem(menu); 60604c9d578SStephan Aßmus } 60704c9d578SStephan Aßmus 60804c9d578SStephan Aßmus 60904c9d578SStephan Aßmus void 610e0a26dceSStephan Aßmus MainWindow::_BuildUserMenu(BMenuBar* menuBar) 611e0a26dceSStephan Aßmus { 612e0a26dceSStephan Aßmus fUserMenu = new BMenu(B_TRANSLATE("Not logged in")); 613e0a26dceSStephan Aßmus 614e0a26dceSStephan Aßmus fLogInItem = new BMenuItem(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS), 615e0a26dceSStephan Aßmus new BMessage(MSG_LOG_IN)); 616e0a26dceSStephan Aßmus fUserMenu->AddItem(fLogInItem); 617e0a26dceSStephan Aßmus 618e0a26dceSStephan Aßmus fLogOutItem = new BMenuItem(B_TRANSLATE("Log out"), 619e0a26dceSStephan Aßmus new BMessage(MSG_LOG_OUT)); 620e0a26dceSStephan Aßmus fUserMenu->AddItem(fLogOutItem); 621e0a26dceSStephan Aßmus 622e0a26dceSStephan Aßmus menuBar->AddItem(fUserMenu); 623e0a26dceSStephan Aßmus } 624e0a26dceSStephan Aßmus 625e0a26dceSStephan Aßmus 626e0a26dceSStephan Aßmus void 627*f7c2983eSAxel Dörfler MainWindow::_RestoreUserName(const BMessage& settings) 628*f7c2983eSAxel Dörfler { 629*f7c2983eSAxel Dörfler BString username; 630*f7c2983eSAxel Dörfler if (settings.FindString("username", &username) == B_OK 631*f7c2983eSAxel Dörfler && username.Length() > 0) { 632*f7c2983eSAxel Dörfler fModel.SetUsername(username); 633*f7c2983eSAxel Dörfler } 634*f7c2983eSAxel Dörfler } 635*f7c2983eSAxel Dörfler 636*f7c2983eSAxel Dörfler 637*f7c2983eSAxel Dörfler const char* 638*f7c2983eSAxel Dörfler MainWindow::_WindowFrameName() const 639*f7c2983eSAxel Dörfler { 640*f7c2983eSAxel Dörfler if (fSinglePackageMode) 641*f7c2983eSAxel Dörfler return "small window frame"; 642*f7c2983eSAxel Dörfler 643*f7c2983eSAxel Dörfler return "window frame"; 644*f7c2983eSAxel Dörfler } 645*f7c2983eSAxel Dörfler 646*f7c2983eSAxel Dörfler 647*f7c2983eSAxel Dörfler void 648*f7c2983eSAxel Dörfler MainWindow::_RestoreWindowFrame(const BMessage& settings) 649*f7c2983eSAxel Dörfler { 650*f7c2983eSAxel Dörfler BRect frame = Frame(); 651*f7c2983eSAxel Dörfler 652*f7c2983eSAxel Dörfler BRect windowFrame; 653*f7c2983eSAxel Dörfler bool fromSettings = false; 654*f7c2983eSAxel Dörfler if (settings.FindRect(_WindowFrameName(), &windowFrame) == B_OK) { 655*f7c2983eSAxel Dörfler frame = windowFrame; 656*f7c2983eSAxel Dörfler fromSettings = true; 657*f7c2983eSAxel Dörfler } else if (!fSinglePackageMode) { 658*f7c2983eSAxel Dörfler // Resize to occupy a certain screen size 659*f7c2983eSAxel Dörfler BRect screenFrame = BScreen(this).Frame(); 660*f7c2983eSAxel Dörfler float width = frame.Width(); 661*f7c2983eSAxel Dörfler float height = frame.Height(); 662*f7c2983eSAxel Dörfler if (width < screenFrame.Width() * .666f 663*f7c2983eSAxel Dörfler && height < screenFrame.Height() * .666f) { 664*f7c2983eSAxel Dörfler frame.bottom = frame.top + screenFrame.Height() * .666f; 665*f7c2983eSAxel Dörfler frame.right = frame.left 666*f7c2983eSAxel Dörfler + std::min(screenFrame.Width() * .666f, height * 7 / 5); 667*f7c2983eSAxel Dörfler } 668*f7c2983eSAxel Dörfler } 669*f7c2983eSAxel Dörfler 670*f7c2983eSAxel Dörfler MoveTo(frame.LeftTop()); 671*f7c2983eSAxel Dörfler ResizeTo(frame.Width(), frame.Height()); 672*f7c2983eSAxel Dörfler 673*f7c2983eSAxel Dörfler if (fromSettings) 674*f7c2983eSAxel Dörfler MoveOnScreen(true); 675*f7c2983eSAxel Dörfler else 676*f7c2983eSAxel Dörfler CenterOnScreen(); 677*f7c2983eSAxel Dörfler } 678*f7c2983eSAxel Dörfler 679*f7c2983eSAxel Dörfler 680*f7c2983eSAxel Dörfler void 68163975654SStephan Aßmus MainWindow::_InitWorkerThreads() 68263975654SStephan Aßmus { 68363975654SStephan Aßmus fPendingActionsSem = create_sem(0, "PendingPackageActions"); 68463975654SStephan Aßmus if (fPendingActionsSem >= 0) { 68563975654SStephan Aßmus fPendingActionsWorker = spawn_thread(&_PackageActionWorker, 68663975654SStephan Aßmus "Planet Express", B_NORMAL_PRIORITY, this); 68763975654SStephan Aßmus if (fPendingActionsWorker >= 0) 68863975654SStephan Aßmus resume_thread(fPendingActionsWorker); 68909f82905SStephan Aßmus } else 69009f82905SStephan Aßmus fPendingActionsWorker = -1; 69163975654SStephan Aßmus 69263975654SStephan Aßmus fPackageToPopulateSem = create_sem(0, "PopulatePackage"); 69363975654SStephan Aßmus if (fPackageToPopulateSem >= 0) { 69463975654SStephan Aßmus fPopulatePackageWorker = spawn_thread(&_PopulatePackageWorker, 69563975654SStephan Aßmus "Package Populator", B_NORMAL_PRIORITY, this); 69663975654SStephan Aßmus if (fPopulatePackageWorker >= 0) 69763975654SStephan Aßmus resume_thread(fPopulatePackageWorker); 69809f82905SStephan Aßmus } else 69909f82905SStephan Aßmus fPopulatePackageWorker = -1; 70063975654SStephan Aßmus } 70163975654SStephan Aßmus 70263975654SStephan Aßmus 70363975654SStephan Aßmus void 70404c9d578SStephan Aßmus MainWindow::_AdoptModel() 70504c9d578SStephan Aßmus { 70604c9d578SStephan Aßmus fVisiblePackages = fModel.CreatePackageList(); 70704c9d578SStephan Aßmus 7084b930ccaSStephan Aßmus fFeaturedPackagesView->Clear(); 70904c9d578SStephan Aßmus fPackageListView->Clear(); 71004c9d578SStephan Aßmus for (int32 i = 0; i < fVisiblePackages.CountItems(); i++) { 71104c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 7124b930ccaSStephan Aßmus 7134b930ccaSStephan Aßmus const PackageInfoRef& package = fVisiblePackages.ItemAtFast(i); 7144b930ccaSStephan Aßmus fPackageListView->AddPackage(package); 7154b930ccaSStephan Aßmus 7164fade61fSStephan Aßmus if (package->IsProminent()) 7174b930ccaSStephan Aßmus fFeaturedPackagesView->AddPackage(package); 71804c9d578SStephan Aßmus } 71904c9d578SStephan Aßmus 72004c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 7214fade61fSStephan Aßmus fShowFeaturedPackagesItem->SetMarked(fModel.ShowFeaturedPackages()); 7224fade61fSStephan Aßmus fShowFeaturedPackagesItem->SetEnabled(fModel.SearchTerms() == ""); 723fdec4227SStephan Aßmus fShowAvailablePackagesItem->SetMarked(fModel.ShowAvailablePackages()); 724fdec4227SStephan Aßmus fShowInstalledPackagesItem->SetMarked(fModel.ShowInstalledPackages()); 725fdec4227SStephan Aßmus fShowSourcePackagesItem->SetMarked(fModel.ShowSourcePackages()); 726fdec4227SStephan Aßmus fShowDevelopPackagesItem->SetMarked(fModel.ShowDevelopPackages()); 727da651104SStephan Aßmus 7284fade61fSStephan Aßmus if (fModel.ShowFeaturedPackages() && fModel.SearchTerms() == "") 729da651104SStephan Aßmus fListLayout->SetVisibleItem((int32)0); 7304fade61fSStephan Aßmus else 7314fade61fSStephan Aßmus fListLayout->SetVisibleItem((int32)1); 7321986ab9fSStephan Aßmus 7331986ab9fSStephan Aßmus // Maintain selection 7341986ab9fSStephan Aßmus const PackageInfoRef& selectedPackage = fPackageInfoView->Package(); 7351986ab9fSStephan Aßmus fFeaturedPackagesView->SelectPackage(selectedPackage); 7361986ab9fSStephan Aßmus fPackageListView->SelectPackage(selectedPackage); 73793a7cf94SStephan Aßmus 73893a7cf94SStephan Aßmus if (!fVisiblePackages.Contains(fPackageInfoView->Package())) 73993a7cf94SStephan Aßmus fPackageInfoView->Clear(); 74004c9d578SStephan Aßmus } 74104c9d578SStephan Aßmus 74204c9d578SStephan Aßmus 74304c9d578SStephan Aßmus void 74404c9d578SStephan Aßmus MainWindow::_AdoptPackage(const PackageInfoRef& package) 74504c9d578SStephan Aßmus { 74675ba9dbfSStephan Aßmus { 74775ba9dbfSStephan Aßmus BAutolock locker(fModel.Lock()); 74804c9d578SStephan Aßmus fPackageInfoView->SetPackage(package); 7491986ab9fSStephan Aßmus 750664372abSStephan Aßmus if (fFeaturedPackagesView != NULL) 751664372abSStephan Aßmus fFeaturedPackagesView->SelectPackage(package); 7521986ab9fSStephan Aßmus if (fPackageListView != NULL) 7531986ab9fSStephan Aßmus fPackageListView->SelectPackage(package); 75475ba9dbfSStephan Aßmus } 75504c9d578SStephan Aßmus 75604c9d578SStephan Aßmus // Trigger asynchronous package population from the web-app 75704c9d578SStephan Aßmus { 75804c9d578SStephan Aßmus AutoLocker<BLocker> lock(&fPackageToPopulateLock); 75904c9d578SStephan Aßmus fPackageToPopulate = package; 76004c9d578SStephan Aßmus } 76104c9d578SStephan Aßmus release_sem_etc(fPackageToPopulateSem, 1, 0); 76204c9d578SStephan Aßmus } 76304c9d578SStephan Aßmus 76404c9d578SStephan Aßmus 76504c9d578SStephan Aßmus void 76604c9d578SStephan Aßmus MainWindow::_ClearPackage() 76704c9d578SStephan Aßmus { 76804c9d578SStephan Aßmus fPackageInfoView->Clear(); 76904c9d578SStephan Aßmus } 77004c9d578SStephan Aßmus 77104c9d578SStephan Aßmus 77204c9d578SStephan Aßmus void 77304c9d578SStephan Aßmus MainWindow::_RefreshRepositories(bool force) 77404c9d578SStephan Aßmus { 775448f707cSStephan Aßmus if (fSinglePackageMode) 776448f707cSStephan Aßmus return; 777448f707cSStephan Aßmus 77804c9d578SStephan Aßmus BPackageRoster roster; 77904c9d578SStephan Aßmus BStringList repositoryNames; 78004c9d578SStephan Aßmus 78104c9d578SStephan Aßmus status_t result = roster.GetRepositoryNames(repositoryNames); 78204c9d578SStephan Aßmus if (result != B_OK) 78304c9d578SStephan Aßmus return; 78404c9d578SStephan Aßmus 78504c9d578SStephan Aßmus DecisionProvider decisionProvider; 78604c9d578SStephan Aßmus JobStateListener listener; 78704c9d578SStephan Aßmus BContext context(decisionProvider, listener); 78804c9d578SStephan Aßmus 78904c9d578SStephan Aßmus BRepositoryCache cache; 79004c9d578SStephan Aßmus for (int32 i = 0; i < repositoryNames.CountStrings(); ++i) { 79104c9d578SStephan Aßmus const BString& repoName = repositoryNames.StringAt(i); 79204c9d578SStephan Aßmus BRepositoryConfig repoConfig; 79304c9d578SStephan Aßmus result = roster.GetRepositoryConfig(repoName, &repoConfig); 79404c9d578SStephan Aßmus if (result != B_OK) { 79504c9d578SStephan Aßmus // TODO: notify user 79604c9d578SStephan Aßmus continue; 79704c9d578SStephan Aßmus } 79804c9d578SStephan Aßmus 79904c9d578SStephan Aßmus if (roster.GetRepositoryCache(repoName, &cache) != B_OK || force) { 80004c9d578SStephan Aßmus try { 80104c9d578SStephan Aßmus BRefreshRepositoryRequest refreshRequest(context, repoConfig); 80204c9d578SStephan Aßmus 80304c9d578SStephan Aßmus result = refreshRequest.Process(); 80404c9d578SStephan Aßmus } catch (BFatalErrorException ex) { 80504c9d578SStephan Aßmus BString message(B_TRANSLATE("An error occurred while " 80604c9d578SStephan Aßmus "refreshing the repository: %error% (%details%)")); 80704c9d578SStephan Aßmus message.ReplaceFirst("%error%", ex.Message()); 80804c9d578SStephan Aßmus message.ReplaceFirst("%details%", ex.Details()); 80904c9d578SStephan Aßmus _NotifyUser("Error", message.String()); 81004c9d578SStephan Aßmus } catch (BException ex) { 81104c9d578SStephan Aßmus BString message(B_TRANSLATE("An error occurred while " 81204c9d578SStephan Aßmus "refreshing the repository: %error%")); 81304c9d578SStephan Aßmus message.ReplaceFirst("%error%", ex.Message()); 81404c9d578SStephan Aßmus _NotifyUser("Error", message.String()); 81504c9d578SStephan Aßmus } 81604c9d578SStephan Aßmus } 81704c9d578SStephan Aßmus } 81804c9d578SStephan Aßmus } 81904c9d578SStephan Aßmus 82004c9d578SStephan Aßmus 82104c9d578SStephan Aßmus void 8227b2c59b9SStephan Aßmus MainWindow::_RefreshPackageList(bool force) 82304c9d578SStephan Aßmus { 824448f707cSStephan Aßmus if (fSinglePackageMode) 825448f707cSStephan Aßmus return; 826448f707cSStephan Aßmus 82704c9d578SStephan Aßmus BPackageRoster roster; 82804c9d578SStephan Aßmus BStringList repositoryNames; 82904c9d578SStephan Aßmus 83004c9d578SStephan Aßmus status_t result = roster.GetRepositoryNames(repositoryNames); 83104c9d578SStephan Aßmus if (result != B_OK) 83204c9d578SStephan Aßmus return; 83304c9d578SStephan Aßmus 83404c9d578SStephan Aßmus DepotInfoMap depots; 83504c9d578SStephan Aßmus for (int32 i = 0; i < repositoryNames.CountStrings(); i++) { 83604c9d578SStephan Aßmus const BString& repoName = repositoryNames.StringAt(i); 83704c9d578SStephan Aßmus depots[repoName] = DepotInfo(repoName); 83804c9d578SStephan Aßmus } 83904c9d578SStephan Aßmus 84004c9d578SStephan Aßmus PackageManager manager(B_PACKAGE_INSTALLATION_LOCATION_HOME); 84104c9d578SStephan Aßmus try { 84204c9d578SStephan Aßmus manager.Init(PackageManager::B_ADD_INSTALLED_REPOSITORIES 84304c9d578SStephan Aßmus | PackageManager::B_ADD_REMOTE_REPOSITORIES); 84404c9d578SStephan Aßmus } catch (BException ex) { 84504c9d578SStephan Aßmus BString message(B_TRANSLATE("An error occurred while " 84604c9d578SStephan Aßmus "initializing the package manager: %message%")); 84704c9d578SStephan Aßmus message.ReplaceFirst("%message%", ex.Message()); 84804c9d578SStephan Aßmus _NotifyUser("Error", message.String()); 84904c9d578SStephan Aßmus return; 85004c9d578SStephan Aßmus } 85104c9d578SStephan Aßmus 85204c9d578SStephan Aßmus BObjectList<BSolverPackage> packages; 85304c9d578SStephan Aßmus result = manager.Solver()->FindPackages("", 85404c9d578SStephan Aßmus BSolver::B_FIND_CASE_INSENSITIVE | BSolver::B_FIND_IN_NAME 85504c9d578SStephan Aßmus | BSolver::B_FIND_IN_SUMMARY | BSolver::B_FIND_IN_DESCRIPTION 85604c9d578SStephan Aßmus | BSolver::B_FIND_IN_PROVIDES, 85704c9d578SStephan Aßmus packages); 85804c9d578SStephan Aßmus if (result != B_OK) { 85904c9d578SStephan Aßmus BString message(B_TRANSLATE("An error occurred while " 86004c9d578SStephan Aßmus "obtaining the package list: %message%")); 86104c9d578SStephan Aßmus message.ReplaceFirst("%message%", strerror(result)); 86204c9d578SStephan Aßmus _NotifyUser("Error", message.String()); 86304c9d578SStephan Aßmus return; 86404c9d578SStephan Aßmus } 86504c9d578SStephan Aßmus 86604c9d578SStephan Aßmus if (packages.IsEmpty()) 86704c9d578SStephan Aßmus return; 86804c9d578SStephan Aßmus 86904c9d578SStephan Aßmus PackageInfoMap foundPackages; 87004c9d578SStephan Aßmus // if a given package is installed locally, we will potentially 87104c9d578SStephan Aßmus // get back multiple entries, one for each local installation 87204c9d578SStephan Aßmus // location, and one for each remote repository the package 87304c9d578SStephan Aßmus // is available in. The above map is used to ensure that in such 87404c9d578SStephan Aßmus // cases we consolidate the information, rather than displaying 87504c9d578SStephan Aßmus // duplicates 87604c9d578SStephan Aßmus PackageInfoMap remotePackages; 87704c9d578SStephan Aßmus // any package that we find in a remote repository goes in this map. 87804c9d578SStephan Aßmus // this is later used to discern which packages came from a local 87904c9d578SStephan Aßmus // installation only, as those must be handled a bit differently 88004c9d578SStephan Aßmus // upon uninstallation, since we'd no longer be able to pull them 88104c9d578SStephan Aßmus // down remotely. 88204c9d578SStephan Aßmus BStringList systemFlaggedPackages; 88304c9d578SStephan Aßmus // any packages flagged as a system package are added to this list. 88404c9d578SStephan Aßmus // such packages cannot be uninstalled, nor can any of their deps. 88504c9d578SStephan Aßmus PackageInfoMap systemInstalledPackages; 88604c9d578SStephan Aßmus // any packages installed in system are added to this list. 88704c9d578SStephan Aßmus // This is later used for dependency resolution of the actual 88804c9d578SStephan Aßmus // system packages in order to compute the list of protected 88904c9d578SStephan Aßmus // dependencies indicated above. 89004c9d578SStephan Aßmus 89104c9d578SStephan Aßmus for (int32 i = 0; i < packages.CountItems(); i++) { 89204c9d578SStephan Aßmus BSolverPackage* package = packages.ItemAt(i); 89304c9d578SStephan Aßmus const BPackageInfo& repoPackageInfo = package->Info(); 89404c9d578SStephan Aßmus PackageInfoRef modelInfo; 89504c9d578SStephan Aßmus PackageInfoMap::iterator it = foundPackages.find( 89604c9d578SStephan Aßmus repoPackageInfo.Name()); 89704c9d578SStephan Aßmus if (it != foundPackages.end()) 89804c9d578SStephan Aßmus modelInfo.SetTo(it->second); 89904c9d578SStephan Aßmus else { 90004c9d578SStephan Aßmus // Add new package info 9016d519fd1SStephan Aßmus modelInfo.SetTo(new(std::nothrow) PackageInfo(repoPackageInfo), 90204c9d578SStephan Aßmus true); 90304c9d578SStephan Aßmus 90404c9d578SStephan Aßmus if (modelInfo.Get() == NULL) 90504c9d578SStephan Aßmus return; 90604c9d578SStephan Aßmus 90704c9d578SStephan Aßmus foundPackages[repoPackageInfo.Name()] = modelInfo; 90804c9d578SStephan Aßmus } 90904c9d578SStephan Aßmus 91004c9d578SStephan Aßmus modelInfo->AddListener(this); 91104c9d578SStephan Aßmus 91204c9d578SStephan Aßmus BSolverRepository* repository = package->Repository(); 91304c9d578SStephan Aßmus if (dynamic_cast<BPackageManager::RemoteRepository*>(repository) 91404c9d578SStephan Aßmus != NULL) { 91504c9d578SStephan Aßmus depots[repository->Name()].AddPackage(modelInfo); 91672992391SStephan Aßmus remotePackages[modelInfo->Name()] = modelInfo; 91704c9d578SStephan Aßmus } else { 91804c9d578SStephan Aßmus if (repository == static_cast<const BSolverRepository*>( 91904c9d578SStephan Aßmus manager.SystemRepository())) { 92004c9d578SStephan Aßmus modelInfo->AddInstallationLocation( 92104c9d578SStephan Aßmus B_PACKAGE_INSTALLATION_LOCATION_SYSTEM); 92204c9d578SStephan Aßmus if (!modelInfo->IsSystemPackage()) { 92304c9d578SStephan Aßmus systemInstalledPackages[repoPackageInfo.FileName()] 92404c9d578SStephan Aßmus = modelInfo; 92504c9d578SStephan Aßmus } 92604c9d578SStephan Aßmus } else if (repository == static_cast<const BSolverRepository*>( 92704c9d578SStephan Aßmus manager.HomeRepository())) { 92804c9d578SStephan Aßmus modelInfo->AddInstallationLocation( 92904c9d578SStephan Aßmus B_PACKAGE_INSTALLATION_LOCATION_HOME); 93004c9d578SStephan Aßmus } 93104c9d578SStephan Aßmus } 93204c9d578SStephan Aßmus 93304c9d578SStephan Aßmus if (modelInfo->IsSystemPackage()) 93404c9d578SStephan Aßmus systemFlaggedPackages.Add(repoPackageInfo.FileName()); 93504c9d578SStephan Aßmus } 93604c9d578SStephan Aßmus 9377b2c59b9SStephan Aßmus bool wasEmpty = fModel.Depots().IsEmpty(); 9387b2c59b9SStephan Aßmus if (force || wasEmpty) 9396b147523SStephan Aßmus fModel.StopPopulatingAllPackages(); 94004c9d578SStephan Aßmus 9416b147523SStephan Aßmus BAutolock lock(fModel.Lock()); 9427b2c59b9SStephan Aßmus 9437b2c59b9SStephan Aßmus if (force) 94404c9d578SStephan Aßmus fModel.Clear(); 94504c9d578SStephan Aßmus 94604c9d578SStephan Aßmus // filter remote packages from the found list 94704c9d578SStephan Aßmus // any packages remaining will be locally installed packages 94804c9d578SStephan Aßmus // that weren't acquired from a repository 94904c9d578SStephan Aßmus for (PackageInfoMap::iterator it = remotePackages.begin(); 95004c9d578SStephan Aßmus it != remotePackages.end(); it++) { 95104c9d578SStephan Aßmus foundPackages.erase(it->first); 95204c9d578SStephan Aßmus } 95304c9d578SStephan Aßmus 95404c9d578SStephan Aßmus if (!foundPackages.empty()) { 95504c9d578SStephan Aßmus BString repoName = B_TRANSLATE("Local"); 95604c9d578SStephan Aßmus depots[repoName] = DepotInfo(repoName); 95704c9d578SStephan Aßmus DepotInfoMap::iterator depot = depots.find(repoName); 95804c9d578SStephan Aßmus for (PackageInfoMap::iterator it = foundPackages.begin(); 95904c9d578SStephan Aßmus it != foundPackages.end(); ++it) { 96004c9d578SStephan Aßmus depot->second.AddPackage(it->second); 96104c9d578SStephan Aßmus } 96204c9d578SStephan Aßmus } 96304c9d578SStephan Aßmus 96404c9d578SStephan Aßmus for (DepotInfoMap::iterator it = depots.begin(); it != depots.end(); it++) { 9657b2c59b9SStephan Aßmus if (fModel.HasDepot(it->second.Name())) 9667b2c59b9SStephan Aßmus fModel.SyncDepot(it->second); 9677b2c59b9SStephan Aßmus else 96804c9d578SStephan Aßmus fModel.AddDepot(it->second); 96904c9d578SStephan Aßmus } 97004c9d578SStephan Aßmus 97104c9d578SStephan Aßmus // start retrieving package icons and average ratings 9727b2c59b9SStephan Aßmus if (force || wasEmpty) 97304c9d578SStephan Aßmus fModel.PopulateAllPackages(); 97404c9d578SStephan Aßmus 97504c9d578SStephan Aßmus // compute the OS package dependencies 97604c9d578SStephan Aßmus try { 97704c9d578SStephan Aßmus // create the solver 97804c9d578SStephan Aßmus BSolver* solver; 97904c9d578SStephan Aßmus status_t error = BSolver::Create(solver); 98004c9d578SStephan Aßmus if (error != B_OK) 98104c9d578SStephan Aßmus throw BFatalErrorException(error, "Failed to create solver."); 98204c9d578SStephan Aßmus 98304c9d578SStephan Aßmus ObjectDeleter<BSolver> solverDeleter(solver); 98404c9d578SStephan Aßmus BPath systemPath; 98504c9d578SStephan Aßmus error = find_directory(B_SYSTEM_PACKAGES_DIRECTORY, &systemPath); 98604c9d578SStephan Aßmus if (error != B_OK) { 98704c9d578SStephan Aßmus throw BFatalErrorException(error, 98804c9d578SStephan Aßmus "Unable to retrieve system packages directory."); 98904c9d578SStephan Aßmus } 99004c9d578SStephan Aßmus 99104c9d578SStephan Aßmus // add the "installed" repository with the given packages 99204c9d578SStephan Aßmus BSolverRepository installedRepository; 99304c9d578SStephan Aßmus { 99404c9d578SStephan Aßmus BRepositoryBuilder installedRepositoryBuilder(installedRepository, 99504c9d578SStephan Aßmus "installed"); 99604c9d578SStephan Aßmus for (int32 i = 0; i < systemFlaggedPackages.CountStrings(); i++) { 99704c9d578SStephan Aßmus BPath packagePath(systemPath); 99804c9d578SStephan Aßmus packagePath.Append(systemFlaggedPackages.StringAt(i)); 99904c9d578SStephan Aßmus installedRepositoryBuilder.AddPackage(packagePath.Path()); 100004c9d578SStephan Aßmus } 100104c9d578SStephan Aßmus installedRepositoryBuilder.AddToSolver(solver, true); 100204c9d578SStephan Aßmus } 100304c9d578SStephan Aßmus 100404c9d578SStephan Aßmus // add system repository 100504c9d578SStephan Aßmus BSolverRepository systemRepository; 100604c9d578SStephan Aßmus { 100704c9d578SStephan Aßmus BRepositoryBuilder systemRepositoryBuilder(systemRepository, 100804c9d578SStephan Aßmus "system"); 100904c9d578SStephan Aßmus for (PackageInfoMap::iterator it = systemInstalledPackages.begin(); 101004c9d578SStephan Aßmus it != systemInstalledPackages.end(); it++) { 101104c9d578SStephan Aßmus BPath packagePath(systemPath); 101204c9d578SStephan Aßmus packagePath.Append(it->first); 101304c9d578SStephan Aßmus systemRepositoryBuilder.AddPackage(packagePath.Path()); 101404c9d578SStephan Aßmus } 101504c9d578SStephan Aßmus systemRepositoryBuilder.AddToSolver(solver, false); 101604c9d578SStephan Aßmus } 101704c9d578SStephan Aßmus 101804c9d578SStephan Aßmus // solve 101904c9d578SStephan Aßmus error = solver->VerifyInstallation(); 102004c9d578SStephan Aßmus if (error != B_OK) { 102104c9d578SStephan Aßmus throw BFatalErrorException(error, "Failed to compute packages to " 102204c9d578SStephan Aßmus "install."); 102304c9d578SStephan Aßmus } 102404c9d578SStephan Aßmus 102504c9d578SStephan Aßmus BSolverResult solverResult; 102604c9d578SStephan Aßmus error = solver->GetResult(solverResult); 102704c9d578SStephan Aßmus if (error != B_OK) { 102804c9d578SStephan Aßmus throw BFatalErrorException(error, "Failed to retrieve system " 102904c9d578SStephan Aßmus "package dependency list."); 103004c9d578SStephan Aßmus } 103104c9d578SStephan Aßmus 103204c9d578SStephan Aßmus for (int32 i = 0; const BSolverResultElement* element 103304c9d578SStephan Aßmus = solverResult.ElementAt(i); i++) { 103404c9d578SStephan Aßmus BSolverPackage* package = element->Package(); 103504c9d578SStephan Aßmus if (element->Type() == BSolverResultElement::B_TYPE_INSTALL) { 103604c9d578SStephan Aßmus PackageInfoMap::iterator it = systemInstalledPackages.find( 103704c9d578SStephan Aßmus package->Info().FileName()); 103804c9d578SStephan Aßmus if (it != systemInstalledPackages.end()) 103904c9d578SStephan Aßmus it->second->SetSystemDependency(true); 104004c9d578SStephan Aßmus } 104104c9d578SStephan Aßmus } 104204c9d578SStephan Aßmus } catch (BFatalErrorException ex) { 104304c9d578SStephan Aßmus printf("Fatal exception occurred while resolving system dependencies: " 104404c9d578SStephan Aßmus "%s, details: %s\n", strerror(ex.Error()), ex.Details().String()); 104504c9d578SStephan Aßmus } catch (BNothingToDoException) { 104604c9d578SStephan Aßmus // do nothing 104704c9d578SStephan Aßmus } catch (BException ex) { 104804c9d578SStephan Aßmus printf("Exception occurred while resolving system dependencies: %s\n", 104904c9d578SStephan Aßmus ex.Message().String()); 105004c9d578SStephan Aßmus } catch (...) { 105104c9d578SStephan Aßmus printf("Unknown exception occurred while resolving system " 105204c9d578SStephan Aßmus "dependencies.\n"); 105304c9d578SStephan Aßmus } 105404c9d578SStephan Aßmus } 105504c9d578SStephan Aßmus 105604c9d578SStephan Aßmus 105704c9d578SStephan Aßmus void 105804c9d578SStephan Aßmus MainWindow::_StartRefreshWorker(bool force) 105904c9d578SStephan Aßmus { 106004c9d578SStephan Aßmus if (fModelWorker != B_BAD_THREAD_ID) 106104c9d578SStephan Aßmus return; 106204c9d578SStephan Aßmus 106304c9d578SStephan Aßmus RefreshWorkerParameters* parameters = new(std::nothrow) 106404c9d578SStephan Aßmus RefreshWorkerParameters(this, force); 106504c9d578SStephan Aßmus if (parameters == NULL) 106604c9d578SStephan Aßmus return; 106704c9d578SStephan Aßmus 106804c9d578SStephan Aßmus ObjectDeleter<RefreshWorkerParameters> deleter(parameters); 106904c9d578SStephan Aßmus fModelWorker = spawn_thread(&_RefreshModelThreadWorker, "model loader", 107004c9d578SStephan Aßmus B_LOW_PRIORITY, parameters); 107104c9d578SStephan Aßmus 107204c9d578SStephan Aßmus if (fModelWorker > 0) { 107304c9d578SStephan Aßmus deleter.Detach(); 107404c9d578SStephan Aßmus resume_thread(fModelWorker); 107504c9d578SStephan Aßmus } 107604c9d578SStephan Aßmus } 107704c9d578SStephan Aßmus 107804c9d578SStephan Aßmus 107904c9d578SStephan Aßmus status_t 108004c9d578SStephan Aßmus MainWindow::_RefreshModelThreadWorker(void* arg) 108104c9d578SStephan Aßmus { 108204c9d578SStephan Aßmus RefreshWorkerParameters* parameters 108304c9d578SStephan Aßmus = reinterpret_cast<RefreshWorkerParameters*>(arg); 108404c9d578SStephan Aßmus MainWindow* mainWindow = parameters->window; 108504c9d578SStephan Aßmus ObjectDeleter<RefreshWorkerParameters> deleter(parameters); 108604c9d578SStephan Aßmus 108704c9d578SStephan Aßmus BMessenger messenger(mainWindow); 108804c9d578SStephan Aßmus 108904c9d578SStephan Aßmus mainWindow->_RefreshRepositories(parameters->forceRefresh); 109004c9d578SStephan Aßmus 109104c9d578SStephan Aßmus if (mainWindow->fTerminating) 109204c9d578SStephan Aßmus return B_OK; 109304c9d578SStephan Aßmus 10947b2c59b9SStephan Aßmus mainWindow->_RefreshPackageList(parameters->forceRefresh); 109504c9d578SStephan Aßmus 109604c9d578SStephan Aßmus messenger.SendMessage(MSG_MODEL_WORKER_DONE); 109704c9d578SStephan Aßmus 109804c9d578SStephan Aßmus return B_OK; 109904c9d578SStephan Aßmus } 110004c9d578SStephan Aßmus 110104c9d578SStephan Aßmus 110204c9d578SStephan Aßmus status_t 110304c9d578SStephan Aßmus MainWindow::_PackageActionWorker(void* arg) 110404c9d578SStephan Aßmus { 110504c9d578SStephan Aßmus MainWindow* window = reinterpret_cast<MainWindow*>(arg); 110604c9d578SStephan Aßmus 110704c9d578SStephan Aßmus while (acquire_sem(window->fPendingActionsSem) == B_OK) { 110804c9d578SStephan Aßmus PackageActionRef ref; 110904c9d578SStephan Aßmus { 111004c9d578SStephan Aßmus AutoLocker<BLocker> lock(&window->fPendingActionsLock); 111104c9d578SStephan Aßmus ref = window->fPendingActions.ItemAt(0); 111204c9d578SStephan Aßmus if (ref.Get() == NULL) 111304c9d578SStephan Aßmus break; 111404c9d578SStephan Aßmus window->fPendingActions.Remove(0); 111504c9d578SStephan Aßmus } 111604c9d578SStephan Aßmus 111704c9d578SStephan Aßmus ref->Perform(); 111804c9d578SStephan Aßmus } 111904c9d578SStephan Aßmus 112004c9d578SStephan Aßmus return 0; 112104c9d578SStephan Aßmus } 112204c9d578SStephan Aßmus 112304c9d578SStephan Aßmus 112404c9d578SStephan Aßmus status_t 112504c9d578SStephan Aßmus MainWindow::_PopulatePackageWorker(void* arg) 112604c9d578SStephan Aßmus { 112704c9d578SStephan Aßmus MainWindow* window = reinterpret_cast<MainWindow*>(arg); 112804c9d578SStephan Aßmus 112904c9d578SStephan Aßmus while (acquire_sem(window->fPackageToPopulateSem) == B_OK) { 113004c9d578SStephan Aßmus PackageInfoRef package; 113104c9d578SStephan Aßmus { 113204c9d578SStephan Aßmus AutoLocker<BLocker> lock(&window->fPackageToPopulateLock); 113304c9d578SStephan Aßmus package = window->fPackageToPopulate; 113404c9d578SStephan Aßmus } 113504c9d578SStephan Aßmus 113604c9d578SStephan Aßmus if (package.Get() != NULL) { 113704c9d578SStephan Aßmus window->fModel.PopulatePackage(package, 113804c9d578SStephan Aßmus Model::POPULATE_USER_RATINGS | Model::POPULATE_SCREEN_SHOTS 113904c9d578SStephan Aßmus | Model::POPULATE_CHANGELOG); 114004c9d578SStephan Aßmus } 114104c9d578SStephan Aßmus } 114204c9d578SStephan Aßmus 114304c9d578SStephan Aßmus return 0; 114404c9d578SStephan Aßmus } 114504c9d578SStephan Aßmus 114604c9d578SStephan Aßmus 114704c9d578SStephan Aßmus void 114804c9d578SStephan Aßmus MainWindow::_NotifyUser(const char* title, const char* message) 114904c9d578SStephan Aßmus { 115004c9d578SStephan Aßmus BAlert* alert = new(std::nothrow) BAlert(title, message, 115104c9d578SStephan Aßmus B_TRANSLATE("Close")); 115204c9d578SStephan Aßmus 115304c9d578SStephan Aßmus if (alert != NULL) 115404c9d578SStephan Aßmus alert->Go(); 115504c9d578SStephan Aßmus } 115604c9d578SStephan Aßmus 115704c9d578SStephan Aßmus 115804c9d578SStephan Aßmus void 11591bbda92dSStephan Aßmus MainWindow::_OpenLoginWindow(const BMessage& onSuccessMessage) 116004c9d578SStephan Aßmus { 116104c9d578SStephan Aßmus UserLoginWindow* window = new UserLoginWindow(this, 116204c9d578SStephan Aßmus BRect(0, 0, 500, 400), fModel); 11631bbda92dSStephan Aßmus 11641bbda92dSStephan Aßmus if (onSuccessMessage.what != 0) 11651bbda92dSStephan Aßmus window->SetOnSuccessMessage(BMessenger(this), onSuccessMessage); 11661bbda92dSStephan Aßmus 116704c9d578SStephan Aßmus window->Show(); 116804c9d578SStephan Aßmus } 116904c9d578SStephan Aßmus 11708f03a0f9SStephan Aßmus 11718f03a0f9SStephan Aßmus void 11728f03a0f9SStephan Aßmus MainWindow::_UpdateAuthorization() 11738f03a0f9SStephan Aßmus { 11748f03a0f9SStephan Aßmus BString username(fModel.Username()); 1175e0a26dceSStephan Aßmus bool hasUser = !username.IsEmpty(); 1176e0a26dceSStephan Aßmus 11776d519fd1SStephan Aßmus if (fLogOutItem != NULL) 1178e0a26dceSStephan Aßmus fLogOutItem->SetEnabled(hasUser); 1179e0a26dceSStephan Aßmus if (fLogInItem != NULL) { 1180e0a26dceSStephan Aßmus if (hasUser) 1181e0a26dceSStephan Aßmus fLogInItem->SetLabel(B_TRANSLATE("Switch account" B_UTF8_ELLIPSIS)); 1182e0a26dceSStephan Aßmus else 1183e0a26dceSStephan Aßmus fLogInItem->SetLabel(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS)); 1184e0a26dceSStephan Aßmus } 1185e0a26dceSStephan Aßmus 1186e0a26dceSStephan Aßmus if (fUserMenu != NULL) { 1187e0a26dceSStephan Aßmus BString label; 1188e0a26dceSStephan Aßmus if (username.Length() == 0) { 1189e0a26dceSStephan Aßmus label = B_TRANSLATE("Not logged in"); 1190e0a26dceSStephan Aßmus } else { 1191e0a26dceSStephan Aßmus label = B_TRANSLATE("Logged in as %User%"); 1192e0a26dceSStephan Aßmus label.ReplaceAll("%User%", username); 1193e0a26dceSStephan Aßmus } 1194e0a26dceSStephan Aßmus fUserMenu->Superitem()->SetLabel(label); 1195e0a26dceSStephan Aßmus } 11968f03a0f9SStephan Aßmus } 11971bbda92dSStephan Aßmus 11981bbda92dSStephan Aßmus 11991bbda92dSStephan Aßmus void 12001bbda92dSStephan Aßmus MainWindow::_RatePackage() 12011bbda92dSStephan Aßmus { 12021bbda92dSStephan Aßmus if (fModel.Username().IsEmpty()) { 12031bbda92dSStephan Aßmus BAlert* alert = new(std::nothrow) BAlert( 12041bbda92dSStephan Aßmus B_TRANSLATE("Not logged in"), 12051bbda92dSStephan Aßmus B_TRANSLATE("You need to be logged into an account before you " 12061bbda92dSStephan Aßmus "can rate packages."), 12071bbda92dSStephan Aßmus B_TRANSLATE("Cancel"), 12081bbda92dSStephan Aßmus B_TRANSLATE("Login or Create account")); 12091bbda92dSStephan Aßmus 12101bbda92dSStephan Aßmus if (alert == NULL) 12111bbda92dSStephan Aßmus return; 12121bbda92dSStephan Aßmus 12131bbda92dSStephan Aßmus int32 choice = alert->Go(); 12141bbda92dSStephan Aßmus if (choice == 1) 12151bbda92dSStephan Aßmus _OpenLoginWindow(BMessage(MSG_RATE_PACKAGE)); 12161bbda92dSStephan Aßmus return; 12171bbda92dSStephan Aßmus } 12181bbda92dSStephan Aßmus 12191bbda92dSStephan Aßmus // TODO: Allow only one RatePackageWindow 12201bbda92dSStephan Aßmus // TODO: Mechanism for remembering the window frame 12211bbda92dSStephan Aßmus RatePackageWindow* window = new RatePackageWindow(this, 12221bbda92dSStephan Aßmus BRect(0, 0, 500, 400), fModel); 12231bbda92dSStephan Aßmus window->SetPackage(fPackageInfoView->Package()); 12241bbda92dSStephan Aßmus window->Show(); 12251bbda92dSStephan Aßmus } 1226d5ef985eSStephan Aßmus 1227d5ef985eSStephan Aßmus 1228d5ef985eSStephan Aßmus void 1229d5ef985eSStephan Aßmus MainWindow::_ShowScreenshot() 1230d5ef985eSStephan Aßmus { 1231d5ef985eSStephan Aßmus // TODO: Mechanism for remembering the window frame 1232d5ef985eSStephan Aßmus if (fScreenshotWindow == NULL) 1233d5ef985eSStephan Aßmus fScreenshotWindow = new ScreenshotWindow(this, BRect(0, 0, 500, 400)); 1234d5ef985eSStephan Aßmus 1235d5ef985eSStephan Aßmus if (fScreenshotWindow->LockWithTimeout(1000) != B_OK) 1236d5ef985eSStephan Aßmus return; 1237d5ef985eSStephan Aßmus 1238d5ef985eSStephan Aßmus fScreenshotWindow->SetPackage(fPackageInfoView->Package()); 1239d5ef985eSStephan Aßmus 1240d5ef985eSStephan Aßmus if (fScreenshotWindow->IsHidden()) 1241d5ef985eSStephan Aßmus fScreenshotWindow->Show(); 1242d5ef985eSStephan Aßmus else 1243d5ef985eSStephan Aßmus fScreenshotWindow->Activate(); 1244d5ef985eSStephan Aßmus 1245d5ef985eSStephan Aßmus fScreenshotWindow->Unlock(); 1246d5ef985eSStephan Aßmus } 1247d5ef985eSStephan Aßmus 1248