104c9d578SStephan Aßmus /* 2f7c2983eSAxel Dörfler * Copyright 2015, Axel Dörfler, <axeld@pinc-software.de>. 304c9d578SStephan Aßmus * Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>. 404c9d578SStephan Aßmus * Copyright 2013, Rene Gollent, rene@gollent.com. 504c9d578SStephan Aßmus * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. 6*89b16bb4SAndrew Lindesay * Copyright 2016-2019, Andrew Lindesay <apl@lindesay.co.nz>. 7125d42d9SJulian Harnath * Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>. 804c9d578SStephan Aßmus * All rights reserved. Distributed under the terms of the MIT License. 904c9d578SStephan Aßmus */ 1004c9d578SStephan Aßmus 11f7c2983eSAxel Dörfler 1204c9d578SStephan Aßmus #include "MainWindow.h" 1304c9d578SStephan Aßmus 1404c9d578SStephan Aßmus #include <map> 153b17d8ddSAndrew Lindesay #include <vector> 1604c9d578SStephan Aßmus 1704c9d578SStephan Aßmus #include <stdio.h> 1804c9d578SStephan Aßmus #include <Alert.h> 1904c9d578SStephan Aßmus #include <Autolock.h> 2004c9d578SStephan Aßmus #include <Application.h> 2104c9d578SStephan Aßmus #include <Button.h> 2204c9d578SStephan Aßmus #include <Catalog.h> 234b930ccaSStephan Aßmus #include <CardLayout.h> 2404c9d578SStephan Aßmus #include <LayoutBuilder.h> 2504c9d578SStephan Aßmus #include <MenuBar.h> 2604c9d578SStephan Aßmus #include <MenuItem.h> 2704c9d578SStephan Aßmus #include <Messenger.h> 285bf2b6ebSBrian Hill #include <Roster.h> 29f7c2983eSAxel Dörfler #include <Screen.h> 3004c9d578SStephan Aßmus #include <ScrollView.h> 3104c9d578SStephan Aßmus #include <StringList.h> 320a9c9029SStephan Aßmus #include <StringView.h> 3304c9d578SStephan Aßmus #include <TabView.h> 3404c9d578SStephan Aßmus 353369e03dSAndrew Lindesay #include "AppUtils.h" 3604c9d578SStephan Aßmus #include "AutoDeleter.h" 3704c9d578SStephan Aßmus #include "AutoLocker.h" 3804c9d578SStephan Aßmus #include "DecisionProvider.h" 394b930ccaSStephan Aßmus #include "FeaturedPackagesView.h" 4004c9d578SStephan Aßmus #include "FilterView.h" 41d13c3d89SAndrew Lindesay #include "Logger.h" 4204c9d578SStephan Aßmus #include "PackageInfoView.h" 4304c9d578SStephan Aßmus #include "PackageListView.h" 4404c9d578SStephan Aßmus #include "PackageManager.h" 453369e03dSAndrew Lindesay #include "ProcessCoordinator.h" 463369e03dSAndrew Lindesay #include "ProcessCoordinatorFactory.h" 4704c9d578SStephan Aßmus #include "RatePackageWindow.h" 48e0a26dceSStephan Aßmus #include "support.h" 49d5ef985eSStephan Aßmus #include "ScreenshotWindow.h" 5004c9d578SStephan Aßmus #include "UserLoginWindow.h" 51125d42d9SJulian Harnath #include "WorkStatusView.h" 5204c9d578SStephan Aßmus 5304c9d578SStephan Aßmus 5404c9d578SStephan Aßmus #undef B_TRANSLATION_CONTEXT 5504c9d578SStephan Aßmus #define B_TRANSLATION_CONTEXT "MainWindow" 5604c9d578SStephan Aßmus 5704c9d578SStephan Aßmus 5804c9d578SStephan Aßmus enum { 593369e03dSAndrew Lindesay MSG_BULK_LOAD_DONE = 'mmwd', 605bf2b6ebSBrian Hill MSG_REFRESH_REPOS = 'mrrp', 615bf2b6ebSBrian Hill MSG_MANAGE_REPOS = 'mmrp', 62d144f952SAugustin Cavalier MSG_SOFTWARE_UPDATER = 'mswu', 6304c9d578SStephan Aßmus MSG_LOG_IN = 'lgin', 648f03a0f9SStephan Aßmus MSG_LOG_OUT = 'lgot', 658f03a0f9SStephan Aßmus MSG_AUTHORIZATION_CHANGED = 'athc', 66*89b16bb4SAndrew Lindesay MSG_CATEGORIES_LIST_CHANGED = 'clic', 67da651104SStephan Aßmus MSG_PACKAGE_CHANGED = 'pchd', 683369e03dSAndrew Lindesay MSG_WORK_STATUS_CHANGE = 'wsch', 693369e03dSAndrew Lindesay MSG_WORK_STATUS_CLEAR = 'wscl', 70fdec4227SStephan Aßmus 71e00a489bSAugustin Cavalier 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 8504c9d578SStephan Aßmus 8604c9d578SStephan Aßmus struct RefreshWorkerParameters { 8704c9d578SStephan Aßmus MainWindow* window; 8804c9d578SStephan Aßmus bool forceRefresh; 8904c9d578SStephan Aßmus 9004c9d578SStephan Aßmus RefreshWorkerParameters(MainWindow* window, bool forceRefresh) 9104c9d578SStephan Aßmus : 9204c9d578SStephan Aßmus window(window), 9304c9d578SStephan Aßmus forceRefresh(forceRefresh) 9404c9d578SStephan Aßmus { 9504c9d578SStephan Aßmus } 9604c9d578SStephan Aßmus }; 9704c9d578SStephan Aßmus 9804c9d578SStephan Aßmus 99*89b16bb4SAndrew Lindesay class MainWindowModelListener : public ModelListener { 1008f03a0f9SStephan Aßmus public: 101*89b16bb4SAndrew Lindesay MainWindowModelListener(const BMessenger& messenger) 1028f03a0f9SStephan Aßmus : 1038f03a0f9SStephan Aßmus fMessenger(messenger) 1048f03a0f9SStephan Aßmus { 1058f03a0f9SStephan Aßmus } 1068f03a0f9SStephan Aßmus 1078f03a0f9SStephan Aßmus virtual void AuthorizationChanged() 1088f03a0f9SStephan Aßmus { 1098f03a0f9SStephan Aßmus if (fMessenger.IsValid()) 1108f03a0f9SStephan Aßmus fMessenger.SendMessage(MSG_AUTHORIZATION_CHANGED); 1118f03a0f9SStephan Aßmus } 1128f03a0f9SStephan Aßmus 113*89b16bb4SAndrew Lindesay virtual void CategoryListChanged() 114*89b16bb4SAndrew Lindesay { 115*89b16bb4SAndrew Lindesay if (fMessenger.IsValid()) 116*89b16bb4SAndrew Lindesay fMessenger.SendMessage(MSG_CATEGORIES_LIST_CHANGED); 117*89b16bb4SAndrew Lindesay } 118*89b16bb4SAndrew Lindesay 1198f03a0f9SStephan Aßmus private: 1208f03a0f9SStephan Aßmus BMessenger fMessenger; 1218f03a0f9SStephan Aßmus }; 1228f03a0f9SStephan Aßmus 1238f03a0f9SStephan Aßmus 124f7c2983eSAxel Dörfler MainWindow::MainWindow(const BMessage& settings) 12504c9d578SStephan Aßmus : 126f7c2983eSAxel Dörfler BWindow(BRect(50, 50, 650, 550), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"), 12704c9d578SStephan Aßmus B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 12804c9d578SStephan Aßmus B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 129d5ef985eSStephan Aßmus fScreenshotWindow(NULL), 130e0a26dceSStephan Aßmus fUserMenu(NULL), 131e0a26dceSStephan Aßmus fLogInItem(NULL), 132e0a26dceSStephan Aßmus fLogOutItem(NULL), 133*89b16bb4SAndrew Lindesay fModelListener(new MainWindowModelListener(BMessenger(this)), true), 1343369e03dSAndrew Lindesay fBulkLoadProcessCoordinator(NULL), 1353369e03dSAndrew Lindesay fSinglePackageMode(false) 13604c9d578SStephan Aßmus { 137cbadcae1SHumdinger BMenuBar* menuBar = new BMenuBar("Main Menu"); 13804c9d578SStephan Aßmus _BuildMenu(menuBar); 13904c9d578SStephan Aßmus 140cbadcae1SHumdinger BMenuBar* userMenuBar = new BMenuBar("User Menu"); 141e0a26dceSStephan Aßmus _BuildUserMenu(userMenuBar); 142e0a26dceSStephan Aßmus set_small_font(userMenuBar); 143e0a26dceSStephan Aßmus userMenuBar->SetExplicitMaxSize(BSize(B_SIZE_UNSET, 144e0a26dceSStephan Aßmus menuBar->MaxSize().height)); 145e0a26dceSStephan Aßmus 14604c9d578SStephan Aßmus fFilterView = new FilterView(); 1474b930ccaSStephan Aßmus fFeaturedPackagesView = new FeaturedPackagesView(); 14804c9d578SStephan Aßmus fPackageListView = new PackageListView(fModel.Lock()); 14904c9d578SStephan Aßmus fPackageInfoView = new PackageInfoView(fModel.Lock(), this); 15004c9d578SStephan Aßmus 15104c9d578SStephan Aßmus fSplitView = new BSplitView(B_VERTICAL, 5.0f); 15204c9d578SStephan Aßmus 153125d42d9SJulian Harnath fWorkStatusView = new WorkStatusView("work status"); 154125d42d9SJulian Harnath fPackageListView->AttachWorkStatusView(fWorkStatusView); 155125d42d9SJulian Harnath 156e00a489bSAugustin Cavalier fListTabs = new TabView(BMessenger(this), 157e00a489bSAugustin Cavalier BMessage(MSG_SHOW_FEATURED_PACKAGES), "list tabs"); 158e00a489bSAugustin Cavalier fListTabs->AddTab(fFeaturedPackagesView); 159e00a489bSAugustin Cavalier fListTabs->AddTab(fPackageListView); 1604b930ccaSStephan Aßmus 16104c9d578SStephan Aßmus BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f) 162e0a26dceSStephan Aßmus .AddGroup(B_HORIZONTAL, 0.0f) 163e0a26dceSStephan Aßmus .Add(menuBar, 1.0f) 164e0a26dceSStephan Aßmus .Add(userMenuBar, 0.0f) 165e0a26dceSStephan Aßmus .End() 16604c9d578SStephan Aßmus .Add(fFilterView) 16704c9d578SStephan Aßmus .AddSplit(fSplitView) 16804c9d578SStephan Aßmus .AddGroup(B_VERTICAL) 169e00a489bSAugustin Cavalier .Add(fListTabs) 17004c9d578SStephan Aßmus .SetInsets( 17104c9d578SStephan Aßmus B_USE_DEFAULT_SPACING, 0.0f, 17204c9d578SStephan Aßmus B_USE_DEFAULT_SPACING, 0.0f) 17304c9d578SStephan Aßmus .End() 17404c9d578SStephan Aßmus .Add(fPackageInfoView) 17504c9d578SStephan Aßmus .End() 176125d42d9SJulian Harnath .Add(fWorkStatusView) 17704c9d578SStephan Aßmus ; 17804c9d578SStephan Aßmus 17904c9d578SStephan Aßmus fSplitView->SetCollapsible(0, false); 18004c9d578SStephan Aßmus fSplitView->SetCollapsible(1, false); 18104c9d578SStephan Aßmus 1828f03a0f9SStephan Aßmus fModel.AddListener(fModelListener); 1838f03a0f9SStephan Aßmus 18404c9d578SStephan Aßmus // Restore settings 18504c9d578SStephan Aßmus BMessage columnSettings; 18604c9d578SStephan Aßmus if (settings.FindMessage("column settings", &columnSettings) == B_OK) 18704c9d578SStephan Aßmus fPackageListView->LoadState(&columnSettings); 18804c9d578SStephan Aßmus 18904c9d578SStephan Aßmus bool showOption; 1902997e05bSStephan Aßmus if (settings.FindBool("show featured packages", &showOption) == B_OK) 1912997e05bSStephan Aßmus fModel.SetShowFeaturedPackages(showOption); 1922997e05bSStephan Aßmus if (settings.FindBool("show available packages", &showOption) == B_OK) 1932997e05bSStephan Aßmus fModel.SetShowAvailablePackages(showOption); 1942997e05bSStephan Aßmus if (settings.FindBool("show installed packages", &showOption) == B_OK) 1952997e05bSStephan Aßmus fModel.SetShowInstalledPackages(showOption); 19604c9d578SStephan Aßmus if (settings.FindBool("show develop packages", &showOption) == B_OK) 19704c9d578SStephan Aßmus fModel.SetShowDevelopPackages(showOption); 19804c9d578SStephan Aßmus if (settings.FindBool("show source packages", &showOption) == B_OK) 19904c9d578SStephan Aßmus fModel.SetShowSourcePackages(showOption); 20004c9d578SStephan Aßmus 2012997e05bSStephan Aßmus if (fModel.ShowFeaturedPackages()) 202e00a489bSAugustin Cavalier fListTabs->Select(0); 2032997e05bSStephan Aßmus else 204e00a489bSAugustin Cavalier fListTabs->Select(1); 2052997e05bSStephan Aßmus 206f7c2983eSAxel Dörfler _RestoreUserName(settings); 207f7c2983eSAxel Dörfler _RestoreWindowFrame(settings); 208f7c2983eSAxel Dörfler 20972fff6d3SJulian Harnath atomic_set(&fPackagesToShowListID, 0); 21072fff6d3SJulian Harnath 2118f03a0f9SStephan Aßmus // start worker threads 21204c9d578SStephan Aßmus BPackageRoster().StartWatching(this, 21304c9d578SStephan Aßmus B_WATCH_PACKAGE_INSTALLATION_LOCATIONS); 21404c9d578SStephan Aßmus 2153369e03dSAndrew Lindesay _StartBulkLoad(); 21604c9d578SStephan Aßmus 21763975654SStephan Aßmus _InitWorkerThreads(); 21804c9d578SStephan Aßmus } 21904c9d578SStephan Aßmus 22004c9d578SStephan Aßmus 221f7c2983eSAxel Dörfler MainWindow::MainWindow(const BMessage& settings, const PackageInfoRef& package) 2226d519fd1SStephan Aßmus : 223f7c2983eSAxel Dörfler BWindow(BRect(50, 50, 650, 350), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"), 2246d519fd1SStephan Aßmus B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 2256d519fd1SStephan Aßmus B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 226d78bfd8dSJulian Harnath fWorkStatusView(NULL), 227d5ef985eSStephan Aßmus fScreenshotWindow(NULL), 228e0a26dceSStephan Aßmus fUserMenu(NULL), 229e0a26dceSStephan Aßmus fLogInItem(NULL), 2306d519fd1SStephan Aßmus fLogOutItem(NULL), 231*89b16bb4SAndrew Lindesay fModelListener(new MainWindowModelListener(BMessenger(this)), true), 2323369e03dSAndrew Lindesay fBulkLoadProcessCoordinator(NULL), 2333369e03dSAndrew Lindesay fSinglePackageMode(true) 2346d519fd1SStephan Aßmus { 2356d519fd1SStephan Aßmus fFilterView = new FilterView(); 2366d519fd1SStephan Aßmus fPackageListView = new PackageListView(fModel.Lock()); 2376d519fd1SStephan Aßmus fPackageInfoView = new PackageInfoView(fModel.Lock(), this); 2386d519fd1SStephan Aßmus 2396d519fd1SStephan Aßmus BLayoutBuilder::Group<>(this, B_VERTICAL) 2406d519fd1SStephan Aßmus .Add(fPackageInfoView) 2416d519fd1SStephan Aßmus .SetInsets(0, B_USE_WINDOW_INSETS, 0, 0) 2426d519fd1SStephan Aßmus ; 2436d519fd1SStephan Aßmus 2446d519fd1SStephan Aßmus fModel.AddListener(fModelListener); 2456d519fd1SStephan Aßmus 2466d519fd1SStephan Aßmus // Restore settings 247f7c2983eSAxel Dörfler _RestoreUserName(settings); 248f7c2983eSAxel Dörfler _RestoreWindowFrame(settings); 2496d519fd1SStephan Aßmus 2506d519fd1SStephan Aßmus fPackageInfoView->SetPackage(package); 25163975654SStephan Aßmus 25263975654SStephan Aßmus _InitWorkerThreads(); 2536d519fd1SStephan Aßmus } 2546d519fd1SStephan Aßmus 2556d519fd1SStephan Aßmus 25604c9d578SStephan Aßmus MainWindow::~MainWindow() 25704c9d578SStephan Aßmus { 25804c9d578SStephan Aßmus BPackageRoster().StopWatching(this); 25904c9d578SStephan Aßmus 26004c9d578SStephan Aßmus delete_sem(fPendingActionsSem); 26105bffa62SStephan Aßmus if (fPendingActionsWorker >= 0) 26204c9d578SStephan Aßmus wait_for_thread(fPendingActionsWorker, NULL); 26304c9d578SStephan Aßmus 26404c9d578SStephan Aßmus delete_sem(fPackageToPopulateSem); 26505bffa62SStephan Aßmus if (fPopulatePackageWorker >= 0) 26604c9d578SStephan Aßmus wait_for_thread(fPopulatePackageWorker, NULL); 267d5ef985eSStephan Aßmus 26872fff6d3SJulian Harnath delete_sem(fNewPackagesToShowSem); 26972fff6d3SJulian Harnath delete_sem(fShowPackagesAcknowledgeSem); 27072fff6d3SJulian Harnath if (fShowPackagesWorker >= 0) 27172fff6d3SJulian Harnath wait_for_thread(fShowPackagesWorker, NULL); 27272fff6d3SJulian Harnath 273d5ef985eSStephan Aßmus if (fScreenshotWindow != NULL && fScreenshotWindow->Lock()) 274d5ef985eSStephan Aßmus fScreenshotWindow->Quit(); 27504c9d578SStephan Aßmus } 27604c9d578SStephan Aßmus 27704c9d578SStephan Aßmus 27804c9d578SStephan Aßmus bool 27904c9d578SStephan Aßmus MainWindow::QuitRequested() 28004c9d578SStephan Aßmus { 28104c9d578SStephan Aßmus BMessage settings; 28204c9d578SStephan Aßmus StoreSettings(settings); 28304c9d578SStephan Aßmus 28404c9d578SStephan Aßmus BMessage message(MSG_MAIN_WINDOW_CLOSED); 2853369e03dSAndrew Lindesay message.AddMessage(KEY_WINDOW_SETTINGS, &settings); 28604c9d578SStephan Aßmus 28704c9d578SStephan Aßmus be_app->PostMessage(&message); 28804c9d578SStephan Aßmus 2893369e03dSAndrew Lindesay _StopBulkLoad(); 2903369e03dSAndrew Lindesay 29104c9d578SStephan Aßmus return true; 29204c9d578SStephan Aßmus } 29304c9d578SStephan Aßmus 29404c9d578SStephan Aßmus 29504c9d578SStephan Aßmus void 29604c9d578SStephan Aßmus MainWindow::MessageReceived(BMessage* message) 29704c9d578SStephan Aßmus { 29804c9d578SStephan Aßmus switch (message->what) { 2993369e03dSAndrew Lindesay case MSG_BULK_LOAD_DONE: 3003369e03dSAndrew Lindesay _BulkLoadCompleteReceived(); 30104c9d578SStephan Aßmus break; 30204c9d578SStephan Aßmus case B_SIMPLE_DATA: 30304c9d578SStephan Aßmus case B_REFS_RECEIVED: 30404c9d578SStephan Aßmus // TODO: ? 30504c9d578SStephan Aßmus break; 30604c9d578SStephan Aßmus 30704c9d578SStephan Aßmus case B_PACKAGE_UPDATE: 30804c9d578SStephan Aßmus // TODO: We should do a more selective update depending on the 30904c9d578SStephan Aßmus // "event", "location", and "change count" fields! 3103369e03dSAndrew Lindesay _StartBulkLoad(false); 31104c9d578SStephan Aßmus break; 31204c9d578SStephan Aßmus 3135bf2b6ebSBrian Hill case MSG_REFRESH_REPOS: 3143369e03dSAndrew Lindesay _StartBulkLoad(true); 3153369e03dSAndrew Lindesay break; 3163369e03dSAndrew Lindesay 3173369e03dSAndrew Lindesay case MSG_WORK_STATUS_CHANGE: 3183369e03dSAndrew Lindesay _HandleWorkStatusChangeMessageReceived(message); 31904c9d578SStephan Aßmus break; 32004c9d578SStephan Aßmus 3215bf2b6ebSBrian Hill case MSG_MANAGE_REPOS: 3225bf2b6ebSBrian Hill be_roster->Launch("application/x-vnd.Haiku-Repositories"); 3235bf2b6ebSBrian Hill break; 3245bf2b6ebSBrian Hill 325d144f952SAugustin Cavalier case MSG_SOFTWARE_UPDATER: 326d144f952SAugustin Cavalier be_roster->Launch("application/x-vnd.haiku-softwareupdater"); 327d144f952SAugustin Cavalier break; 328d144f952SAugustin Cavalier 32904c9d578SStephan Aßmus case MSG_LOG_IN: 3301bbda92dSStephan Aßmus _OpenLoginWindow(BMessage()); 33104c9d578SStephan Aßmus break; 33204c9d578SStephan Aßmus 3338f03a0f9SStephan Aßmus case MSG_LOG_OUT: 3348f03a0f9SStephan Aßmus fModel.SetUsername(""); 3358f03a0f9SStephan Aßmus break; 3368f03a0f9SStephan Aßmus 3378f03a0f9SStephan Aßmus case MSG_AUTHORIZATION_CHANGED: 3388f03a0f9SStephan Aßmus _UpdateAuthorization(); 3398f03a0f9SStephan Aßmus break; 3408f03a0f9SStephan Aßmus 341*89b16bb4SAndrew Lindesay case MSG_CATEGORIES_LIST_CHANGED: 342*89b16bb4SAndrew Lindesay fFilterView->AdoptModel(fModel); 343*89b16bb4SAndrew Lindesay break; 344*89b16bb4SAndrew Lindesay 3454fade61fSStephan Aßmus case MSG_SHOW_FEATURED_PACKAGES: 346e00a489bSAugustin Cavalier // check to see if we aren't already on the current tab 347e00a489bSAugustin Cavalier if (fListTabs->Selection() == 348e00a489bSAugustin Cavalier (fModel.ShowFeaturedPackages() ? 0 : 1)) 349e00a489bSAugustin Cavalier break; 3504fade61fSStephan Aßmus { 3514fade61fSStephan Aßmus BAutolock locker(fModel.Lock()); 3524fade61fSStephan Aßmus fModel.SetShowFeaturedPackages( 353e00a489bSAugustin Cavalier fListTabs->Selection() == 0); 3544fade61fSStephan Aßmus } 3554fade61fSStephan Aßmus _AdoptModel(); 3564fade61fSStephan Aßmus break; 3574fade61fSStephan Aßmus 358fdec4227SStephan Aßmus case MSG_SHOW_AVAILABLE_PACKAGES: 359fdec4227SStephan Aßmus { 360fdec4227SStephan Aßmus BAutolock locker(fModel.Lock()); 361fdec4227SStephan Aßmus fModel.SetShowAvailablePackages( 362fdec4227SStephan Aßmus !fModel.ShowAvailablePackages()); 363fdec4227SStephan Aßmus } 364fdec4227SStephan Aßmus _AdoptModel(); 365fdec4227SStephan Aßmus break; 366fdec4227SStephan Aßmus 367fdec4227SStephan Aßmus case MSG_SHOW_INSTALLED_PACKAGES: 368fdec4227SStephan Aßmus { 369fdec4227SStephan Aßmus BAutolock locker(fModel.Lock()); 370fdec4227SStephan Aßmus fModel.SetShowInstalledPackages( 371fdec4227SStephan Aßmus !fModel.ShowInstalledPackages()); 372fdec4227SStephan Aßmus } 373fdec4227SStephan Aßmus _AdoptModel(); 374fdec4227SStephan Aßmus break; 375fdec4227SStephan Aßmus 37604c9d578SStephan Aßmus case MSG_SHOW_SOURCE_PACKAGES: 37704c9d578SStephan Aßmus { 37804c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 37904c9d578SStephan Aßmus fModel.SetShowSourcePackages(!fModel.ShowSourcePackages()); 38004c9d578SStephan Aßmus } 38104c9d578SStephan Aßmus _AdoptModel(); 38204c9d578SStephan Aßmus break; 38304c9d578SStephan Aßmus 38404c9d578SStephan Aßmus case MSG_SHOW_DEVELOP_PACKAGES: 38504c9d578SStephan Aßmus { 38604c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 38704c9d578SStephan Aßmus fModel.SetShowDevelopPackages(!fModel.ShowDevelopPackages()); 38804c9d578SStephan Aßmus } 38904c9d578SStephan Aßmus _AdoptModel(); 39004c9d578SStephan Aßmus break; 39104c9d578SStephan Aßmus 392a9edb9bfSAndrew Lindesay // this may be triggered by, for example, a user rating being added 393a9edb9bfSAndrew Lindesay // or having been altered. 394a9edb9bfSAndrew Lindesay case MSG_SERVER_DATA_CHANGED: 395a9edb9bfSAndrew Lindesay { 396a9edb9bfSAndrew Lindesay BString name; 397a9edb9bfSAndrew Lindesay if (message->FindString("name", &name) == B_OK) { 398a9edb9bfSAndrew Lindesay BAutolock locker(fModel.Lock()); 399a9edb9bfSAndrew Lindesay if (fPackageInfoView->Package()->Name() == name) { 400a9edb9bfSAndrew Lindesay _PopulatePackageAsync(true); 401a9edb9bfSAndrew Lindesay } else { 402a9edb9bfSAndrew Lindesay if (Logger::IsDebugEnabled()) { 403a9edb9bfSAndrew Lindesay printf("pkg [%s] is updated on the server, but is " 404a9edb9bfSAndrew Lindesay "not selected so will not be updated.\n", 405a9edb9bfSAndrew Lindesay name.String()); 406a9edb9bfSAndrew Lindesay } 407a9edb9bfSAndrew Lindesay } 408a9edb9bfSAndrew Lindesay } 409a9edb9bfSAndrew Lindesay break; 410a9edb9bfSAndrew Lindesay } 411a9edb9bfSAndrew Lindesay 41204c9d578SStephan Aßmus case MSG_PACKAGE_SELECTED: 41304c9d578SStephan Aßmus { 41472992391SStephan Aßmus BString name; 41572992391SStephan Aßmus if (message->FindString("name", &name) == B_OK) { 41675ba9dbfSStephan Aßmus BAutolock locker(fModel.Lock()); 41704c9d578SStephan Aßmus int count = fVisiblePackages.CountItems(); 41804c9d578SStephan Aßmus for (int i = 0; i < count; i++) { 41904c9d578SStephan Aßmus const PackageInfoRef& package 42004c9d578SStephan Aßmus = fVisiblePackages.ItemAtFast(i); 42172992391SStephan Aßmus if (package.Get() != NULL && package->Name() == name) { 42275ba9dbfSStephan Aßmus locker.Unlock(); 42304c9d578SStephan Aßmus _AdoptPackage(package); 42404c9d578SStephan Aßmus break; 42504c9d578SStephan Aßmus } 42604c9d578SStephan Aßmus } 42704c9d578SStephan Aßmus } else { 42804c9d578SStephan Aßmus _ClearPackage(); 42904c9d578SStephan Aßmus } 43004c9d578SStephan Aßmus break; 43104c9d578SStephan Aßmus } 43204c9d578SStephan Aßmus 43304c9d578SStephan Aßmus case MSG_CATEGORY_SELECTED: 43404c9d578SStephan Aßmus { 435*89b16bb4SAndrew Lindesay BString code; 436*89b16bb4SAndrew Lindesay if (message->FindString("code", &code) != B_OK) 437*89b16bb4SAndrew Lindesay code = ""; 43804c9d578SStephan Aßmus { 43904c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 440*89b16bb4SAndrew Lindesay fModel.SetCategory(code); 44104c9d578SStephan Aßmus } 44204c9d578SStephan Aßmus _AdoptModel(); 44304c9d578SStephan Aßmus break; 44404c9d578SStephan Aßmus } 44504c9d578SStephan Aßmus 44604c9d578SStephan Aßmus case MSG_DEPOT_SELECTED: 44704c9d578SStephan Aßmus { 44804c9d578SStephan Aßmus BString name; 44904c9d578SStephan Aßmus if (message->FindString("name", &name) != B_OK) 45004c9d578SStephan Aßmus name = ""; 45104c9d578SStephan Aßmus { 45204c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 45304c9d578SStephan Aßmus fModel.SetDepot(name); 45404c9d578SStephan Aßmus } 45504c9d578SStephan Aßmus _AdoptModel(); 456b965ce70SHumdinger _UpdateAvailableRepositories(); 45704c9d578SStephan Aßmus break; 45804c9d578SStephan Aßmus } 45904c9d578SStephan Aßmus 46004c9d578SStephan Aßmus case MSG_SEARCH_TERMS_MODIFIED: 46104c9d578SStephan Aßmus { 46204c9d578SStephan Aßmus // TODO: Do this with a delay! 46304c9d578SStephan Aßmus BString searchTerms; 46404c9d578SStephan Aßmus if (message->FindString("search terms", &searchTerms) != B_OK) 46504c9d578SStephan Aßmus searchTerms = ""; 46604c9d578SStephan Aßmus { 46704c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 46804c9d578SStephan Aßmus fModel.SetSearchTerms(searchTerms); 46904c9d578SStephan Aßmus } 47004c9d578SStephan Aßmus _AdoptModel(); 47104c9d578SStephan Aßmus break; 47204c9d578SStephan Aßmus } 47304c9d578SStephan Aßmus 474da651104SStephan Aßmus case MSG_PACKAGE_CHANGED: 47504c9d578SStephan Aßmus { 47604c9d578SStephan Aßmus PackageInfo* info; 47704c9d578SStephan Aßmus if (message->FindPointer("package", (void**)&info) == B_OK) { 47804c9d578SStephan Aßmus PackageInfoRef ref(info, true); 479da651104SStephan Aßmus uint32 changes; 480da651104SStephan Aßmus if (message->FindUInt32("changes", &changes) != B_OK) 481da651104SStephan Aßmus changes = 0; 482da651104SStephan Aßmus if ((changes & PKG_CHANGED_STATE) != 0) { 48304c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 48404c9d578SStephan Aßmus fModel.SetPackageState(ref, ref->State()); 48504c9d578SStephan Aßmus } 48657e51fffSStephan Aßmus 48757e51fffSStephan Aßmus // Asynchronous updates to the package information 48857e51fffSStephan Aßmus // can mean that the package needs to be added or 48957e51fffSStephan Aßmus // removed to/from the visible packages when the current 49057e51fffSStephan Aßmus // filter parameters are re-evaluated on this package. 49157e51fffSStephan Aßmus bool wasVisible = fVisiblePackages.Contains(ref); 49257e51fffSStephan Aßmus bool isVisible; 49357e51fffSStephan Aßmus { 494da651104SStephan Aßmus BAutolock locker(fModel.Lock()); 4950c6df5d5SStephan Aßmus // The package didn't get a chance yet to be in the 4960c6df5d5SStephan Aßmus // visible package list 49739f49f70SJulian Harnath isVisible = fModel.MatchesFilter(ref); 49857e51fffSStephan Aßmus 49957e51fffSStephan Aßmus // Transfer this single package, otherwise we miss 50057e51fffSStephan Aßmus // other packages if they appear or disappear along 50157e51fffSStephan Aßmus // with this one before receive a notification for 50257e51fffSStephan Aßmus // them. 50357e51fffSStephan Aßmus if (isVisible) { 50457e51fffSStephan Aßmus fVisiblePackages.Add(ref); 50557e51fffSStephan Aßmus } else if (wasVisible) 50657e51fffSStephan Aßmus fVisiblePackages.Remove(ref); 50757e51fffSStephan Aßmus } 50857e51fffSStephan Aßmus 50957e51fffSStephan Aßmus if (wasVisible != isVisible) { 51057e51fffSStephan Aßmus if (!isVisible) { 51157e51fffSStephan Aßmus fPackageListView->RemovePackage(ref); 51257e51fffSStephan Aßmus fFeaturedPackagesView->RemovePackage(ref); 51357e51fffSStephan Aßmus } else { 51457e51fffSStephan Aßmus fPackageListView->AddPackage(ref); 51557e51fffSStephan Aßmus if (ref->IsProminent()) 516da651104SStephan Aßmus fFeaturedPackagesView->AddPackage(ref); 517da651104SStephan Aßmus } 518da651104SStephan Aßmus } 5194e6fbe03SJulian Harnath 5204e6fbe03SJulian Harnath if (!fSinglePackageMode && (changes & PKG_CHANGED_STATE) != 0) 5214e6fbe03SJulian Harnath fWorkStatusView->PackageStatusChanged(ref); 52257e51fffSStephan Aßmus } 52304c9d578SStephan Aßmus break; 52404c9d578SStephan Aßmus } 52504c9d578SStephan Aßmus 52604c9d578SStephan Aßmus case MSG_RATE_PACKAGE: 5271bbda92dSStephan Aßmus _RatePackage(); 52804c9d578SStephan Aßmus break; 52904c9d578SStephan Aßmus 530d5ef985eSStephan Aßmus case MSG_SHOW_SCREENSHOT: 531d5ef985eSStephan Aßmus _ShowScreenshot(); 532d5ef985eSStephan Aßmus break; 533d5ef985eSStephan Aßmus 534125d42d9SJulian Harnath case MSG_PACKAGE_WORKER_BUSY: 535125d42d9SJulian Harnath { 536125d42d9SJulian Harnath BString reason; 537125d42d9SJulian Harnath status_t status = message->FindString("reason", &reason); 538125d42d9SJulian Harnath if (status != B_OK) 539125d42d9SJulian Harnath break; 540d78bfd8dSJulian Harnath if (!fSinglePackageMode) 541125d42d9SJulian Harnath fWorkStatusView->SetBusy(reason); 542125d42d9SJulian Harnath break; 543125d42d9SJulian Harnath } 544125d42d9SJulian Harnath 545125d42d9SJulian Harnath case MSG_PACKAGE_WORKER_IDLE: 546d78bfd8dSJulian Harnath if (!fSinglePackageMode) 547125d42d9SJulian Harnath fWorkStatusView->SetIdle(); 548125d42d9SJulian Harnath break; 549125d42d9SJulian Harnath 55072fff6d3SJulian Harnath case MSG_ADD_VISIBLE_PACKAGES: 55172fff6d3SJulian Harnath { 55272fff6d3SJulian Harnath struct SemaphoreReleaser { 55372fff6d3SJulian Harnath SemaphoreReleaser(sem_id semaphore) 55472fff6d3SJulian Harnath : 55572fff6d3SJulian Harnath fSemaphore(semaphore) 55672fff6d3SJulian Harnath { } 55772fff6d3SJulian Harnath 55872fff6d3SJulian Harnath ~SemaphoreReleaser() { release_sem(fSemaphore); } 55972fff6d3SJulian Harnath 56072fff6d3SJulian Harnath sem_id fSemaphore; 56172fff6d3SJulian Harnath }; 56272fff6d3SJulian Harnath 56372fff6d3SJulian Harnath // Make sure acknowledge semaphore is released even on error, 56472fff6d3SJulian Harnath // so the worker thread won't be blocked 56572fff6d3SJulian Harnath SemaphoreReleaser acknowledger(fShowPackagesAcknowledgeSem); 56672fff6d3SJulian Harnath 56772fff6d3SJulian Harnath int32 numPackages = 0; 56872fff6d3SJulian Harnath type_code unused; 56972fff6d3SJulian Harnath status_t status = message->GetInfo("package_ref", &unused, 57072fff6d3SJulian Harnath &numPackages); 57172fff6d3SJulian Harnath if (status != B_OK || numPackages == 0) 57272fff6d3SJulian Harnath break; 57372fff6d3SJulian Harnath 57472fff6d3SJulian Harnath int32 listID = 0; 57572fff6d3SJulian Harnath status = message->FindInt32("list_id", &listID); 57672fff6d3SJulian Harnath if (status != B_OK) 57772fff6d3SJulian Harnath break; 57872fff6d3SJulian Harnath if (listID != atomic_get(&fPackagesToShowListID)) { 57972fff6d3SJulian Harnath // list is outdated, ignore 58072fff6d3SJulian Harnath break; 58172fff6d3SJulian Harnath } 58272fff6d3SJulian Harnath 58372fff6d3SJulian Harnath for (int i = 0; i < numPackages; i++) { 58472fff6d3SJulian Harnath PackageInfo* packageRaw = NULL; 58572fff6d3SJulian Harnath status = message->FindPointer("package_ref", i, 58672fff6d3SJulian Harnath (void**)&packageRaw); 58772fff6d3SJulian Harnath if (status != B_OK) 58872fff6d3SJulian Harnath break; 58972fff6d3SJulian Harnath PackageInfoRef package(packageRaw, true); 59072fff6d3SJulian Harnath 59172fff6d3SJulian Harnath fPackageListView->AddPackage(package); 59272fff6d3SJulian Harnath if (package->IsProminent()) 59372fff6d3SJulian Harnath fFeaturedPackagesView->AddPackage(package); 59472fff6d3SJulian Harnath } 59572fff6d3SJulian Harnath break; 59672fff6d3SJulian Harnath } 59772fff6d3SJulian Harnath 59872fff6d3SJulian Harnath case MSG_UPDATE_SELECTED_PACKAGE: 59972fff6d3SJulian Harnath { 60072fff6d3SJulian Harnath const PackageInfoRef& selectedPackage = fPackageInfoView->Package(); 60172fff6d3SJulian Harnath fFeaturedPackagesView->SelectPackage(selectedPackage, true); 60272fff6d3SJulian Harnath fPackageListView->SelectPackage(selectedPackage); 60372fff6d3SJulian Harnath 60472fff6d3SJulian Harnath AutoLocker<BLocker> modelLocker(fModel.Lock()); 60572fff6d3SJulian Harnath if (!fVisiblePackages.Contains(fPackageInfoView->Package())) 60672fff6d3SJulian Harnath fPackageInfoView->Clear(); 60772fff6d3SJulian Harnath break; 60872fff6d3SJulian Harnath } 60972fff6d3SJulian Harnath 61004c9d578SStephan Aßmus default: 61104c9d578SStephan Aßmus BWindow::MessageReceived(message); 61204c9d578SStephan Aßmus break; 61304c9d578SStephan Aßmus } 61404c9d578SStephan Aßmus } 61504c9d578SStephan Aßmus 61604c9d578SStephan Aßmus 61704c9d578SStephan Aßmus void 61804c9d578SStephan Aßmus MainWindow::StoreSettings(BMessage& settings) const 61904c9d578SStephan Aßmus { 620f7c2983eSAxel Dörfler settings.AddRect(_WindowFrameName(), Frame()); 621f7c2983eSAxel Dörfler if (!fSinglePackageMode) { 62204c9d578SStephan Aßmus settings.AddRect("window frame", Frame()); 62304c9d578SStephan Aßmus 62404c9d578SStephan Aßmus BMessage columnSettings; 62504c9d578SStephan Aßmus fPackageListView->SaveState(&columnSettings); 62604c9d578SStephan Aßmus 62704c9d578SStephan Aßmus settings.AddMessage("column settings", &columnSettings); 62804c9d578SStephan Aßmus 6292997e05bSStephan Aßmus settings.AddBool("show featured packages", 6302997e05bSStephan Aßmus fModel.ShowFeaturedPackages()); 6312997e05bSStephan Aßmus settings.AddBool("show available packages", 6322997e05bSStephan Aßmus fModel.ShowAvailablePackages()); 6332997e05bSStephan Aßmus settings.AddBool("show installed packages", 6342997e05bSStephan Aßmus fModel.ShowInstalledPackages()); 63504c9d578SStephan Aßmus settings.AddBool("show develop packages", fModel.ShowDevelopPackages()); 63604c9d578SStephan Aßmus settings.AddBool("show source packages", fModel.ShowSourcePackages()); 6376d519fd1SStephan Aßmus } 6388f03a0f9SStephan Aßmus 6398f03a0f9SStephan Aßmus settings.AddString("username", fModel.Username()); 64004c9d578SStephan Aßmus } 64104c9d578SStephan Aßmus 64204c9d578SStephan Aßmus 64304c9d578SStephan Aßmus void 64404c9d578SStephan Aßmus MainWindow::PackageChanged(const PackageInfoEvent& event) 64504c9d578SStephan Aßmus { 646a9edb9bfSAndrew Lindesay uint32 watchedChanges = PKG_CHANGED_STATE | PKG_CHANGED_PROMINENCE; 647a9edb9bfSAndrew Lindesay if ((event.Changes() & watchedChanges) != 0) { 64804c9d578SStephan Aßmus PackageInfoRef ref(event.Package()); 649da651104SStephan Aßmus BMessage message(MSG_PACKAGE_CHANGED); 65004c9d578SStephan Aßmus message.AddPointer("package", ref.Get()); 651da651104SStephan Aßmus message.AddUInt32("changes", event.Changes()); 65204c9d578SStephan Aßmus ref.Detach(); 65304c9d578SStephan Aßmus // reference needs to be released by MessageReceived(); 65404c9d578SStephan Aßmus PostMessage(&message); 65504c9d578SStephan Aßmus } 65604c9d578SStephan Aßmus } 65704c9d578SStephan Aßmus 65804c9d578SStephan Aßmus 65904c9d578SStephan Aßmus status_t 66004c9d578SStephan Aßmus MainWindow::SchedulePackageActions(PackageActionList& list) 66104c9d578SStephan Aßmus { 66204c9d578SStephan Aßmus AutoLocker<BLocker> lock(&fPendingActionsLock); 66304c9d578SStephan Aßmus for (int32 i = 0; i < list.CountItems(); i++) { 66404c9d578SStephan Aßmus if (!fPendingActions.Add(list.ItemAtFast(i))) 66504c9d578SStephan Aßmus return B_NO_MEMORY; 66604c9d578SStephan Aßmus } 66704c9d578SStephan Aßmus 66804c9d578SStephan Aßmus return release_sem_etc(fPendingActionsSem, list.CountItems(), 0); 66904c9d578SStephan Aßmus } 67004c9d578SStephan Aßmus 67104c9d578SStephan Aßmus 67204c9d578SStephan Aßmus Model* 67304c9d578SStephan Aßmus MainWindow::GetModel() 67404c9d578SStephan Aßmus { 67504c9d578SStephan Aßmus return &fModel; 67604c9d578SStephan Aßmus } 67704c9d578SStephan Aßmus 67804c9d578SStephan Aßmus 67904c9d578SStephan Aßmus void 68004c9d578SStephan Aßmus MainWindow::_BuildMenu(BMenuBar* menuBar) 68104c9d578SStephan Aßmus { 68204c9d578SStephan Aßmus BMenu* menu = new BMenu(B_TRANSLATE("Tools")); 6833369e03dSAndrew Lindesay fRefreshRepositoriesItem = new BMenuItem( 6843369e03dSAndrew Lindesay B_TRANSLATE("Refresh repositories"), new BMessage(MSG_REFRESH_REPOS)); 6853369e03dSAndrew Lindesay menu->AddItem(fRefreshRepositoriesItem); 686d7f78130SHumdinger menu->AddItem(new BMenuItem(B_TRANSLATE("Manage repositories" 687d7f78130SHumdinger B_UTF8_ELLIPSIS), new BMessage(MSG_MANAGE_REPOS))); 688d144f952SAugustin Cavalier menu->AddItem(new BMenuItem(B_TRANSLATE("Check for updates" 689d144f952SAugustin Cavalier B_UTF8_ELLIPSIS), new BMessage(MSG_SOFTWARE_UPDATER))); 690e0a26dceSStephan Aßmus 69104c9d578SStephan Aßmus menuBar->AddItem(menu); 69204c9d578SStephan Aßmus 693b965ce70SHumdinger fRepositoryMenu = new BMenu(B_TRANSLATE("Repositories")); 694b965ce70SHumdinger menuBar->AddItem(fRepositoryMenu); 695b965ce70SHumdinger 6964fade61fSStephan Aßmus menu = new BMenu(B_TRANSLATE("Show")); 6974fade61fSStephan Aßmus 698fdec4227SStephan Aßmus fShowAvailablePackagesItem = new BMenuItem( 6994fade61fSStephan Aßmus B_TRANSLATE("Available packages"), 700fdec4227SStephan Aßmus new BMessage(MSG_SHOW_AVAILABLE_PACKAGES)); 701fdec4227SStephan Aßmus menu->AddItem(fShowAvailablePackagesItem); 702fdec4227SStephan Aßmus 703fdec4227SStephan Aßmus fShowInstalledPackagesItem = new BMenuItem( 7044fade61fSStephan Aßmus B_TRANSLATE("Installed packages"), 705fdec4227SStephan Aßmus new BMessage(MSG_SHOW_INSTALLED_PACKAGES)); 706fdec4227SStephan Aßmus menu->AddItem(fShowInstalledPackagesItem); 707fdec4227SStephan Aßmus 708fdec4227SStephan Aßmus menu->AddSeparatorItem(); 709fdec4227SStephan Aßmus 710fdec4227SStephan Aßmus fShowDevelopPackagesItem = new BMenuItem( 7114fade61fSStephan Aßmus B_TRANSLATE("Develop packages"), 712fdec4227SStephan Aßmus new BMessage(MSG_SHOW_DEVELOP_PACKAGES)); 713fdec4227SStephan Aßmus menu->AddItem(fShowDevelopPackagesItem); 714fdec4227SStephan Aßmus 715fdec4227SStephan Aßmus fShowSourcePackagesItem = new BMenuItem( 7164fade61fSStephan Aßmus B_TRANSLATE("Source packages"), 717fdec4227SStephan Aßmus new BMessage(MSG_SHOW_SOURCE_PACKAGES)); 718fdec4227SStephan Aßmus menu->AddItem(fShowSourcePackagesItem); 719fdec4227SStephan Aßmus 720fdec4227SStephan Aßmus menuBar->AddItem(menu); 72104c9d578SStephan Aßmus } 72204c9d578SStephan Aßmus 72304c9d578SStephan Aßmus 72404c9d578SStephan Aßmus void 725e0a26dceSStephan Aßmus MainWindow::_BuildUserMenu(BMenuBar* menuBar) 726e0a26dceSStephan Aßmus { 727e0a26dceSStephan Aßmus fUserMenu = new BMenu(B_TRANSLATE("Not logged in")); 728e0a26dceSStephan Aßmus 729e0a26dceSStephan Aßmus fLogInItem = new BMenuItem(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS), 730e0a26dceSStephan Aßmus new BMessage(MSG_LOG_IN)); 731e0a26dceSStephan Aßmus fUserMenu->AddItem(fLogInItem); 732e0a26dceSStephan Aßmus 733e0a26dceSStephan Aßmus fLogOutItem = new BMenuItem(B_TRANSLATE("Log out"), 734e0a26dceSStephan Aßmus new BMessage(MSG_LOG_OUT)); 735e0a26dceSStephan Aßmus fUserMenu->AddItem(fLogOutItem); 736e0a26dceSStephan Aßmus 737e0a26dceSStephan Aßmus menuBar->AddItem(fUserMenu); 738e0a26dceSStephan Aßmus } 739e0a26dceSStephan Aßmus 740e0a26dceSStephan Aßmus 741e0a26dceSStephan Aßmus void 742f7c2983eSAxel Dörfler MainWindow::_RestoreUserName(const BMessage& settings) 743f7c2983eSAxel Dörfler { 744f7c2983eSAxel Dörfler BString username; 745f7c2983eSAxel Dörfler if (settings.FindString("username", &username) == B_OK 746f7c2983eSAxel Dörfler && username.Length() > 0) { 747f7c2983eSAxel Dörfler fModel.SetUsername(username); 748f7c2983eSAxel Dörfler } 749f7c2983eSAxel Dörfler } 750f7c2983eSAxel Dörfler 751f7c2983eSAxel Dörfler 752f7c2983eSAxel Dörfler const char* 753f7c2983eSAxel Dörfler MainWindow::_WindowFrameName() const 754f7c2983eSAxel Dörfler { 755f7c2983eSAxel Dörfler if (fSinglePackageMode) 756f7c2983eSAxel Dörfler return "small window frame"; 757f7c2983eSAxel Dörfler 758f7c2983eSAxel Dörfler return "window frame"; 759f7c2983eSAxel Dörfler } 760f7c2983eSAxel Dörfler 761f7c2983eSAxel Dörfler 762f7c2983eSAxel Dörfler void 763f7c2983eSAxel Dörfler MainWindow::_RestoreWindowFrame(const BMessage& settings) 764f7c2983eSAxel Dörfler { 765f7c2983eSAxel Dörfler BRect frame = Frame(); 766f7c2983eSAxel Dörfler 767f7c2983eSAxel Dörfler BRect windowFrame; 768f7c2983eSAxel Dörfler bool fromSettings = false; 769f7c2983eSAxel Dörfler if (settings.FindRect(_WindowFrameName(), &windowFrame) == B_OK) { 770f7c2983eSAxel Dörfler frame = windowFrame; 771f7c2983eSAxel Dörfler fromSettings = true; 772f7c2983eSAxel Dörfler } else if (!fSinglePackageMode) { 773f7c2983eSAxel Dörfler // Resize to occupy a certain screen size 774f7c2983eSAxel Dörfler BRect screenFrame = BScreen(this).Frame(); 775f7c2983eSAxel Dörfler float width = frame.Width(); 776f7c2983eSAxel Dörfler float height = frame.Height(); 777f7c2983eSAxel Dörfler if (width < screenFrame.Width() * .666f 778f7c2983eSAxel Dörfler && height < screenFrame.Height() * .666f) { 779f7c2983eSAxel Dörfler frame.bottom = frame.top + screenFrame.Height() * .666f; 780f7c2983eSAxel Dörfler frame.right = frame.left 781f7c2983eSAxel Dörfler + std::min(screenFrame.Width() * .666f, height * 7 / 5); 782f7c2983eSAxel Dörfler } 783f7c2983eSAxel Dörfler } 784f7c2983eSAxel Dörfler 785f7c2983eSAxel Dörfler MoveTo(frame.LeftTop()); 786f7c2983eSAxel Dörfler ResizeTo(frame.Width(), frame.Height()); 787f7c2983eSAxel Dörfler 788f7c2983eSAxel Dörfler if (fromSettings) 7898e96ec34SAxel Dörfler MoveOnScreen(); 790f7c2983eSAxel Dörfler else 791f7c2983eSAxel Dörfler CenterOnScreen(); 792f7c2983eSAxel Dörfler } 793f7c2983eSAxel Dörfler 794f7c2983eSAxel Dörfler 795f7c2983eSAxel Dörfler void 79663975654SStephan Aßmus MainWindow::_InitWorkerThreads() 79763975654SStephan Aßmus { 79863975654SStephan Aßmus fPendingActionsSem = create_sem(0, "PendingPackageActions"); 79963975654SStephan Aßmus if (fPendingActionsSem >= 0) { 80063975654SStephan Aßmus fPendingActionsWorker = spawn_thread(&_PackageActionWorker, 80163975654SStephan Aßmus "Planet Express", B_NORMAL_PRIORITY, this); 80263975654SStephan Aßmus if (fPendingActionsWorker >= 0) 80363975654SStephan Aßmus resume_thread(fPendingActionsWorker); 80409f82905SStephan Aßmus } else 80509f82905SStephan Aßmus fPendingActionsWorker = -1; 80663975654SStephan Aßmus 80763975654SStephan Aßmus fPackageToPopulateSem = create_sem(0, "PopulatePackage"); 80863975654SStephan Aßmus if (fPackageToPopulateSem >= 0) { 80963975654SStephan Aßmus fPopulatePackageWorker = spawn_thread(&_PopulatePackageWorker, 81063975654SStephan Aßmus "Package Populator", B_NORMAL_PRIORITY, this); 81163975654SStephan Aßmus if (fPopulatePackageWorker >= 0) 81263975654SStephan Aßmus resume_thread(fPopulatePackageWorker); 81309f82905SStephan Aßmus } else 81409f82905SStephan Aßmus fPopulatePackageWorker = -1; 81572fff6d3SJulian Harnath 81672fff6d3SJulian Harnath fNewPackagesToShowSem = create_sem(0, "ShowPackages"); 81772fff6d3SJulian Harnath fShowPackagesAcknowledgeSem = create_sem(0, "ShowPackagesAck"); 81872fff6d3SJulian Harnath if (fNewPackagesToShowSem >= 0 && fShowPackagesAcknowledgeSem >= 0) { 81972fff6d3SJulian Harnath fShowPackagesWorker = spawn_thread(&_PackagesToShowWorker, 82072fff6d3SJulian Harnath "Good news everyone", B_NORMAL_PRIORITY, this); 82172fff6d3SJulian Harnath if (fShowPackagesWorker >= 0) 82272fff6d3SJulian Harnath resume_thread(fShowPackagesWorker); 82372fff6d3SJulian Harnath } else 82472fff6d3SJulian Harnath fShowPackagesWorker = -1; 82563975654SStephan Aßmus } 82663975654SStephan Aßmus 82763975654SStephan Aßmus 82863975654SStephan Aßmus void 82904c9d578SStephan Aßmus MainWindow::_AdoptModel() 83004c9d578SStephan Aßmus { 83172fff6d3SJulian Harnath { 83272fff6d3SJulian Harnath AutoLocker<BLocker> modelLocker(fModel.Lock()); 833cd002761SAndrew Lindesay fVisiblePackages = fModel.CreatePackageList(); 83472fff6d3SJulian Harnath AutoLocker<BLocker> listLocker(fPackagesToShowListLock); 83572fff6d3SJulian Harnath fPackagesToShowList = fVisiblePackages; 83672fff6d3SJulian Harnath atomic_add(&fPackagesToShowListID, 1); 83772fff6d3SJulian Harnath } 83872fff6d3SJulian Harnath 8394b930ccaSStephan Aßmus fFeaturedPackagesView->Clear(); 84004c9d578SStephan Aßmus fPackageListView->Clear(); 8414b930ccaSStephan Aßmus 84272fff6d3SJulian Harnath release_sem(fNewPackagesToShowSem); 84304c9d578SStephan Aßmus 84404c9d578SStephan Aßmus BAutolock locker(fModel.Lock()); 845fdec4227SStephan Aßmus fShowAvailablePackagesItem->SetMarked(fModel.ShowAvailablePackages()); 846fdec4227SStephan Aßmus fShowInstalledPackagesItem->SetMarked(fModel.ShowInstalledPackages()); 847fdec4227SStephan Aßmus fShowSourcePackagesItem->SetMarked(fModel.ShowSourcePackages()); 848fdec4227SStephan Aßmus fShowDevelopPackagesItem->SetMarked(fModel.ShowDevelopPackages()); 849da651104SStephan Aßmus 850b965ce70SHumdinger if (fModel.ShowFeaturedPackages()) 851e00a489bSAugustin Cavalier fListTabs->Select(0); 8524fade61fSStephan Aßmus else 853e00a489bSAugustin Cavalier fListTabs->Select(1); 854b965ce70SHumdinger 855b965ce70SHumdinger fFilterView->AdoptModel(fModel); 85604c9d578SStephan Aßmus } 85704c9d578SStephan Aßmus 85804c9d578SStephan Aßmus 85904c9d578SStephan Aßmus void 86004c9d578SStephan Aßmus MainWindow::_AdoptPackage(const PackageInfoRef& package) 86104c9d578SStephan Aßmus { 86275ba9dbfSStephan Aßmus { 86375ba9dbfSStephan Aßmus BAutolock locker(fModel.Lock()); 86404c9d578SStephan Aßmus fPackageInfoView->SetPackage(package); 8651986ab9fSStephan Aßmus 866664372abSStephan Aßmus if (fFeaturedPackagesView != NULL) 867664372abSStephan Aßmus fFeaturedPackagesView->SelectPackage(package); 8681986ab9fSStephan Aßmus if (fPackageListView != NULL) 8691986ab9fSStephan Aßmus fPackageListView->SelectPackage(package); 87075ba9dbfSStephan Aßmus } 87104c9d578SStephan Aßmus 872a9edb9bfSAndrew Lindesay _PopulatePackageAsync(false); 87304c9d578SStephan Aßmus } 87404c9d578SStephan Aßmus 87504c9d578SStephan Aßmus 87604c9d578SStephan Aßmus void 87704c9d578SStephan Aßmus MainWindow::_ClearPackage() 87804c9d578SStephan Aßmus { 87904c9d578SStephan Aßmus fPackageInfoView->Clear(); 88004c9d578SStephan Aßmus } 88104c9d578SStephan Aßmus 88204c9d578SStephan Aßmus 88304c9d578SStephan Aßmus void 8843369e03dSAndrew Lindesay MainWindow::_StopBulkLoad() 88504c9d578SStephan Aßmus { 8863369e03dSAndrew Lindesay AutoLocker<BLocker> lock(&fBulkLoadProcessCoordinatorLock); 887448f707cSStephan Aßmus 8883369e03dSAndrew Lindesay if (fBulkLoadProcessCoordinator != NULL) { 8893369e03dSAndrew Lindesay printf("will stop full update process coordinator\n"); 8903369e03dSAndrew Lindesay fBulkLoadProcessCoordinator->Stop(); 89104c9d578SStephan Aßmus } 89204c9d578SStephan Aßmus } 89304c9d578SStephan Aßmus 89404c9d578SStephan Aßmus 89504c9d578SStephan Aßmus void 8963369e03dSAndrew Lindesay MainWindow::_StartBulkLoad(bool force) 89704c9d578SStephan Aßmus { 8983369e03dSAndrew Lindesay AutoLocker<BLocker> lock(&fBulkLoadProcessCoordinatorLock); 899448f707cSStephan Aßmus 9003369e03dSAndrew Lindesay if (fBulkLoadProcessCoordinator == NULL) { 9013369e03dSAndrew Lindesay fBulkLoadProcessCoordinator 9023369e03dSAndrew Lindesay = ProcessCoordinatorFactory::CreateBulkLoadCoordinator( 9033369e03dSAndrew Lindesay this, 9043369e03dSAndrew Lindesay // PackageInfoListener 9053369e03dSAndrew Lindesay this, 9063369e03dSAndrew Lindesay // ProcessCoordinatorListener 9073369e03dSAndrew Lindesay &fModel, force); 9083369e03dSAndrew Lindesay fBulkLoadProcessCoordinator->Start(); 9093369e03dSAndrew Lindesay fRefreshRepositoriesItem->SetEnabled(false); 9103b17d8ddSAndrew Lindesay } 911ebb1a01cSAndrew Lindesay } 912ebb1a01cSAndrew Lindesay 91304c9d578SStephan Aßmus 9143369e03dSAndrew Lindesay /*! This method is called when there is some change in the bulk load process. 9153369e03dSAndrew Lindesay A change may mean that a new process has started / stopped etc... or it 9163369e03dSAndrew Lindesay may mean that the entire coordinator has finished. 9173369e03dSAndrew Lindesay */ 91804c9d578SStephan Aßmus 9193369e03dSAndrew Lindesay void 9203369e03dSAndrew Lindesay MainWindow::CoordinatorChanged(ProcessCoordinatorState& coordinatorState) 9213369e03dSAndrew Lindesay { 9223369e03dSAndrew Lindesay AutoLocker<BLocker> lock(&fBulkLoadProcessCoordinatorLock); 92304c9d578SStephan Aßmus 9243369e03dSAndrew Lindesay if (fBulkLoadProcessCoordinator == coordinatorState.Coordinator()) { 9253369e03dSAndrew Lindesay if (!coordinatorState.IsRunning()) 9263369e03dSAndrew Lindesay _BulkLoadProcessCoordinatorFinished(coordinatorState); 92704c9d578SStephan Aßmus else { 9283369e03dSAndrew Lindesay _NotifyWorkStatusChange(coordinatorState.Message(), 9293369e03dSAndrew Lindesay coordinatorState.Progress()); 9303369e03dSAndrew Lindesay // show the progress to the user. 931d13c3d89SAndrew Lindesay } 932d13c3d89SAndrew Lindesay } else { 9333369e03dSAndrew Lindesay if (Logger::IsInfoEnabled()) { 9343369e03dSAndrew Lindesay printf("unknown process coordinator changed\n"); 9353b17d8ddSAndrew Lindesay } 936d13c3d89SAndrew Lindesay } 93704c9d578SStephan Aßmus } 93804c9d578SStephan Aßmus 93904c9d578SStephan Aßmus 94004c9d578SStephan Aßmus void 9413369e03dSAndrew Lindesay MainWindow::_BulkLoadProcessCoordinatorFinished( 9423369e03dSAndrew Lindesay ProcessCoordinatorState& coordinatorState) 94304c9d578SStephan Aßmus { 9443369e03dSAndrew Lindesay if (coordinatorState.ErrorStatus() != B_OK) { 9453369e03dSAndrew Lindesay AppUtils::NotifySimpleError( 9463369e03dSAndrew Lindesay B_TRANSLATE("Package Update Error"), 9473369e03dSAndrew Lindesay B_TRANSLATE("While updating package data, a problem has arisen " 9483369e03dSAndrew Lindesay "that may cause data to be outdated or missing from the " 9493369e03dSAndrew Lindesay "application's display. Additional details regarding this " 9503369e03dSAndrew Lindesay "problem may be able to be obtained from the application " 9513369e03dSAndrew Lindesay "logs.")); 95204c9d578SStephan Aßmus } 9533369e03dSAndrew Lindesay BMessenger messenger(this); 9543369e03dSAndrew Lindesay messenger.SendMessage(MSG_BULK_LOAD_DONE); 9553369e03dSAndrew Lindesay // it is safe to delete the coordinator here because it is already known 9563369e03dSAndrew Lindesay // that all of the processes have completed and their threads will have 9573369e03dSAndrew Lindesay // exited safely by this point. 9583369e03dSAndrew Lindesay delete fBulkLoadProcessCoordinator; 9593369e03dSAndrew Lindesay fBulkLoadProcessCoordinator = NULL; 9603369e03dSAndrew Lindesay fRefreshRepositoriesItem->SetEnabled(true); 96104c9d578SStephan Aßmus } 96204c9d578SStephan Aßmus 96304c9d578SStephan Aßmus 9643369e03dSAndrew Lindesay void 9653369e03dSAndrew Lindesay MainWindow::_BulkLoadCompleteReceived() 96604c9d578SStephan Aßmus { 9673369e03dSAndrew Lindesay _AdoptModel(); 9683369e03dSAndrew Lindesay _UpdateAvailableRepositories(); 9693369e03dSAndrew Lindesay fWorkStatusView->SetIdle(); 9703369e03dSAndrew Lindesay } 97104c9d578SStephan Aßmus 97204c9d578SStephan Aßmus 9733369e03dSAndrew Lindesay /*! Sends off a message to the Window so that it can change the status view 9743369e03dSAndrew Lindesay on the front-end in the UI thread. 9753369e03dSAndrew Lindesay */ 97604c9d578SStephan Aßmus 9773369e03dSAndrew Lindesay void 9783369e03dSAndrew Lindesay MainWindow::_NotifyWorkStatusChange(const BString& text, float progress) 9793369e03dSAndrew Lindesay { 9803369e03dSAndrew Lindesay BMessage message(MSG_WORK_STATUS_CHANGE); 98104c9d578SStephan Aßmus 9823369e03dSAndrew Lindesay if (!text.IsEmpty()) 9833369e03dSAndrew Lindesay message.AddString(KEY_WORK_STATUS_TEXT, text); 9843369e03dSAndrew Lindesay message.AddFloat(KEY_WORK_STATUS_PROGRESS, progress); 98504c9d578SStephan Aßmus 9863369e03dSAndrew Lindesay this->PostMessage(&message, this); 9873369e03dSAndrew Lindesay } 98804c9d578SStephan Aßmus 9893369e03dSAndrew Lindesay 9903369e03dSAndrew Lindesay void 9913369e03dSAndrew Lindesay MainWindow::_HandleWorkStatusChangeMessageReceived(const BMessage* message) 9923369e03dSAndrew Lindesay { 9933369e03dSAndrew Lindesay BString text; 9943369e03dSAndrew Lindesay float progress; 9953369e03dSAndrew Lindesay 9963369e03dSAndrew Lindesay if (message->FindString(KEY_WORK_STATUS_TEXT, &text) == B_OK) 9973369e03dSAndrew Lindesay fWorkStatusView->SetText(text); 9983369e03dSAndrew Lindesay 9993369e03dSAndrew Lindesay if (message->FindFloat(KEY_WORK_STATUS_PROGRESS, &progress) == B_OK) 10003369e03dSAndrew Lindesay fWorkStatusView->SetProgress(progress); 100104c9d578SStephan Aßmus } 100204c9d578SStephan Aßmus 100304c9d578SStephan Aßmus 100404c9d578SStephan Aßmus status_t 100504c9d578SStephan Aßmus MainWindow::_PackageActionWorker(void* arg) 100604c9d578SStephan Aßmus { 100704c9d578SStephan Aßmus MainWindow* window = reinterpret_cast<MainWindow*>(arg); 100804c9d578SStephan Aßmus 100904c9d578SStephan Aßmus while (acquire_sem(window->fPendingActionsSem) == B_OK) { 101004c9d578SStephan Aßmus PackageActionRef ref; 101104c9d578SStephan Aßmus { 101204c9d578SStephan Aßmus AutoLocker<BLocker> lock(&window->fPendingActionsLock); 101304c9d578SStephan Aßmus ref = window->fPendingActions.ItemAt(0); 101404c9d578SStephan Aßmus if (ref.Get() == NULL) 101504c9d578SStephan Aßmus break; 101604c9d578SStephan Aßmus window->fPendingActions.Remove(0); 101704c9d578SStephan Aßmus } 101804c9d578SStephan Aßmus 1019125d42d9SJulian Harnath BMessenger messenger(window); 1020125d42d9SJulian Harnath BMessage busyMessage(MSG_PACKAGE_WORKER_BUSY); 1021125d42d9SJulian Harnath BString text(ref->Label()); 1022bc622f6bSHumdinger text << B_UTF8_ELLIPSIS; 1023125d42d9SJulian Harnath busyMessage.AddString("reason", text); 1024125d42d9SJulian Harnath 1025125d42d9SJulian Harnath messenger.SendMessage(&busyMessage); 102604c9d578SStephan Aßmus ref->Perform(); 1027125d42d9SJulian Harnath messenger.SendMessage(MSG_PACKAGE_WORKER_IDLE); 102804c9d578SStephan Aßmus } 102904c9d578SStephan Aßmus 103004c9d578SStephan Aßmus return 0; 103104c9d578SStephan Aßmus } 103204c9d578SStephan Aßmus 103304c9d578SStephan Aßmus 1034a9edb9bfSAndrew Lindesay /*! This method will cause the package to have its data refreshed from 1035a9edb9bfSAndrew Lindesay the server application. The refresh happens in the background; this method 1036a9edb9bfSAndrew Lindesay is asynchronous. 1037a9edb9bfSAndrew Lindesay */ 1038a9edb9bfSAndrew Lindesay 1039a9edb9bfSAndrew Lindesay void 1040a9edb9bfSAndrew Lindesay MainWindow::_PopulatePackageAsync(bool forcePopulate) 1041a9edb9bfSAndrew Lindesay { 1042a9edb9bfSAndrew Lindesay // Trigger asynchronous package population from the web-app 1043a9edb9bfSAndrew Lindesay { 1044a9edb9bfSAndrew Lindesay AutoLocker<BLocker> lock(&fPackageToPopulateLock); 1045a9edb9bfSAndrew Lindesay fPackageToPopulate = fPackageInfoView->Package(); 1046a9edb9bfSAndrew Lindesay fForcePopulatePackage = forcePopulate; 1047a9edb9bfSAndrew Lindesay } 1048a9edb9bfSAndrew Lindesay release_sem_etc(fPackageToPopulateSem, 1, 0); 1049a9edb9bfSAndrew Lindesay 1050a9edb9bfSAndrew Lindesay if (Logger::IsDebugEnabled()) { 1051a9edb9bfSAndrew Lindesay printf("pkg [%s] will be updated from the server.\n", 1052a9edb9bfSAndrew Lindesay fPackageToPopulate->Name().String()); 1053a9edb9bfSAndrew Lindesay } 1054a9edb9bfSAndrew Lindesay } 1055a9edb9bfSAndrew Lindesay 1056a9edb9bfSAndrew Lindesay 1057a9edb9bfSAndrew Lindesay /*! This method will run in the background. The thread will block until there 1058a9edb9bfSAndrew Lindesay is a package to be updated. When the thread unblocks, it will update the 1059a9edb9bfSAndrew Lindesay package with information from the server. 1060a9edb9bfSAndrew Lindesay */ 1061a9edb9bfSAndrew Lindesay 106204c9d578SStephan Aßmus status_t 106304c9d578SStephan Aßmus MainWindow::_PopulatePackageWorker(void* arg) 106404c9d578SStephan Aßmus { 106504c9d578SStephan Aßmus MainWindow* window = reinterpret_cast<MainWindow*>(arg); 106604c9d578SStephan Aßmus 106704c9d578SStephan Aßmus while (acquire_sem(window->fPackageToPopulateSem) == B_OK) { 106804c9d578SStephan Aßmus PackageInfoRef package; 1069a9edb9bfSAndrew Lindesay bool force; 107004c9d578SStephan Aßmus { 107104c9d578SStephan Aßmus AutoLocker<BLocker> lock(&window->fPackageToPopulateLock); 107204c9d578SStephan Aßmus package = window->fPackageToPopulate; 1073a9edb9bfSAndrew Lindesay force = window->fForcePopulatePackage; 107404c9d578SStephan Aßmus } 107504c9d578SStephan Aßmus 107604c9d578SStephan Aßmus if (package.Get() != NULL) { 1077a9edb9bfSAndrew Lindesay uint32 populateFlags = Model::POPULATE_USER_RATINGS 1078a9edb9bfSAndrew Lindesay | Model::POPULATE_SCREEN_SHOTS 1079a9edb9bfSAndrew Lindesay | Model::POPULATE_CHANGELOG; 1080a9edb9bfSAndrew Lindesay 1081a9edb9bfSAndrew Lindesay if (force) 1082a9edb9bfSAndrew Lindesay populateFlags |= Model::POPULATE_FORCE; 1083a9edb9bfSAndrew Lindesay 1084a9edb9bfSAndrew Lindesay window->fModel.PopulatePackage(package, populateFlags); 1085a9edb9bfSAndrew Lindesay 1086a9edb9bfSAndrew Lindesay if (Logger::IsDebugEnabled()) { 1087a9edb9bfSAndrew Lindesay printf("populating package [%s]\n", 1088a9edb9bfSAndrew Lindesay package->Name().String()); 1089a9edb9bfSAndrew Lindesay } 109004c9d578SStephan Aßmus } 109104c9d578SStephan Aßmus } 109204c9d578SStephan Aßmus 109304c9d578SStephan Aßmus return 0; 109404c9d578SStephan Aßmus } 109504c9d578SStephan Aßmus 109604c9d578SStephan Aßmus 109772fff6d3SJulian Harnath /* static */ status_t 109872fff6d3SJulian Harnath MainWindow::_PackagesToShowWorker(void* arg) 109972fff6d3SJulian Harnath { 110072fff6d3SJulian Harnath MainWindow* window = reinterpret_cast<MainWindow*>(arg); 110172fff6d3SJulian Harnath 110272fff6d3SJulian Harnath while (acquire_sem(window->fNewPackagesToShowSem) == B_OK) { 110372fff6d3SJulian Harnath PackageList packageList; 110472fff6d3SJulian Harnath int32 listID = 0; 110572fff6d3SJulian Harnath { 110672fff6d3SJulian Harnath AutoLocker<BLocker> lock(&window->fPackagesToShowListLock); 110772fff6d3SJulian Harnath packageList = window->fPackagesToShowList; 110872fff6d3SJulian Harnath listID = atomic_get(&window->fPackagesToShowListID); 110972fff6d3SJulian Harnath window->fPackagesToShowList.Clear(); 111072fff6d3SJulian Harnath } 111172fff6d3SJulian Harnath 111272fff6d3SJulian Harnath // Add packages to list views in batches of kPackagesPerUpdate so we 111372fff6d3SJulian Harnath // don't block the window thread for long with each iteration 111472fff6d3SJulian Harnath enum { 111572fff6d3SJulian Harnath kPackagesPerUpdate = 20 111672fff6d3SJulian Harnath }; 111772fff6d3SJulian Harnath uint32 packagesInMessage = 0; 111872fff6d3SJulian Harnath BMessage message(MSG_ADD_VISIBLE_PACKAGES); 111972fff6d3SJulian Harnath BMessenger messenger(window); 112072fff6d3SJulian Harnath bool listIsOutdated = false; 112172fff6d3SJulian Harnath 112272fff6d3SJulian Harnath for (int i = 0; i < packageList.CountItems(); i++) { 112372fff6d3SJulian Harnath const PackageInfoRef& package = packageList.ItemAtFast(i); 112472fff6d3SJulian Harnath 112572fff6d3SJulian Harnath if (packagesInMessage >= kPackagesPerUpdate) { 112672fff6d3SJulian Harnath if (listID != atomic_get(&window->fPackagesToShowListID)) { 112772fff6d3SJulian Harnath // The model was changed again in the meantime, and thus 112872fff6d3SJulian Harnath // our package list isn't current anymore. Send no further 112972fff6d3SJulian Harnath // messags based on this list and go back to start. 113072fff6d3SJulian Harnath listIsOutdated = true; 113172fff6d3SJulian Harnath break; 113272fff6d3SJulian Harnath } 113372fff6d3SJulian Harnath 113472fff6d3SJulian Harnath message.AddInt32("list_id", listID); 113572fff6d3SJulian Harnath messenger.SendMessage(&message); 113672fff6d3SJulian Harnath message.MakeEmpty(); 113772fff6d3SJulian Harnath packagesInMessage = 0; 113872fff6d3SJulian Harnath 113972fff6d3SJulian Harnath // Don't spam the window's message queue, which would make it 114072fff6d3SJulian Harnath // unresponsive (i.e. allows UI messages to get in between our 114172fff6d3SJulian Harnath // messages). When it has processed the message we just sent, 114272fff6d3SJulian Harnath // it will let us know by releasing the semaphore. 114372fff6d3SJulian Harnath acquire_sem(window->fShowPackagesAcknowledgeSem); 114472fff6d3SJulian Harnath } 114572fff6d3SJulian Harnath package->AcquireReference(); 114672fff6d3SJulian Harnath message.AddPointer("package_ref", package.Get()); 114772fff6d3SJulian Harnath packagesInMessage++; 114872fff6d3SJulian Harnath } 114972fff6d3SJulian Harnath 115072fff6d3SJulian Harnath if (listIsOutdated) 115172fff6d3SJulian Harnath continue; 115272fff6d3SJulian Harnath 115372fff6d3SJulian Harnath // Send remaining package infos, if any, which didn't make it into 115472fff6d3SJulian Harnath // the last message (count < kPackagesPerUpdate) 115572fff6d3SJulian Harnath if (packagesInMessage > 0) { 115672fff6d3SJulian Harnath message.AddInt32("list_id", listID); 115772fff6d3SJulian Harnath messenger.SendMessage(&message); 115872fff6d3SJulian Harnath acquire_sem(window->fShowPackagesAcknowledgeSem); 115972fff6d3SJulian Harnath } 116072fff6d3SJulian Harnath 116172fff6d3SJulian Harnath // Update selected package in list views 116272fff6d3SJulian Harnath messenger.SendMessage(MSG_UPDATE_SELECTED_PACKAGE); 116372fff6d3SJulian Harnath } 116472fff6d3SJulian Harnath 116572fff6d3SJulian Harnath return 0; 116672fff6d3SJulian Harnath } 116772fff6d3SJulian Harnath 116872fff6d3SJulian Harnath 116904c9d578SStephan Aßmus void 11701bbda92dSStephan Aßmus MainWindow::_OpenLoginWindow(const BMessage& onSuccessMessage) 117104c9d578SStephan Aßmus { 117204c9d578SStephan Aßmus UserLoginWindow* window = new UserLoginWindow(this, 117304c9d578SStephan Aßmus BRect(0, 0, 500, 400), fModel); 11741bbda92dSStephan Aßmus 11751bbda92dSStephan Aßmus if (onSuccessMessage.what != 0) 11761bbda92dSStephan Aßmus window->SetOnSuccessMessage(BMessenger(this), onSuccessMessage); 11771bbda92dSStephan Aßmus 117804c9d578SStephan Aßmus window->Show(); 117904c9d578SStephan Aßmus } 118004c9d578SStephan Aßmus 11818f03a0f9SStephan Aßmus 11828f03a0f9SStephan Aßmus void 11838f03a0f9SStephan Aßmus MainWindow::_UpdateAuthorization() 11848f03a0f9SStephan Aßmus { 11858f03a0f9SStephan Aßmus BString username(fModel.Username()); 1186e0a26dceSStephan Aßmus bool hasUser = !username.IsEmpty(); 1187e0a26dceSStephan Aßmus 11886d519fd1SStephan Aßmus if (fLogOutItem != NULL) 1189e0a26dceSStephan Aßmus fLogOutItem->SetEnabled(hasUser); 1190e0a26dceSStephan Aßmus if (fLogInItem != NULL) { 1191e0a26dceSStephan Aßmus if (hasUser) 1192e0a26dceSStephan Aßmus fLogInItem->SetLabel(B_TRANSLATE("Switch account" B_UTF8_ELLIPSIS)); 1193e0a26dceSStephan Aßmus else 1194e0a26dceSStephan Aßmus fLogInItem->SetLabel(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS)); 1195e0a26dceSStephan Aßmus } 1196e0a26dceSStephan Aßmus 1197e0a26dceSStephan Aßmus if (fUserMenu != NULL) { 1198e0a26dceSStephan Aßmus BString label; 1199e0a26dceSStephan Aßmus if (username.Length() == 0) { 1200e0a26dceSStephan Aßmus label = B_TRANSLATE("Not logged in"); 1201e0a26dceSStephan Aßmus } else { 1202e0a26dceSStephan Aßmus label = B_TRANSLATE("Logged in as %User%"); 1203e0a26dceSStephan Aßmus label.ReplaceAll("%User%", username); 1204e0a26dceSStephan Aßmus } 1205e0a26dceSStephan Aßmus fUserMenu->Superitem()->SetLabel(label); 1206e0a26dceSStephan Aßmus } 12078f03a0f9SStephan Aßmus } 12081bbda92dSStephan Aßmus 12091bbda92dSStephan Aßmus 12101bbda92dSStephan Aßmus void 1211b965ce70SHumdinger MainWindow::_UpdateAvailableRepositories() 1212b965ce70SHumdinger { 1213b965ce70SHumdinger fRepositoryMenu->RemoveItems(0, fRepositoryMenu->CountItems(), true); 1214b965ce70SHumdinger 1215b965ce70SHumdinger fRepositoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All repositories"), 1216b965ce70SHumdinger new BMessage(MSG_DEPOT_SELECTED))); 1217b965ce70SHumdinger 1218b965ce70SHumdinger fRepositoryMenu->AddItem(new BSeparatorItem()); 1219b965ce70SHumdinger 1220b965ce70SHumdinger bool foundSelectedDepot = false; 1221b965ce70SHumdinger const DepotList& depots = fModel.Depots(); 1222b965ce70SHumdinger for (int i = 0; i < depots.CountItems(); i++) { 1223b965ce70SHumdinger const DepotInfo& depot = depots.ItemAtFast(i); 1224d13c3d89SAndrew Lindesay 1225d13c3d89SAndrew Lindesay if (depot.Name().Length() != 0) { 1226b965ce70SHumdinger BMessage* message = new BMessage(MSG_DEPOT_SELECTED); 1227b965ce70SHumdinger message->AddString("name", depot.Name()); 1228b965ce70SHumdinger BMenuItem* item = new BMenuItem(depot.Name(), message); 1229b965ce70SHumdinger fRepositoryMenu->AddItem(item); 1230b965ce70SHumdinger 1231b965ce70SHumdinger if (depot.Name() == fModel.Depot()) { 1232b965ce70SHumdinger item->SetMarked(true); 1233b965ce70SHumdinger foundSelectedDepot = true; 1234b965ce70SHumdinger } 1235b965ce70SHumdinger } 1236d13c3d89SAndrew Lindesay } 1237b965ce70SHumdinger 1238b965ce70SHumdinger if (!foundSelectedDepot) 1239b965ce70SHumdinger fRepositoryMenu->ItemAt(0)->SetMarked(true); 1240b965ce70SHumdinger } 1241b965ce70SHumdinger 1242b965ce70SHumdinger 1243a9edb9bfSAndrew Lindesay bool 1244a9edb9bfSAndrew Lindesay MainWindow::_SelectedPackageHasWebAppRepositoryCode() 1245a9edb9bfSAndrew Lindesay { 1246a9edb9bfSAndrew Lindesay const PackageInfoRef& package = fPackageInfoView->Package(); 12476ab878c0SAndrew Lindesay const BString depotName = package->DepotName(); 1248a9edb9bfSAndrew Lindesay 12496ab878c0SAndrew Lindesay if (depotName.IsEmpty()) { 12506ab878c0SAndrew Lindesay if (Logger::IsDebugEnabled()) { 12516ab878c0SAndrew Lindesay printf("the package [%s] has no depot name\n", 12526ab878c0SAndrew Lindesay package->Name().String()); 12536ab878c0SAndrew Lindesay } 12546ab878c0SAndrew Lindesay } else { 12556ab878c0SAndrew Lindesay const DepotInfo* depot = fModel.DepotForName(depotName); 1256a9edb9bfSAndrew Lindesay 12576ab878c0SAndrew Lindesay if (depot == NULL) { 12586ab878c0SAndrew Lindesay printf("the depot [%s] was not able to be found\n", 12596ab878c0SAndrew Lindesay depotName.String()); 12606ab878c0SAndrew Lindesay } else { 12616ab878c0SAndrew Lindesay BString repositoryCode = depot->WebAppRepositoryCode(); 1262a9edb9bfSAndrew Lindesay 12636ab878c0SAndrew Lindesay if (repositoryCode.IsEmpty()) { 12646ab878c0SAndrew Lindesay printf("the depot [%s] has no web app repository code\n", 12656ab878c0SAndrew Lindesay depotName.String()); 12666ab878c0SAndrew Lindesay } else { 12676ab878c0SAndrew Lindesay return true; 12686ab878c0SAndrew Lindesay } 12696ab878c0SAndrew Lindesay } 12706ab878c0SAndrew Lindesay } 12716ab878c0SAndrew Lindesay 12726ab878c0SAndrew Lindesay return false; 1273a9edb9bfSAndrew Lindesay } 1274a9edb9bfSAndrew Lindesay 1275a9edb9bfSAndrew Lindesay 1276b965ce70SHumdinger void 12771bbda92dSStephan Aßmus MainWindow::_RatePackage() 12781bbda92dSStephan Aßmus { 1279a9edb9bfSAndrew Lindesay if (!_SelectedPackageHasWebAppRepositoryCode()) { 1280a9edb9bfSAndrew Lindesay BAlert* alert = new(std::nothrow) BAlert( 1281cbadcae1SHumdinger B_TRANSLATE("Rating not possible"), 1282cbadcae1SHumdinger B_TRANSLATE("This package doesn't seem to be on the HaikuDepot " 1283cbadcae1SHumdinger "Server, so it's not possible to create a new rating " 1284cbadcae1SHumdinger "or edit an existing rating."), 1285a9edb9bfSAndrew Lindesay B_TRANSLATE("OK")); 1286a9edb9bfSAndrew Lindesay alert->Go(); 1287a9edb9bfSAndrew Lindesay return; 1288a9edb9bfSAndrew Lindesay } 1289a9edb9bfSAndrew Lindesay 12901bbda92dSStephan Aßmus if (fModel.Username().IsEmpty()) { 12911bbda92dSStephan Aßmus BAlert* alert = new(std::nothrow) BAlert( 12921bbda92dSStephan Aßmus B_TRANSLATE("Not logged in"), 12931bbda92dSStephan Aßmus B_TRANSLATE("You need to be logged into an account before you " 12941bbda92dSStephan Aßmus "can rate packages."), 12951bbda92dSStephan Aßmus B_TRANSLATE("Cancel"), 12961bbda92dSStephan Aßmus B_TRANSLATE("Login or Create account")); 12971bbda92dSStephan Aßmus 12981bbda92dSStephan Aßmus if (alert == NULL) 12991bbda92dSStephan Aßmus return; 13001bbda92dSStephan Aßmus 13011bbda92dSStephan Aßmus int32 choice = alert->Go(); 13021bbda92dSStephan Aßmus if (choice == 1) 13031bbda92dSStephan Aßmus _OpenLoginWindow(BMessage(MSG_RATE_PACKAGE)); 13041bbda92dSStephan Aßmus return; 13051bbda92dSStephan Aßmus } 13061bbda92dSStephan Aßmus 13071bbda92dSStephan Aßmus // TODO: Allow only one RatePackageWindow 13081bbda92dSStephan Aßmus // TODO: Mechanism for remembering the window frame 13091bbda92dSStephan Aßmus RatePackageWindow* window = new RatePackageWindow(this, 13101bbda92dSStephan Aßmus BRect(0, 0, 500, 400), fModel); 13111bbda92dSStephan Aßmus window->SetPackage(fPackageInfoView->Package()); 13121bbda92dSStephan Aßmus window->Show(); 13131bbda92dSStephan Aßmus } 1314d5ef985eSStephan Aßmus 1315d5ef985eSStephan Aßmus 1316d5ef985eSStephan Aßmus void 1317d5ef985eSStephan Aßmus MainWindow::_ShowScreenshot() 1318d5ef985eSStephan Aßmus { 1319d5ef985eSStephan Aßmus // TODO: Mechanism for remembering the window frame 1320d5ef985eSStephan Aßmus if (fScreenshotWindow == NULL) 1321d5ef985eSStephan Aßmus fScreenshotWindow = new ScreenshotWindow(this, BRect(0, 0, 500, 400)); 1322d5ef985eSStephan Aßmus 1323d5ef985eSStephan Aßmus if (fScreenshotWindow->LockWithTimeout(1000) != B_OK) 1324d5ef985eSStephan Aßmus return; 1325d5ef985eSStephan Aßmus 1326d5ef985eSStephan Aßmus fScreenshotWindow->SetPackage(fPackageInfoView->Package()); 1327d5ef985eSStephan Aßmus 1328d5ef985eSStephan Aßmus if (fScreenshotWindow->IsHidden()) 1329d5ef985eSStephan Aßmus fScreenshotWindow->Show(); 1330d5ef985eSStephan Aßmus else 1331d5ef985eSStephan Aßmus fScreenshotWindow->Activate(); 1332d5ef985eSStephan Aßmus 1333d5ef985eSStephan Aßmus fScreenshotWindow->Unlock(); 1334d5ef985eSStephan Aßmus } 1335