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