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