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