xref: /haiku/src/apps/haikudepot/ui/MainWindow.cpp (revision 1bbda92dc72e7b14358c38db78373923ecb806fa)
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>
1904c9d578SStephan Aßmus #include <LayoutBuilder.h>
2004c9d578SStephan Aßmus #include <MenuBar.h>
2104c9d578SStephan Aßmus #include <MenuItem.h>
2204c9d578SStephan Aßmus #include <Messenger.h>
2304c9d578SStephan Aßmus #include <ScrollView.h>
2404c9d578SStephan Aßmus #include <StringList.h>
2504c9d578SStephan Aßmus #include <TabView.h>
2604c9d578SStephan Aßmus 
2704c9d578SStephan Aßmus #include <package/Context.h>
2804c9d578SStephan Aßmus #include <package/manager/Exceptions.h>
2904c9d578SStephan Aßmus #include <package/manager/RepositoryBuilder.h>
3004c9d578SStephan Aßmus #include <package/RefreshRepositoryRequest.h>
3104c9d578SStephan Aßmus #include <package/PackageRoster.h>
3204c9d578SStephan Aßmus #include "package/RepositoryCache.h"
3304c9d578SStephan Aßmus #include <package/solver/SolverPackage.h>
3404c9d578SStephan Aßmus #include <package/solver/SolverProblem.h>
3504c9d578SStephan Aßmus #include <package/solver/SolverProblemSolution.h>
3604c9d578SStephan Aßmus #include <package/solver/SolverRepository.h>
3704c9d578SStephan Aßmus #include <package/solver/SolverResult.h>
3804c9d578SStephan Aßmus 
3904c9d578SStephan Aßmus #include "AutoDeleter.h"
4004c9d578SStephan Aßmus #include "AutoLocker.h"
4104c9d578SStephan Aßmus #include "DecisionProvider.h"
4204c9d578SStephan Aßmus #include "FilterView.h"
4304c9d578SStephan Aßmus #include "JobStateListener.h"
4404c9d578SStephan Aßmus #include "PackageInfoView.h"
4504c9d578SStephan Aßmus #include "PackageListView.h"
4604c9d578SStephan Aßmus #include "PackageManager.h"
4704c9d578SStephan Aßmus #include "RatePackageWindow.h"
4804c9d578SStephan Aßmus #include "UserLoginWindow.h"
4904c9d578SStephan Aßmus 
5004c9d578SStephan Aßmus 
5104c9d578SStephan Aßmus #undef B_TRANSLATION_CONTEXT
5204c9d578SStephan Aßmus #define B_TRANSLATION_CONTEXT "MainWindow"
5304c9d578SStephan Aßmus 
5404c9d578SStephan Aßmus 
5504c9d578SStephan Aßmus enum {
5604c9d578SStephan Aßmus 	MSG_MODEL_WORKER_DONE		= 'mmwd',
5704c9d578SStephan Aßmus 	MSG_REFRESH_DEPOTS			= 'mrdp',
5804c9d578SStephan Aßmus 	MSG_LOG_IN					= 'lgin',
598f03a0f9SStephan Aßmus 	MSG_LOG_OUT					= 'lgot',
608f03a0f9SStephan Aßmus 	MSG_AUTHORIZATION_CHANGED	= 'athc',
6104c9d578SStephan Aßmus 	MSG_PACKAGE_STATE_CHANGED	= 'mpsc',
6204c9d578SStephan Aßmus 	MSG_SHOW_SOURCE_PACKAGES	= 'ssrc',
6304c9d578SStephan Aßmus 	MSG_SHOW_DEVELOP_PACKAGES	= 'sdvl'
6404c9d578SStephan Aßmus };
6504c9d578SStephan Aßmus 
6604c9d578SStephan Aßmus 
6704c9d578SStephan Aßmus using namespace BPackageKit;
6804c9d578SStephan Aßmus using namespace BPackageKit::BManager::BPrivate;
6904c9d578SStephan Aßmus 
7004c9d578SStephan Aßmus 
7104c9d578SStephan Aßmus typedef std::map<BString, PackageInfoRef> PackageInfoMap;
7204c9d578SStephan Aßmus typedef std::map<BString, DepotInfo> DepotInfoMap;
7304c9d578SStephan Aßmus 
7404c9d578SStephan Aßmus 
7504c9d578SStephan Aßmus struct RefreshWorkerParameters {
7604c9d578SStephan Aßmus 	MainWindow* window;
7704c9d578SStephan Aßmus 	bool forceRefresh;
7804c9d578SStephan Aßmus 
7904c9d578SStephan Aßmus 	RefreshWorkerParameters(MainWindow* window, bool forceRefresh)
8004c9d578SStephan Aßmus 		:
8104c9d578SStephan Aßmus 		window(window),
8204c9d578SStephan Aßmus 		forceRefresh(forceRefresh)
8304c9d578SStephan Aßmus 	{
8404c9d578SStephan Aßmus 	}
8504c9d578SStephan Aßmus };
8604c9d578SStephan Aßmus 
8704c9d578SStephan Aßmus 
888f03a0f9SStephan Aßmus class MessageModelListener : public ModelListener {
898f03a0f9SStephan Aßmus public:
908f03a0f9SStephan Aßmus 	MessageModelListener(const BMessenger& messenger)
918f03a0f9SStephan Aßmus 		:
928f03a0f9SStephan Aßmus 		fMessenger(messenger)
938f03a0f9SStephan Aßmus 	{
948f03a0f9SStephan Aßmus 	}
958f03a0f9SStephan Aßmus 
968f03a0f9SStephan Aßmus 	virtual void AuthorizationChanged()
978f03a0f9SStephan Aßmus 	{
988f03a0f9SStephan Aßmus 		if (fMessenger.IsValid())
998f03a0f9SStephan Aßmus 			fMessenger.SendMessage(MSG_AUTHORIZATION_CHANGED);
1008f03a0f9SStephan Aßmus 	}
1018f03a0f9SStephan Aßmus 
1028f03a0f9SStephan Aßmus private:
1038f03a0f9SStephan Aßmus 	BMessenger	fMessenger;
1048f03a0f9SStephan Aßmus };
1058f03a0f9SStephan Aßmus 
1068f03a0f9SStephan Aßmus 
10704c9d578SStephan Aßmus MainWindow::MainWindow(BRect frame, const BMessage& settings)
10804c9d578SStephan Aßmus 	:
10904c9d578SStephan Aßmus 	BWindow(frame, B_TRANSLATE_SYSTEM_NAME("HaikuDepot"),
11004c9d578SStephan Aßmus 		B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
11104c9d578SStephan Aßmus 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
1128f03a0f9SStephan Aßmus 	fModelListener(new MessageModelListener(BMessenger(this)), true),
11304c9d578SStephan Aßmus 	fTerminating(false),
11404c9d578SStephan Aßmus 	fModelWorker(B_BAD_THREAD_ID)
11504c9d578SStephan Aßmus {
11604c9d578SStephan Aßmus 	BMenuBar* menuBar = new BMenuBar(B_TRANSLATE("Main Menu"));
11704c9d578SStephan Aßmus 	_BuildMenu(menuBar);
11804c9d578SStephan Aßmus 
11904c9d578SStephan Aßmus 	fFilterView = new FilterView();
12004c9d578SStephan Aßmus 	fPackageListView = new PackageListView(fModel.Lock());
12104c9d578SStephan Aßmus 	fPackageInfoView = new PackageInfoView(fModel.Lock(), this);
12204c9d578SStephan Aßmus 
12304c9d578SStephan Aßmus 	fSplitView = new BSplitView(B_VERTICAL, 5.0f);
12404c9d578SStephan Aßmus 
12504c9d578SStephan Aßmus 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f)
12604c9d578SStephan Aßmus 		.Add(menuBar)
12704c9d578SStephan Aßmus 		.Add(fFilterView)
12804c9d578SStephan Aßmus 		.AddSplit(fSplitView)
12904c9d578SStephan Aßmus 			.AddGroup(B_VERTICAL)
13004c9d578SStephan Aßmus 				.Add(fPackageListView)
13104c9d578SStephan Aßmus 				.SetInsets(
13204c9d578SStephan Aßmus 					B_USE_DEFAULT_SPACING, 0.0f,
13304c9d578SStephan Aßmus 					B_USE_DEFAULT_SPACING, 0.0f)
13404c9d578SStephan Aßmus 			.End()
13504c9d578SStephan Aßmus 			.Add(fPackageInfoView)
13604c9d578SStephan Aßmus 		.End()
13704c9d578SStephan Aßmus 	;
13804c9d578SStephan Aßmus 
13904c9d578SStephan Aßmus 	fSplitView->SetCollapsible(0, false);
14004c9d578SStephan Aßmus 	fSplitView->SetCollapsible(1, false);
14104c9d578SStephan Aßmus 
1428f03a0f9SStephan Aßmus 	fModel.AddListener(fModelListener);
1438f03a0f9SStephan Aßmus 
14404c9d578SStephan Aßmus 	// Restore settings
14504c9d578SStephan Aßmus 	BMessage columnSettings;
14604c9d578SStephan Aßmus 	if (settings.FindMessage("column settings", &columnSettings) == B_OK)
14704c9d578SStephan Aßmus 		fPackageListView->LoadState(&columnSettings);
14804c9d578SStephan Aßmus 
14904c9d578SStephan Aßmus 	bool showOption;
15004c9d578SStephan Aßmus 	if (settings.FindBool("show develop packages", &showOption) == B_OK)
15104c9d578SStephan Aßmus 		fModel.SetShowDevelopPackages(showOption);
15204c9d578SStephan Aßmus 	if (settings.FindBool("show source packages", &showOption) == B_OK)
15304c9d578SStephan Aßmus 		fModel.SetShowSourcePackages(showOption);
15404c9d578SStephan Aßmus 
1558f03a0f9SStephan Aßmus 	BString username;
1568f03a0f9SStephan Aßmus 	if (settings.FindString("username", &username) == B_OK
1578f03a0f9SStephan Aßmus 		&& username.Length() > 0) {
1588f03a0f9SStephan Aßmus 		fModel.SetUsername(username);
1598f03a0f9SStephan Aßmus 	}
1608f03a0f9SStephan Aßmus 
1618f03a0f9SStephan Aßmus 	// start worker threads
16204c9d578SStephan Aßmus 	BPackageRoster().StartWatching(this,
16304c9d578SStephan Aßmus 		B_WATCH_PACKAGE_INSTALLATION_LOCATIONS);
16404c9d578SStephan Aßmus 
16504c9d578SStephan Aßmus 	_StartRefreshWorker();
16604c9d578SStephan Aßmus 
16704c9d578SStephan Aßmus 	fPendingActionsSem = create_sem(0, "PendingPackageActions");
16804c9d578SStephan Aßmus 	if (fPendingActionsSem >= 0) {
16904c9d578SStephan Aßmus 		fPendingActionsWorker = spawn_thread(&_PackageActionWorker,
17004c9d578SStephan Aßmus 			"Planet Express", B_NORMAL_PRIORITY, this);
17104c9d578SStephan Aßmus 		if (fPendingActionsWorker >= 0)
17204c9d578SStephan Aßmus 			resume_thread(fPendingActionsWorker);
17304c9d578SStephan Aßmus 	}
17404c9d578SStephan Aßmus 
17504c9d578SStephan Aßmus 	fPackageToPopulateSem = create_sem(0, "PopulatePackage");
17604c9d578SStephan Aßmus 	if (fPackageToPopulateSem >= 0) {
17704c9d578SStephan Aßmus 		fPopulatePackageWorker = spawn_thread(&_PopulatePackageWorker,
17804c9d578SStephan Aßmus 			"Package Populator", B_NORMAL_PRIORITY, this);
17904c9d578SStephan Aßmus 		if (fPopulatePackageWorker >= 0)
18004c9d578SStephan Aßmus 			resume_thread(fPopulatePackageWorker);
18104c9d578SStephan Aßmus 	}
18204c9d578SStephan Aßmus }
18304c9d578SStephan Aßmus 
18404c9d578SStephan Aßmus 
18504c9d578SStephan Aßmus MainWindow::~MainWindow()
18604c9d578SStephan Aßmus {
18704c9d578SStephan Aßmus 	BPackageRoster().StopWatching(this);
18804c9d578SStephan Aßmus 
18904c9d578SStephan Aßmus 	fTerminating = true;
19004c9d578SStephan Aßmus 	if (fModelWorker > 0)
19104c9d578SStephan Aßmus 		wait_for_thread(fModelWorker, NULL);
19204c9d578SStephan Aßmus 
19304c9d578SStephan Aßmus 	delete_sem(fPendingActionsSem);
19404c9d578SStephan Aßmus 	wait_for_thread(fPendingActionsWorker, NULL);
19504c9d578SStephan Aßmus 
19604c9d578SStephan Aßmus 	delete_sem(fPackageToPopulateSem);
19704c9d578SStephan Aßmus 	wait_for_thread(fPopulatePackageWorker, NULL);
19804c9d578SStephan Aßmus }
19904c9d578SStephan Aßmus 
20004c9d578SStephan Aßmus 
20104c9d578SStephan Aßmus bool
20204c9d578SStephan Aßmus MainWindow::QuitRequested()
20304c9d578SStephan Aßmus {
20404c9d578SStephan Aßmus 	BMessage settings;
20504c9d578SStephan Aßmus 	StoreSettings(settings);
20604c9d578SStephan Aßmus 
20704c9d578SStephan Aßmus 	BMessage message(MSG_MAIN_WINDOW_CLOSED);
20804c9d578SStephan Aßmus 	message.AddMessage("window settings", &settings);
20904c9d578SStephan Aßmus 
21004c9d578SStephan Aßmus 	be_app->PostMessage(&message);
21104c9d578SStephan Aßmus 
21204c9d578SStephan Aßmus 	return true;
21304c9d578SStephan Aßmus }
21404c9d578SStephan Aßmus 
21504c9d578SStephan Aßmus 
21604c9d578SStephan Aßmus void
21704c9d578SStephan Aßmus MainWindow::MessageReceived(BMessage* message)
21804c9d578SStephan Aßmus {
21904c9d578SStephan Aßmus 	switch (message->what) {
22004c9d578SStephan Aßmus 		case MSG_MODEL_WORKER_DONE:
22104c9d578SStephan Aßmus 		{
22204c9d578SStephan Aßmus 			fModelWorker = B_BAD_THREAD_ID;
22304c9d578SStephan Aßmus 			_AdoptModel();
22404c9d578SStephan Aßmus 			fFilterView->AdoptModel(fModel);
22504c9d578SStephan Aßmus 			break;
22604c9d578SStephan Aßmus 		}
22704c9d578SStephan Aßmus 		case B_SIMPLE_DATA:
22804c9d578SStephan Aßmus 		case B_REFS_RECEIVED:
22904c9d578SStephan Aßmus 			// TODO: ?
23004c9d578SStephan Aßmus 			break;
23104c9d578SStephan Aßmus 
23204c9d578SStephan Aßmus 		case B_PACKAGE_UPDATE:
23304c9d578SStephan Aßmus 			// TODO: We should do a more selective update depending on the
23404c9d578SStephan Aßmus 			// "event", "location", and "change count" fields!
23504c9d578SStephan Aßmus 			_StartRefreshWorker(false);
23604c9d578SStephan Aßmus 			break;
23704c9d578SStephan Aßmus 
23804c9d578SStephan Aßmus 		case MSG_REFRESH_DEPOTS:
23904c9d578SStephan Aßmus 			_StartRefreshWorker(true);
24004c9d578SStephan Aßmus 			break;
24104c9d578SStephan Aßmus 
24204c9d578SStephan Aßmus 		case MSG_LOG_IN:
243*1bbda92dSStephan Aßmus 			_OpenLoginWindow(BMessage());
24404c9d578SStephan Aßmus 			break;
24504c9d578SStephan Aßmus 
2468f03a0f9SStephan Aßmus 		case MSG_LOG_OUT:
2478f03a0f9SStephan Aßmus 			fModel.SetUsername("");
2488f03a0f9SStephan Aßmus 			break;
2498f03a0f9SStephan Aßmus 
2508f03a0f9SStephan Aßmus 		case MSG_AUTHORIZATION_CHANGED:
2518f03a0f9SStephan Aßmus 			_UpdateAuthorization();
2528f03a0f9SStephan Aßmus 			break;
2538f03a0f9SStephan Aßmus 
25404c9d578SStephan Aßmus 		case MSG_SHOW_SOURCE_PACKAGES:
25504c9d578SStephan Aßmus 			{
25604c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
25704c9d578SStephan Aßmus 				fModel.SetShowSourcePackages(!fModel.ShowSourcePackages());
25804c9d578SStephan Aßmus 			}
25904c9d578SStephan Aßmus 			_AdoptModel();
26004c9d578SStephan Aßmus 			break;
26104c9d578SStephan Aßmus 
26204c9d578SStephan Aßmus 		case MSG_SHOW_DEVELOP_PACKAGES:
26304c9d578SStephan Aßmus 			{
26404c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
26504c9d578SStephan Aßmus 				fModel.SetShowDevelopPackages(!fModel.ShowDevelopPackages());
26604c9d578SStephan Aßmus 			}
26704c9d578SStephan Aßmus 			_AdoptModel();
26804c9d578SStephan Aßmus 			break;
26904c9d578SStephan Aßmus 
27004c9d578SStephan Aßmus 		case MSG_PACKAGE_SELECTED:
27104c9d578SStephan Aßmus 		{
27204c9d578SStephan Aßmus 			BString title;
27304c9d578SStephan Aßmus 			if (message->FindString("title", &title) == B_OK) {
27404c9d578SStephan Aßmus 				int count = fVisiblePackages.CountItems();
27504c9d578SStephan Aßmus 				for (int i = 0; i < count; i++) {
27604c9d578SStephan Aßmus 					const PackageInfoRef& package
27704c9d578SStephan Aßmus 						= fVisiblePackages.ItemAtFast(i);
27804c9d578SStephan Aßmus 					if (package.Get() != NULL && package->Title() == title) {
27904c9d578SStephan Aßmus 						_AdoptPackage(package);
28004c9d578SStephan Aßmus 						break;
28104c9d578SStephan Aßmus 					}
28204c9d578SStephan Aßmus 				}
28304c9d578SStephan Aßmus 			} else {
28404c9d578SStephan Aßmus 				_ClearPackage();
28504c9d578SStephan Aßmus 			}
28604c9d578SStephan Aßmus 			break;
28704c9d578SStephan Aßmus 		}
28804c9d578SStephan Aßmus 
28904c9d578SStephan Aßmus 		case MSG_CATEGORY_SELECTED:
29004c9d578SStephan Aßmus 		{
29104c9d578SStephan Aßmus 			BString name;
29204c9d578SStephan Aßmus 			if (message->FindString("name", &name) != B_OK)
29304c9d578SStephan Aßmus 				name = "";
29404c9d578SStephan Aßmus 			{
29504c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
29604c9d578SStephan Aßmus 				fModel.SetCategory(name);
29704c9d578SStephan Aßmus 			}
29804c9d578SStephan Aßmus 			_AdoptModel();
29904c9d578SStephan Aßmus 			break;
30004c9d578SStephan Aßmus 		}
30104c9d578SStephan Aßmus 
30204c9d578SStephan Aßmus 		case MSG_FILTER_SELECTED:
30304c9d578SStephan Aßmus 		{
30404c9d578SStephan Aßmus 			BString name;
30504c9d578SStephan Aßmus 			int32 value;
30604c9d578SStephan Aßmus 			if (message->FindString("name", &name) != B_OK
30704c9d578SStephan Aßmus 				|| message->FindInt32("be:value", &value) != B_OK) {
30804c9d578SStephan Aßmus 				break;
30904c9d578SStephan Aßmus 			}
31004c9d578SStephan Aßmus 			{
31104c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
31204c9d578SStephan Aßmus 				if (name == "available") {
31304c9d578SStephan Aßmus 					fModel.SetShowAvailablePackages(
31404c9d578SStephan Aßmus 						value == B_CONTROL_ON);
31504c9d578SStephan Aßmus 				} else if (name == "installed") {
31604c9d578SStephan Aßmus 					fModel.SetShowInstalledPackages(
31704c9d578SStephan Aßmus 						value == B_CONTROL_ON);
31804c9d578SStephan Aßmus 				} else if (name == "development") {
31904c9d578SStephan Aßmus 					fModel.SetShowDevelopPackages(
32004c9d578SStephan Aßmus 						value == B_CONTROL_ON);
32104c9d578SStephan Aßmus 				} else if (name == "source code") {
32204c9d578SStephan Aßmus 					fModel.SetShowSourcePackages(
32304c9d578SStephan Aßmus 						value == B_CONTROL_ON);
32404c9d578SStephan Aßmus 				} else {
32504c9d578SStephan Aßmus 					break;
32604c9d578SStephan Aßmus 				}
32704c9d578SStephan Aßmus 			}
32804c9d578SStephan Aßmus 			_AdoptModel();
32904c9d578SStephan Aßmus 			break;
33004c9d578SStephan Aßmus 		}
33104c9d578SStephan Aßmus 
33204c9d578SStephan Aßmus 		case MSG_DEPOT_SELECTED:
33304c9d578SStephan Aßmus 		{
33404c9d578SStephan Aßmus 			BString name;
33504c9d578SStephan Aßmus 			if (message->FindString("name", &name) != B_OK)
33604c9d578SStephan Aßmus 				name = "";
33704c9d578SStephan Aßmus 			{
33804c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
33904c9d578SStephan Aßmus 				fModel.SetDepot(name);
34004c9d578SStephan Aßmus 			}
34104c9d578SStephan Aßmus 			_AdoptModel();
34204c9d578SStephan Aßmus 			break;
34304c9d578SStephan Aßmus 		}
34404c9d578SStephan Aßmus 
34504c9d578SStephan Aßmus 		case MSG_SEARCH_TERMS_MODIFIED:
34604c9d578SStephan Aßmus 		{
34704c9d578SStephan Aßmus 			// TODO: Do this with a delay!
34804c9d578SStephan Aßmus 			BString searchTerms;
34904c9d578SStephan Aßmus 			if (message->FindString("search terms", &searchTerms) != B_OK)
35004c9d578SStephan Aßmus 				searchTerms = "";
35104c9d578SStephan Aßmus 			{
35204c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
35304c9d578SStephan Aßmus 				fModel.SetSearchTerms(searchTerms);
35404c9d578SStephan Aßmus 			}
35504c9d578SStephan Aßmus 			_AdoptModel();
35604c9d578SStephan Aßmus 			break;
35704c9d578SStephan Aßmus 		}
35804c9d578SStephan Aßmus 
35904c9d578SStephan Aßmus 		case MSG_PACKAGE_STATE_CHANGED:
36004c9d578SStephan Aßmus 		{
36104c9d578SStephan Aßmus 			PackageInfo* info;
36204c9d578SStephan Aßmus 			if (message->FindPointer("package", (void**)&info) == B_OK) {
36304c9d578SStephan Aßmus 				PackageInfoRef ref(info, true);
36404c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
36504c9d578SStephan Aßmus 				fModel.SetPackageState(ref, ref->State());
36604c9d578SStephan Aßmus 			}
36704c9d578SStephan Aßmus 			break;
36804c9d578SStephan Aßmus 		}
36904c9d578SStephan Aßmus 
37004c9d578SStephan Aßmus 		case MSG_RATE_PACKAGE:
371*1bbda92dSStephan Aßmus 			_RatePackage();
37204c9d578SStephan Aßmus 			break;
37304c9d578SStephan Aßmus 
37404c9d578SStephan Aßmus 		default:
37504c9d578SStephan Aßmus 			BWindow::MessageReceived(message);
37604c9d578SStephan Aßmus 			break;
37704c9d578SStephan Aßmus 	}
37804c9d578SStephan Aßmus }
37904c9d578SStephan Aßmus 
38004c9d578SStephan Aßmus 
38104c9d578SStephan Aßmus void
38204c9d578SStephan Aßmus MainWindow::StoreSettings(BMessage& settings) const
38304c9d578SStephan Aßmus {
38404c9d578SStephan Aßmus 	settings.AddRect("window frame", Frame());
38504c9d578SStephan Aßmus 
38604c9d578SStephan Aßmus 	BMessage columnSettings;
38704c9d578SStephan Aßmus 	fPackageListView->SaveState(&columnSettings);
38804c9d578SStephan Aßmus 
38904c9d578SStephan Aßmus 	settings.AddMessage("column settings", &columnSettings);
39004c9d578SStephan Aßmus 
39104c9d578SStephan Aßmus 	settings.AddBool("show develop packages", fModel.ShowDevelopPackages());
39204c9d578SStephan Aßmus 	settings.AddBool("show source packages", fModel.ShowSourcePackages());
3938f03a0f9SStephan Aßmus 
3948f03a0f9SStephan Aßmus 	settings.AddString("username", fModel.Username());
39504c9d578SStephan Aßmus }
39604c9d578SStephan Aßmus 
39704c9d578SStephan Aßmus 
39804c9d578SStephan Aßmus void
39904c9d578SStephan Aßmus MainWindow::PackageChanged(const PackageInfoEvent& event)
40004c9d578SStephan Aßmus {
40104c9d578SStephan Aßmus 	if ((event.Changes() & PKG_CHANGED_STATE) != 0) {
40204c9d578SStephan Aßmus 		PackageInfoRef ref(event.Package());
40304c9d578SStephan Aßmus 		BMessage message(MSG_PACKAGE_STATE_CHANGED);
40404c9d578SStephan Aßmus 		message.AddPointer("package", ref.Get());
40504c9d578SStephan Aßmus 		ref.Detach();
40604c9d578SStephan Aßmus 			// reference needs to be released by MessageReceived();
40704c9d578SStephan Aßmus 		PostMessage(&message);
40804c9d578SStephan Aßmus 	}
40904c9d578SStephan Aßmus }
41004c9d578SStephan Aßmus 
41104c9d578SStephan Aßmus 
41204c9d578SStephan Aßmus status_t
41304c9d578SStephan Aßmus MainWindow::SchedulePackageActions(PackageActionList& list)
41404c9d578SStephan Aßmus {
41504c9d578SStephan Aßmus 	AutoLocker<BLocker> lock(&fPendingActionsLock);
41604c9d578SStephan Aßmus 	for (int32 i = 0; i < list.CountItems(); i++) {
41704c9d578SStephan Aßmus 		if (!fPendingActions.Add(list.ItemAtFast(i)))
41804c9d578SStephan Aßmus 			return B_NO_MEMORY;
41904c9d578SStephan Aßmus 	}
42004c9d578SStephan Aßmus 
42104c9d578SStephan Aßmus 	return release_sem_etc(fPendingActionsSem, list.CountItems(), 0);
42204c9d578SStephan Aßmus }
42304c9d578SStephan Aßmus 
42404c9d578SStephan Aßmus 
42504c9d578SStephan Aßmus Model*
42604c9d578SStephan Aßmus MainWindow::GetModel()
42704c9d578SStephan Aßmus {
42804c9d578SStephan Aßmus 	return &fModel;
42904c9d578SStephan Aßmus }
43004c9d578SStephan Aßmus 
43104c9d578SStephan Aßmus 
43204c9d578SStephan Aßmus void
43304c9d578SStephan Aßmus MainWindow::_BuildMenu(BMenuBar* menuBar)
43404c9d578SStephan Aßmus {
43504c9d578SStephan Aßmus 	BMenu* menu = new BMenu(B_TRANSLATE("Tools"));
43604c9d578SStephan Aßmus 	menu->AddItem(new BMenuItem(B_TRANSLATE("Refresh depots"),
43704c9d578SStephan Aßmus 			new BMessage(MSG_REFRESH_DEPOTS)));
4388f03a0f9SStephan Aßmus 	menu->AddSeparatorItem();
4398f03a0f9SStephan Aßmus 	menu->AddItem(new BMenuItem(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS),
44004c9d578SStephan Aßmus 			new BMessage(MSG_LOG_IN)));
4418f03a0f9SStephan Aßmus 	fLogOutItem = new BMenuItem(B_TRANSLATE("Log out"),
4428f03a0f9SStephan Aßmus 		new BMessage(MSG_LOG_OUT));
4438f03a0f9SStephan Aßmus 	menu->AddItem(fLogOutItem);
44404c9d578SStephan Aßmus 	menuBar->AddItem(menu);
44504c9d578SStephan Aßmus 
44604c9d578SStephan Aßmus //	menu = new BMenu(B_TRANSLATE("Options"));
44704c9d578SStephan Aßmus //
44804c9d578SStephan Aßmus //	fShowDevelopPackagesItem = new BMenuItem(
44904c9d578SStephan Aßmus //		B_TRANSLATE("Show develop packages"),
45004c9d578SStephan Aßmus //		new BMessage(MSG_SHOW_DEVELOP_PACKAGES));
45104c9d578SStephan Aßmus //	menu->AddItem(fShowDevelopPackagesItem);
45204c9d578SStephan Aßmus //
45304c9d578SStephan Aßmus //	fShowSourcePackagesItem = new BMenuItem(B_TRANSLATE("Show source packages"),
45404c9d578SStephan Aßmus //		new BMessage(MSG_SHOW_SOURCE_PACKAGES));
45504c9d578SStephan Aßmus //	menu->AddItem(fShowSourcePackagesItem);
45604c9d578SStephan Aßmus //
45704c9d578SStephan Aßmus //	menuBar->AddItem(menu);
45804c9d578SStephan Aßmus }
45904c9d578SStephan Aßmus 
46004c9d578SStephan Aßmus 
46104c9d578SStephan Aßmus void
46204c9d578SStephan Aßmus MainWindow::_AdoptModel()
46304c9d578SStephan Aßmus {
46404c9d578SStephan Aßmus 	fVisiblePackages = fModel.CreatePackageList();
46504c9d578SStephan Aßmus 
46604c9d578SStephan Aßmus 	fPackageListView->Clear();
46704c9d578SStephan Aßmus 	for (int32 i = 0; i < fVisiblePackages.CountItems(); i++) {
46804c9d578SStephan Aßmus 		BAutolock locker(fModel.Lock());
46904c9d578SStephan Aßmus 		fPackageListView->AddPackage(fVisiblePackages.ItemAtFast(i));
47004c9d578SStephan Aßmus 	}
47104c9d578SStephan Aßmus 
47204c9d578SStephan Aßmus 	BAutolock locker(fModel.Lock());
47304c9d578SStephan Aßmus //	fShowSourcePackagesItem->SetMarked(fModel.ShowSourcePackages());
47404c9d578SStephan Aßmus //	fShowDevelopPackagesItem->SetMarked(fModel.ShowDevelopPackages());
47504c9d578SStephan Aßmus 	fFilterView->AdoptCheckmarks(fModel);
47604c9d578SStephan Aßmus }
47704c9d578SStephan Aßmus 
47804c9d578SStephan Aßmus 
47904c9d578SStephan Aßmus void
48004c9d578SStephan Aßmus MainWindow::_AdoptPackage(const PackageInfoRef& package)
48104c9d578SStephan Aßmus {
48204c9d578SStephan Aßmus 	fPackageInfoView->SetPackage(package);
48304c9d578SStephan Aßmus 
48404c9d578SStephan Aßmus 	// Trigger asynchronous package population from the web-app
48504c9d578SStephan Aßmus 	{
48604c9d578SStephan Aßmus 		AutoLocker<BLocker> lock(&fPackageToPopulateLock);
48704c9d578SStephan Aßmus 		fPackageToPopulate = package;
48804c9d578SStephan Aßmus 	}
48904c9d578SStephan Aßmus 	release_sem_etc(fPackageToPopulateSem, 1, 0);
49004c9d578SStephan Aßmus }
49104c9d578SStephan Aßmus 
49204c9d578SStephan Aßmus 
49304c9d578SStephan Aßmus void
49404c9d578SStephan Aßmus MainWindow::_ClearPackage()
49504c9d578SStephan Aßmus {
49604c9d578SStephan Aßmus 	fPackageInfoView->Clear();
49704c9d578SStephan Aßmus }
49804c9d578SStephan Aßmus 
49904c9d578SStephan Aßmus 
50004c9d578SStephan Aßmus void
50104c9d578SStephan Aßmus MainWindow::_RefreshRepositories(bool force)
50204c9d578SStephan Aßmus {
50304c9d578SStephan Aßmus 	BPackageRoster roster;
50404c9d578SStephan Aßmus 	BStringList repositoryNames;
50504c9d578SStephan Aßmus 
50604c9d578SStephan Aßmus 	status_t result = roster.GetRepositoryNames(repositoryNames);
50704c9d578SStephan Aßmus 	if (result != B_OK)
50804c9d578SStephan Aßmus 		return;
50904c9d578SStephan Aßmus 
51004c9d578SStephan Aßmus 	DecisionProvider decisionProvider;
51104c9d578SStephan Aßmus 	JobStateListener listener;
51204c9d578SStephan Aßmus 	BContext context(decisionProvider, listener);
51304c9d578SStephan Aßmus 
51404c9d578SStephan Aßmus 	BRepositoryCache cache;
51504c9d578SStephan Aßmus 	for (int32 i = 0; i < repositoryNames.CountStrings(); ++i) {
51604c9d578SStephan Aßmus 		const BString& repoName = repositoryNames.StringAt(i);
51704c9d578SStephan Aßmus 		BRepositoryConfig repoConfig;
51804c9d578SStephan Aßmus 		result = roster.GetRepositoryConfig(repoName, &repoConfig);
51904c9d578SStephan Aßmus 		if (result != B_OK) {
52004c9d578SStephan Aßmus 			// TODO: notify user
52104c9d578SStephan Aßmus 			continue;
52204c9d578SStephan Aßmus 		}
52304c9d578SStephan Aßmus 
52404c9d578SStephan Aßmus 		if (roster.GetRepositoryCache(repoName, &cache) != B_OK || force) {
52504c9d578SStephan Aßmus 			try {
52604c9d578SStephan Aßmus 				BRefreshRepositoryRequest refreshRequest(context, repoConfig);
52704c9d578SStephan Aßmus 
52804c9d578SStephan Aßmus 				result = refreshRequest.Process();
52904c9d578SStephan Aßmus 			} catch (BFatalErrorException ex) {
53004c9d578SStephan Aßmus 				BString message(B_TRANSLATE("An error occurred while "
53104c9d578SStephan Aßmus 					"refreshing the repository: %error% (%details%)"));
53204c9d578SStephan Aßmus  				message.ReplaceFirst("%error%", ex.Message());
53304c9d578SStephan Aßmus 				message.ReplaceFirst("%details%", ex.Details());
53404c9d578SStephan Aßmus 				_NotifyUser("Error", message.String());
53504c9d578SStephan Aßmus 			} catch (BException ex) {
53604c9d578SStephan Aßmus 				BString message(B_TRANSLATE("An error occurred while "
53704c9d578SStephan Aßmus 					"refreshing the repository: %error%"));
53804c9d578SStephan Aßmus 				message.ReplaceFirst("%error%", ex.Message());
53904c9d578SStephan Aßmus 				_NotifyUser("Error", message.String());
54004c9d578SStephan Aßmus 			}
54104c9d578SStephan Aßmus 		}
54204c9d578SStephan Aßmus 	}
54304c9d578SStephan Aßmus }
54404c9d578SStephan Aßmus 
54504c9d578SStephan Aßmus 
54604c9d578SStephan Aßmus void
54704c9d578SStephan Aßmus MainWindow::_RefreshPackageList()
54804c9d578SStephan Aßmus {
54904c9d578SStephan Aßmus 	BPackageRoster roster;
55004c9d578SStephan Aßmus 	BStringList repositoryNames;
55104c9d578SStephan Aßmus 
55204c9d578SStephan Aßmus 	status_t result = roster.GetRepositoryNames(repositoryNames);
55304c9d578SStephan Aßmus 	if (result != B_OK)
55404c9d578SStephan Aßmus 		return;
55504c9d578SStephan Aßmus 
55604c9d578SStephan Aßmus 	DepotInfoMap depots;
55704c9d578SStephan Aßmus 	for (int32 i = 0; i < repositoryNames.CountStrings(); i++) {
55804c9d578SStephan Aßmus 		const BString& repoName = repositoryNames.StringAt(i);
55904c9d578SStephan Aßmus 		depots[repoName] = DepotInfo(repoName);
56004c9d578SStephan Aßmus 	}
56104c9d578SStephan Aßmus 
56204c9d578SStephan Aßmus 	PackageManager manager(B_PACKAGE_INSTALLATION_LOCATION_HOME);
56304c9d578SStephan Aßmus 	try {
56404c9d578SStephan Aßmus 		manager.Init(PackageManager::B_ADD_INSTALLED_REPOSITORIES
56504c9d578SStephan Aßmus 			| PackageManager::B_ADD_REMOTE_REPOSITORIES);
56604c9d578SStephan Aßmus 	} catch (BException ex) {
56704c9d578SStephan Aßmus 		BString message(B_TRANSLATE("An error occurred while "
56804c9d578SStephan Aßmus 			"initializing the package manager: %message%"));
56904c9d578SStephan Aßmus 		message.ReplaceFirst("%message%", ex.Message());
57004c9d578SStephan Aßmus 		_NotifyUser("Error", message.String());
57104c9d578SStephan Aßmus 		return;
57204c9d578SStephan Aßmus 	}
57304c9d578SStephan Aßmus 
57404c9d578SStephan Aßmus 	BObjectList<BSolverPackage> packages;
57504c9d578SStephan Aßmus 	result = manager.Solver()->FindPackages("",
57604c9d578SStephan Aßmus 		BSolver::B_FIND_CASE_INSENSITIVE | BSolver::B_FIND_IN_NAME
57704c9d578SStephan Aßmus 			| BSolver::B_FIND_IN_SUMMARY | BSolver::B_FIND_IN_DESCRIPTION
57804c9d578SStephan Aßmus 			| BSolver::B_FIND_IN_PROVIDES,
57904c9d578SStephan Aßmus 		packages);
58004c9d578SStephan Aßmus 	if (result != B_OK) {
58104c9d578SStephan Aßmus 		BString message(B_TRANSLATE("An error occurred while "
58204c9d578SStephan Aßmus 			"obtaining the package list: %message%"));
58304c9d578SStephan Aßmus 		message.ReplaceFirst("%message%", strerror(result));
58404c9d578SStephan Aßmus 		_NotifyUser("Error", message.String());
58504c9d578SStephan Aßmus 		return;
58604c9d578SStephan Aßmus 	}
58704c9d578SStephan Aßmus 
58804c9d578SStephan Aßmus 	if (packages.IsEmpty())
58904c9d578SStephan Aßmus 		return;
59004c9d578SStephan Aßmus 
59104c9d578SStephan Aßmus 	PackageInfoMap foundPackages;
59204c9d578SStephan Aßmus 		// if a given package is installed locally, we will potentially
59304c9d578SStephan Aßmus 		// get back multiple entries, one for each local installation
59404c9d578SStephan Aßmus 		// location, and one for each remote repository the package
59504c9d578SStephan Aßmus 		// is available in. The above map is used to ensure that in such
59604c9d578SStephan Aßmus 		// cases we consolidate the information, rather than displaying
59704c9d578SStephan Aßmus 		// duplicates
59804c9d578SStephan Aßmus 	PackageInfoMap remotePackages;
59904c9d578SStephan Aßmus 		// any package that we find in a remote repository goes in this map.
60004c9d578SStephan Aßmus 		// this is later used to discern which packages came from a local
60104c9d578SStephan Aßmus 		// installation only, as those must be handled a bit differently
60204c9d578SStephan Aßmus 		// upon uninstallation, since we'd no longer be able to pull them
60304c9d578SStephan Aßmus 		// down remotely.
60404c9d578SStephan Aßmus 	BStringList systemFlaggedPackages;
60504c9d578SStephan Aßmus 		// any packages flagged as a system package are added to this list.
60604c9d578SStephan Aßmus 		// such packages cannot be uninstalled, nor can any of their deps.
60704c9d578SStephan Aßmus 	PackageInfoMap systemInstalledPackages;
60804c9d578SStephan Aßmus 		// any packages installed in system are added to this list.
60904c9d578SStephan Aßmus 		// This is later used for dependency resolution of the actual
61004c9d578SStephan Aßmus 		// system packages in order to compute the list of protected
61104c9d578SStephan Aßmus 		// dependencies indicated above.
61204c9d578SStephan Aßmus 
61304c9d578SStephan Aßmus 	BitmapRef defaultIcon(new(std::nothrow) SharedBitmap(
61404c9d578SStephan Aßmus 		"application/x-vnd.haiku-package"), true);
61504c9d578SStephan Aßmus 
61604c9d578SStephan Aßmus 	for (int32 i = 0; i < packages.CountItems(); i++) {
61704c9d578SStephan Aßmus 		BSolverPackage* package = packages.ItemAt(i);
61804c9d578SStephan Aßmus 		const BPackageInfo& repoPackageInfo = package->Info();
61904c9d578SStephan Aßmus 		PackageInfoRef modelInfo;
62004c9d578SStephan Aßmus 		PackageInfoMap::iterator it = foundPackages.find(
62104c9d578SStephan Aßmus 			repoPackageInfo.Name());
62204c9d578SStephan Aßmus 		if (it != foundPackages.end())
62304c9d578SStephan Aßmus 			modelInfo.SetTo(it->second);
62404c9d578SStephan Aßmus 		else {
62504c9d578SStephan Aßmus 			// Add new package info
62604c9d578SStephan Aßmus 			BString publisherURL;
62704c9d578SStephan Aßmus 			if (repoPackageInfo.URLList().CountStrings() > 0)
62804c9d578SStephan Aßmus 				publisherURL = repoPackageInfo.URLList().StringAt(0);
62904c9d578SStephan Aßmus 
63004c9d578SStephan Aßmus 			BString publisherName = repoPackageInfo.Vendor();
63104c9d578SStephan Aßmus 			const BStringList& rightsList = repoPackageInfo.CopyrightList();
63204c9d578SStephan Aßmus 			if (rightsList.CountStrings() > 0)
63304c9d578SStephan Aßmus 				publisherName = rightsList.StringAt(0);
63404c9d578SStephan Aßmus 
63504c9d578SStephan Aßmus 			modelInfo.SetTo(new(std::nothrow) PackageInfo(
63604c9d578SStephan Aßmus 					repoPackageInfo.Name(),
63746bcb34dSStephan Aßmus 					repoPackageInfo.Version(),
63804c9d578SStephan Aßmus 					PublisherInfo(BitmapRef(), publisherName,
63904c9d578SStephan Aßmus 					"", publisherURL), repoPackageInfo.Summary(),
64004c9d578SStephan Aßmus 					repoPackageInfo.Description(),
64104c9d578SStephan Aßmus 					repoPackageInfo.Flags(),
64204c9d578SStephan Aßmus 					repoPackageInfo.ArchitectureName()),
64304c9d578SStephan Aßmus 				true);
64404c9d578SStephan Aßmus 
64504c9d578SStephan Aßmus 			if (modelInfo.Get() == NULL)
64604c9d578SStephan Aßmus 				return;
64704c9d578SStephan Aßmus 
64804c9d578SStephan Aßmus 			foundPackages[repoPackageInfo.Name()] = modelInfo;
64904c9d578SStephan Aßmus 		}
65004c9d578SStephan Aßmus 
65104c9d578SStephan Aßmus 		modelInfo->SetIcon(defaultIcon);
65204c9d578SStephan Aßmus 		modelInfo->AddListener(this);
65304c9d578SStephan Aßmus 
65404c9d578SStephan Aßmus 		BSolverRepository* repository = package->Repository();
65504c9d578SStephan Aßmus 		if (dynamic_cast<BPackageManager::RemoteRepository*>(repository)
65604c9d578SStephan Aßmus 				!= NULL) {
65704c9d578SStephan Aßmus 			depots[repository->Name()].AddPackage(modelInfo);
65804c9d578SStephan Aßmus 			remotePackages[modelInfo->Title()] = modelInfo;
65904c9d578SStephan Aßmus 		} else {
66004c9d578SStephan Aßmus 			if (repository == static_cast<const BSolverRepository*>(
66104c9d578SStephan Aßmus 					manager.SystemRepository())) {
66204c9d578SStephan Aßmus 				modelInfo->AddInstallationLocation(
66304c9d578SStephan Aßmus 					B_PACKAGE_INSTALLATION_LOCATION_SYSTEM);
66404c9d578SStephan Aßmus 				if (!modelInfo->IsSystemPackage()) {
66504c9d578SStephan Aßmus 					systemInstalledPackages[repoPackageInfo.FileName()]
66604c9d578SStephan Aßmus 						= modelInfo;
66704c9d578SStephan Aßmus 				}
66804c9d578SStephan Aßmus 			} else if (repository == static_cast<const BSolverRepository*>(
66904c9d578SStephan Aßmus 					manager.HomeRepository())) {
67004c9d578SStephan Aßmus 				modelInfo->AddInstallationLocation(
67104c9d578SStephan Aßmus 					B_PACKAGE_INSTALLATION_LOCATION_HOME);
67204c9d578SStephan Aßmus 			}
67304c9d578SStephan Aßmus 		}
67404c9d578SStephan Aßmus 
67504c9d578SStephan Aßmus 		if (modelInfo->IsSystemPackage())
67604c9d578SStephan Aßmus 			systemFlaggedPackages.Add(repoPackageInfo.FileName());
67704c9d578SStephan Aßmus 	}
67804c9d578SStephan Aßmus 
67904c9d578SStephan Aßmus 	BAutolock lock(fModel.Lock());
68004c9d578SStephan Aßmus 
68104c9d578SStephan Aßmus 	fModel.Clear();
68204c9d578SStephan Aßmus 
68304c9d578SStephan Aßmus 	// filter remote packages from the found list
68404c9d578SStephan Aßmus 	// any packages remaining will be locally installed packages
68504c9d578SStephan Aßmus 	// that weren't acquired from a repository
68604c9d578SStephan Aßmus 	for (PackageInfoMap::iterator it = remotePackages.begin();
68704c9d578SStephan Aßmus 			it != remotePackages.end(); it++) {
68804c9d578SStephan Aßmus 		foundPackages.erase(it->first);
68904c9d578SStephan Aßmus 	}
69004c9d578SStephan Aßmus 
69104c9d578SStephan Aßmus 	if (!foundPackages.empty()) {
69204c9d578SStephan Aßmus 		BString repoName = B_TRANSLATE("Local");
69304c9d578SStephan Aßmus 		depots[repoName] = DepotInfo(repoName);
69404c9d578SStephan Aßmus 		DepotInfoMap::iterator depot = depots.find(repoName);
69504c9d578SStephan Aßmus 		for (PackageInfoMap::iterator it = foundPackages.begin();
69604c9d578SStephan Aßmus 				it != foundPackages.end(); ++it) {
69704c9d578SStephan Aßmus 			depot->second.AddPackage(it->second);
69804c9d578SStephan Aßmus 		}
69904c9d578SStephan Aßmus 	}
70004c9d578SStephan Aßmus 
70104c9d578SStephan Aßmus 	for (DepotInfoMap::iterator it = depots.begin(); it != depots.end(); it++) {
70204c9d578SStephan Aßmus 		fModel.AddDepot(it->second);
70304c9d578SStephan Aßmus 	}
70404c9d578SStephan Aßmus 
70504c9d578SStephan Aßmus 	// start retrieving package icons and average ratings
70604c9d578SStephan Aßmus 	fModel.PopulateAllPackages();
70704c9d578SStephan Aßmus 
70804c9d578SStephan Aßmus 	// compute the OS package dependencies
70904c9d578SStephan Aßmus 	try {
71004c9d578SStephan Aßmus 		// create the solver
71104c9d578SStephan Aßmus 		BSolver* solver;
71204c9d578SStephan Aßmus 		status_t error = BSolver::Create(solver);
71304c9d578SStephan Aßmus 		if (error != B_OK)
71404c9d578SStephan Aßmus 			throw BFatalErrorException(error, "Failed to create solver.");
71504c9d578SStephan Aßmus 
71604c9d578SStephan Aßmus 		ObjectDeleter<BSolver> solverDeleter(solver);
71704c9d578SStephan Aßmus 		BPath systemPath;
71804c9d578SStephan Aßmus 		error = find_directory(B_SYSTEM_PACKAGES_DIRECTORY, &systemPath);
71904c9d578SStephan Aßmus 		if (error != B_OK) {
72004c9d578SStephan Aßmus 			throw BFatalErrorException(error,
72104c9d578SStephan Aßmus 				"Unable to retrieve system packages directory.");
72204c9d578SStephan Aßmus 		}
72304c9d578SStephan Aßmus 
72404c9d578SStephan Aßmus 		// add the "installed" repository with the given packages
72504c9d578SStephan Aßmus 		BSolverRepository installedRepository;
72604c9d578SStephan Aßmus 		{
72704c9d578SStephan Aßmus 			BRepositoryBuilder installedRepositoryBuilder(installedRepository,
72804c9d578SStephan Aßmus 				"installed");
72904c9d578SStephan Aßmus 			for (int32 i = 0; i < systemFlaggedPackages.CountStrings(); i++) {
73004c9d578SStephan Aßmus 				BPath packagePath(systemPath);
73104c9d578SStephan Aßmus 				packagePath.Append(systemFlaggedPackages.StringAt(i));
73204c9d578SStephan Aßmus 				installedRepositoryBuilder.AddPackage(packagePath.Path());
73304c9d578SStephan Aßmus 			}
73404c9d578SStephan Aßmus 			installedRepositoryBuilder.AddToSolver(solver, true);
73504c9d578SStephan Aßmus 		}
73604c9d578SStephan Aßmus 
73704c9d578SStephan Aßmus 		// add system repository
73804c9d578SStephan Aßmus 		BSolverRepository systemRepository;
73904c9d578SStephan Aßmus 		{
74004c9d578SStephan Aßmus 			BRepositoryBuilder systemRepositoryBuilder(systemRepository,
74104c9d578SStephan Aßmus 				"system");
74204c9d578SStephan Aßmus 			for (PackageInfoMap::iterator it = systemInstalledPackages.begin();
74304c9d578SStephan Aßmus 					it != systemInstalledPackages.end(); it++) {
74404c9d578SStephan Aßmus 				BPath packagePath(systemPath);
74504c9d578SStephan Aßmus 				packagePath.Append(it->first);
74604c9d578SStephan Aßmus 				systemRepositoryBuilder.AddPackage(packagePath.Path());
74704c9d578SStephan Aßmus 			}
74804c9d578SStephan Aßmus 			systemRepositoryBuilder.AddToSolver(solver, false);
74904c9d578SStephan Aßmus 		}
75004c9d578SStephan Aßmus 
75104c9d578SStephan Aßmus 		// solve
75204c9d578SStephan Aßmus 		error = solver->VerifyInstallation();
75304c9d578SStephan Aßmus 		if (error != B_OK) {
75404c9d578SStephan Aßmus 			throw BFatalErrorException(error, "Failed to compute packages to "
75504c9d578SStephan Aßmus 				"install.");
75604c9d578SStephan Aßmus 		}
75704c9d578SStephan Aßmus 
75804c9d578SStephan Aßmus 		BSolverResult solverResult;
75904c9d578SStephan Aßmus 		error = solver->GetResult(solverResult);
76004c9d578SStephan Aßmus 		if (error != B_OK) {
76104c9d578SStephan Aßmus 			throw BFatalErrorException(error, "Failed to retrieve system "
76204c9d578SStephan Aßmus 				"package dependency list.");
76304c9d578SStephan Aßmus 		}
76404c9d578SStephan Aßmus 
76504c9d578SStephan Aßmus 		for (int32 i = 0; const BSolverResultElement* element
76604c9d578SStephan Aßmus 				= solverResult.ElementAt(i); i++) {
76704c9d578SStephan Aßmus 			BSolverPackage* package = element->Package();
76804c9d578SStephan Aßmus 			if (element->Type() == BSolverResultElement::B_TYPE_INSTALL) {
76904c9d578SStephan Aßmus 				PackageInfoMap::iterator it = systemInstalledPackages.find(
77004c9d578SStephan Aßmus 					package->Info().FileName());
77104c9d578SStephan Aßmus 				if (it != systemInstalledPackages.end())
77204c9d578SStephan Aßmus 					it->second->SetSystemDependency(true);
77304c9d578SStephan Aßmus 			}
77404c9d578SStephan Aßmus 		}
77504c9d578SStephan Aßmus 	} catch (BFatalErrorException ex) {
77604c9d578SStephan Aßmus 		printf("Fatal exception occurred while resolving system dependencies: "
77704c9d578SStephan Aßmus 			"%s, details: %s\n", strerror(ex.Error()), ex.Details().String());
77804c9d578SStephan Aßmus 	} catch (BNothingToDoException) {
77904c9d578SStephan Aßmus 		// do nothing
78004c9d578SStephan Aßmus 	} catch (BException ex) {
78104c9d578SStephan Aßmus 		printf("Exception occurred while resolving system dependencies: %s\n",
78204c9d578SStephan Aßmus 			ex.Message().String());
78304c9d578SStephan Aßmus 	} catch (...) {
78404c9d578SStephan Aßmus 		printf("Unknown exception occurred while resolving system "
78504c9d578SStephan Aßmus 			"dependencies.\n");
78604c9d578SStephan Aßmus 	}
78704c9d578SStephan Aßmus }
78804c9d578SStephan Aßmus 
78904c9d578SStephan Aßmus 
79004c9d578SStephan Aßmus void
79104c9d578SStephan Aßmus MainWindow::_StartRefreshWorker(bool force)
79204c9d578SStephan Aßmus {
79304c9d578SStephan Aßmus 	if (fModelWorker != B_BAD_THREAD_ID)
79404c9d578SStephan Aßmus 		return;
79504c9d578SStephan Aßmus 
79604c9d578SStephan Aßmus 	RefreshWorkerParameters* parameters = new(std::nothrow)
79704c9d578SStephan Aßmus 		RefreshWorkerParameters(this, force);
79804c9d578SStephan Aßmus 	if (parameters == NULL)
79904c9d578SStephan Aßmus 		return;
80004c9d578SStephan Aßmus 
80104c9d578SStephan Aßmus 	ObjectDeleter<RefreshWorkerParameters> deleter(parameters);
80204c9d578SStephan Aßmus 	fModelWorker = spawn_thread(&_RefreshModelThreadWorker, "model loader",
80304c9d578SStephan Aßmus 		B_LOW_PRIORITY, parameters);
80404c9d578SStephan Aßmus 
80504c9d578SStephan Aßmus 	if (fModelWorker > 0) {
80604c9d578SStephan Aßmus 		deleter.Detach();
80704c9d578SStephan Aßmus 		resume_thread(fModelWorker);
80804c9d578SStephan Aßmus 	}
80904c9d578SStephan Aßmus }
81004c9d578SStephan Aßmus 
81104c9d578SStephan Aßmus 
81204c9d578SStephan Aßmus status_t
81304c9d578SStephan Aßmus MainWindow::_RefreshModelThreadWorker(void* arg)
81404c9d578SStephan Aßmus {
81504c9d578SStephan Aßmus 	RefreshWorkerParameters* parameters
81604c9d578SStephan Aßmus 		= reinterpret_cast<RefreshWorkerParameters*>(arg);
81704c9d578SStephan Aßmus 	MainWindow* mainWindow = parameters->window;
81804c9d578SStephan Aßmus 	ObjectDeleter<RefreshWorkerParameters> deleter(parameters);
81904c9d578SStephan Aßmus 
82004c9d578SStephan Aßmus 	BMessenger messenger(mainWindow);
82104c9d578SStephan Aßmus 
82204c9d578SStephan Aßmus 	mainWindow->_RefreshRepositories(parameters->forceRefresh);
82304c9d578SStephan Aßmus 
82404c9d578SStephan Aßmus 	if (mainWindow->fTerminating)
82504c9d578SStephan Aßmus 		return B_OK;
82604c9d578SStephan Aßmus 
82704c9d578SStephan Aßmus 	mainWindow->_RefreshPackageList();
82804c9d578SStephan Aßmus 
82904c9d578SStephan Aßmus 	messenger.SendMessage(MSG_MODEL_WORKER_DONE);
83004c9d578SStephan Aßmus 
83104c9d578SStephan Aßmus 	return B_OK;
83204c9d578SStephan Aßmus }
83304c9d578SStephan Aßmus 
83404c9d578SStephan Aßmus 
83504c9d578SStephan Aßmus status_t
83604c9d578SStephan Aßmus MainWindow::_PackageActionWorker(void* arg)
83704c9d578SStephan Aßmus {
83804c9d578SStephan Aßmus 	MainWindow* window = reinterpret_cast<MainWindow*>(arg);
83904c9d578SStephan Aßmus 
84004c9d578SStephan Aßmus 	while (acquire_sem(window->fPendingActionsSem) == B_OK) {
84104c9d578SStephan Aßmus 		PackageActionRef ref;
84204c9d578SStephan Aßmus 		{
84304c9d578SStephan Aßmus 			AutoLocker<BLocker> lock(&window->fPendingActionsLock);
84404c9d578SStephan Aßmus 			ref = window->fPendingActions.ItemAt(0);
84504c9d578SStephan Aßmus 			if (ref.Get() == NULL)
84604c9d578SStephan Aßmus 				break;
84704c9d578SStephan Aßmus 			window->fPendingActions.Remove(0);
84804c9d578SStephan Aßmus 		}
84904c9d578SStephan Aßmus 
85004c9d578SStephan Aßmus 		ref->Perform();
85104c9d578SStephan Aßmus 	}
85204c9d578SStephan Aßmus 
85304c9d578SStephan Aßmus 	return 0;
85404c9d578SStephan Aßmus }
85504c9d578SStephan Aßmus 
85604c9d578SStephan Aßmus 
85704c9d578SStephan Aßmus status_t
85804c9d578SStephan Aßmus MainWindow::_PopulatePackageWorker(void* arg)
85904c9d578SStephan Aßmus {
86004c9d578SStephan Aßmus 	MainWindow* window = reinterpret_cast<MainWindow*>(arg);
86104c9d578SStephan Aßmus 
86204c9d578SStephan Aßmus 	while (acquire_sem(window->fPackageToPopulateSem) == B_OK) {
86304c9d578SStephan Aßmus 		PackageInfoRef package;
86404c9d578SStephan Aßmus 		{
86504c9d578SStephan Aßmus 			AutoLocker<BLocker> lock(&window->fPackageToPopulateLock);
86604c9d578SStephan Aßmus 			package = window->fPackageToPopulate;
86704c9d578SStephan Aßmus 		}
86804c9d578SStephan Aßmus 
86904c9d578SStephan Aßmus 		if (package.Get() != NULL) {
87004c9d578SStephan Aßmus 			window->fModel.PopulatePackage(package,
87104c9d578SStephan Aßmus 				Model::POPULATE_USER_RATINGS | Model::POPULATE_SCREEN_SHOTS
87204c9d578SStephan Aßmus 					| Model::POPULATE_CHANGELOG);
87304c9d578SStephan Aßmus 		}
87404c9d578SStephan Aßmus 	}
87504c9d578SStephan Aßmus 
87604c9d578SStephan Aßmus 	return 0;
87704c9d578SStephan Aßmus }
87804c9d578SStephan Aßmus 
87904c9d578SStephan Aßmus 
88004c9d578SStephan Aßmus void
88104c9d578SStephan Aßmus MainWindow::_NotifyUser(const char* title, const char* message)
88204c9d578SStephan Aßmus {
88304c9d578SStephan Aßmus 	BAlert *alert = new(std::nothrow) BAlert(title, message,
88404c9d578SStephan Aßmus 		B_TRANSLATE("Close"));
88504c9d578SStephan Aßmus 
88604c9d578SStephan Aßmus 	if (alert != NULL)
88704c9d578SStephan Aßmus 		alert->Go();
88804c9d578SStephan Aßmus }
88904c9d578SStephan Aßmus 
89004c9d578SStephan Aßmus 
89104c9d578SStephan Aßmus void
892*1bbda92dSStephan Aßmus MainWindow::_OpenLoginWindow(const BMessage& onSuccessMessage)
89304c9d578SStephan Aßmus {
89404c9d578SStephan Aßmus 	UserLoginWindow* window = new UserLoginWindow(this,
89504c9d578SStephan Aßmus 		BRect(0, 0, 500, 400), fModel);
896*1bbda92dSStephan Aßmus 
897*1bbda92dSStephan Aßmus 	if (onSuccessMessage.what != 0)
898*1bbda92dSStephan Aßmus 		window->SetOnSuccessMessage(BMessenger(this), onSuccessMessage);
899*1bbda92dSStephan Aßmus 
90004c9d578SStephan Aßmus 	window->Show();
90104c9d578SStephan Aßmus }
90204c9d578SStephan Aßmus 
9038f03a0f9SStephan Aßmus 
9048f03a0f9SStephan Aßmus void
9058f03a0f9SStephan Aßmus MainWindow::_UpdateAuthorization()
9068f03a0f9SStephan Aßmus {
9078f03a0f9SStephan Aßmus 	BString username(fModel.Username());
9088f03a0f9SStephan Aßmus 	fLogOutItem->SetEnabled(username.Length() > 0);
9098f03a0f9SStephan Aßmus 	fFilterView->SetUsername(username);
9108f03a0f9SStephan Aßmus }
911*1bbda92dSStephan Aßmus 
912*1bbda92dSStephan Aßmus 
913*1bbda92dSStephan Aßmus void
914*1bbda92dSStephan Aßmus MainWindow::_RatePackage()
915*1bbda92dSStephan Aßmus {
916*1bbda92dSStephan Aßmus 	if (fModel.Username().IsEmpty()) {
917*1bbda92dSStephan Aßmus 		BAlert* alert = new(std::nothrow) BAlert(
918*1bbda92dSStephan Aßmus 			B_TRANSLATE("Not logged in"),
919*1bbda92dSStephan Aßmus 			B_TRANSLATE("You need to be logged into an account before you "
920*1bbda92dSStephan Aßmus 				"can rate packages."),
921*1bbda92dSStephan Aßmus 			B_TRANSLATE("Cancel"),
922*1bbda92dSStephan Aßmus 			B_TRANSLATE("Login or Create account"));
923*1bbda92dSStephan Aßmus 
924*1bbda92dSStephan Aßmus 		if (alert == NULL)
925*1bbda92dSStephan Aßmus 			return;
926*1bbda92dSStephan Aßmus 
927*1bbda92dSStephan Aßmus 		int32 choice = alert->Go();
928*1bbda92dSStephan Aßmus 		if (choice == 1)
929*1bbda92dSStephan Aßmus 			_OpenLoginWindow(BMessage(MSG_RATE_PACKAGE));
930*1bbda92dSStephan Aßmus 		return;
931*1bbda92dSStephan Aßmus 	}
932*1bbda92dSStephan Aßmus 
933*1bbda92dSStephan Aßmus 	// TODO: Allow only one RatePackageWindow
934*1bbda92dSStephan Aßmus 	// TODO: Mechanism for remembering the window frame
935*1bbda92dSStephan Aßmus 	RatePackageWindow* window = new RatePackageWindow(this,
936*1bbda92dSStephan Aßmus 		BRect(0, 0, 500, 400), fModel);
937*1bbda92dSStephan Aßmus 	window->SetPackage(fPackageInfoView->Package());
938*1bbda92dSStephan Aßmus 	window->Show();
939*1bbda92dSStephan Aßmus }
940