xref: /haiku/src/apps/haikudepot/ui/MainWindow.cpp (revision e00a489b80a7219bf80658d157548eb0aa4a97d0)
104c9d578SStephan Aßmus /*
2f7c2983eSAxel Dörfler  * Copyright 2015, Axel Dörfler, <axeld@pinc-software.de>.
304c9d578SStephan Aßmus  * Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
404c9d578SStephan Aßmus  * Copyright 2013, Rene Gollent, rene@gollent.com.
504c9d578SStephan Aßmus  * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
6d13c3d89SAndrew Lindesay  * Copyright 2016-2018, Andrew Lindesay <apl@lindesay.co.nz>.
7125d42d9SJulian Harnath  * Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>.
804c9d578SStephan Aßmus  * All rights reserved. Distributed under the terms of the MIT License.
904c9d578SStephan Aßmus  */
1004c9d578SStephan Aßmus 
11f7c2983eSAxel Dörfler 
1204c9d578SStephan Aßmus #include "MainWindow.h"
1304c9d578SStephan Aßmus 
1404c9d578SStephan Aßmus #include <map>
153b17d8ddSAndrew Lindesay #include <vector>
1604c9d578SStephan Aßmus 
1704c9d578SStephan Aßmus #include <stdio.h>
1804c9d578SStephan Aßmus #include <Alert.h>
1904c9d578SStephan Aßmus #include <Autolock.h>
2004c9d578SStephan Aßmus #include <Application.h>
2104c9d578SStephan Aßmus #include <Button.h>
2204c9d578SStephan Aßmus #include <Catalog.h>
234b930ccaSStephan Aßmus #include <CardLayout.h>
2404c9d578SStephan Aßmus #include <LayoutBuilder.h>
2504c9d578SStephan Aßmus #include <MenuBar.h>
2604c9d578SStephan Aßmus #include <MenuItem.h>
2704c9d578SStephan Aßmus #include <Messenger.h>
285bf2b6ebSBrian Hill #include <Roster.h>
29f7c2983eSAxel Dörfler #include <Screen.h>
3004c9d578SStephan Aßmus #include <ScrollView.h>
3104c9d578SStephan Aßmus #include <StringList.h>
320a9c9029SStephan Aßmus #include <StringView.h>
3304c9d578SStephan Aßmus #include <TabView.h>
3404c9d578SStephan Aßmus 
3504c9d578SStephan Aßmus #include <package/Context.h>
3604c9d578SStephan Aßmus #include <package/manager/Exceptions.h>
3704c9d578SStephan Aßmus #include <package/manager/RepositoryBuilder.h>
3804c9d578SStephan Aßmus #include <package/RefreshRepositoryRequest.h>
3904c9d578SStephan Aßmus #include <package/PackageRoster.h>
4004c9d578SStephan Aßmus #include "package/RepositoryCache.h"
4104c9d578SStephan Aßmus #include <package/solver/SolverPackage.h>
4204c9d578SStephan Aßmus #include <package/solver/SolverProblem.h>
4304c9d578SStephan Aßmus #include <package/solver/SolverProblemSolution.h>
4404c9d578SStephan Aßmus #include <package/solver/SolverRepository.h>
4504c9d578SStephan Aßmus #include <package/solver/SolverResult.h>
4604c9d578SStephan Aßmus 
4704c9d578SStephan Aßmus #include "AutoDeleter.h"
4804c9d578SStephan Aßmus #include "AutoLocker.h"
4904c9d578SStephan Aßmus #include "DecisionProvider.h"
504b930ccaSStephan Aßmus #include "FeaturedPackagesView.h"
5104c9d578SStephan Aßmus #include "FilterView.h"
5204c9d578SStephan Aßmus #include "JobStateListener.h"
53d13c3d89SAndrew Lindesay #include "Logger.h"
5404c9d578SStephan Aßmus #include "PackageInfoView.h"
5504c9d578SStephan Aßmus #include "PackageListView.h"
5604c9d578SStephan Aßmus #include "PackageManager.h"
5704c9d578SStephan Aßmus #include "RatePackageWindow.h"
583b17d8ddSAndrew Lindesay #include "RepositoryUrlUtils.h"
59e0a26dceSStephan Aßmus #include "support.h"
60d5ef985eSStephan Aßmus #include "ScreenshotWindow.h"
6104c9d578SStephan Aßmus #include "UserLoginWindow.h"
62125d42d9SJulian Harnath #include "WorkStatusView.h"
6304c9d578SStephan Aßmus 
6404c9d578SStephan Aßmus 
6504c9d578SStephan Aßmus #undef B_TRANSLATION_CONTEXT
6604c9d578SStephan Aßmus #define B_TRANSLATION_CONTEXT "MainWindow"
6704c9d578SStephan Aßmus 
6804c9d578SStephan Aßmus 
6904c9d578SStephan Aßmus enum {
7004c9d578SStephan Aßmus 	MSG_MODEL_WORKER_DONE		= 'mmwd',
715bf2b6ebSBrian Hill 	MSG_REFRESH_REPOS			= 'mrrp',
725bf2b6ebSBrian Hill 	MSG_MANAGE_REPOS			= 'mmrp',
73d144f952SAugustin Cavalier 	MSG_SOFTWARE_UPDATER		= 'mswu',
7404c9d578SStephan Aßmus 	MSG_LOG_IN					= 'lgin',
758f03a0f9SStephan Aßmus 	MSG_LOG_OUT					= 'lgot',
768f03a0f9SStephan Aßmus 	MSG_AUTHORIZATION_CHANGED	= 'athc',
77da651104SStephan Aßmus 	MSG_PACKAGE_CHANGED			= 'pchd',
78fdec4227SStephan Aßmus 
79*e00a489bSAugustin Cavalier 	MSG_SHOW_FEATURED_PACKAGES	= 'sofp',
80fdec4227SStephan Aßmus 	MSG_SHOW_AVAILABLE_PACKAGES	= 'savl',
81fdec4227SStephan Aßmus 	MSG_SHOW_INSTALLED_PACKAGES	= 'sins',
8204c9d578SStephan Aßmus 	MSG_SHOW_SOURCE_PACKAGES	= 'ssrc',
8304c9d578SStephan Aßmus 	MSG_SHOW_DEVELOP_PACKAGES	= 'sdvl'
8404c9d578SStephan Aßmus };
8504c9d578SStephan Aßmus 
8604c9d578SStephan Aßmus 
8704c9d578SStephan Aßmus using namespace BPackageKit;
8804c9d578SStephan Aßmus using namespace BPackageKit::BManager::BPrivate;
8904c9d578SStephan Aßmus 
9004c9d578SStephan Aßmus 
9104c9d578SStephan Aßmus typedef std::map<BString, PackageInfoRef> PackageInfoMap;
9204c9d578SStephan Aßmus 
9304c9d578SStephan Aßmus 
9404c9d578SStephan Aßmus struct RefreshWorkerParameters {
9504c9d578SStephan Aßmus 	MainWindow* window;
9604c9d578SStephan Aßmus 	bool forceRefresh;
9704c9d578SStephan Aßmus 
9804c9d578SStephan Aßmus 	RefreshWorkerParameters(MainWindow* window, bool forceRefresh)
9904c9d578SStephan Aßmus 		:
10004c9d578SStephan Aßmus 		window(window),
10104c9d578SStephan Aßmus 		forceRefresh(forceRefresh)
10204c9d578SStephan Aßmus 	{
10304c9d578SStephan Aßmus 	}
10404c9d578SStephan Aßmus };
10504c9d578SStephan Aßmus 
10604c9d578SStephan Aßmus 
1078f03a0f9SStephan Aßmus class MessageModelListener : public ModelListener {
1088f03a0f9SStephan Aßmus public:
1098f03a0f9SStephan Aßmus 	MessageModelListener(const BMessenger& messenger)
1108f03a0f9SStephan Aßmus 		:
1118f03a0f9SStephan Aßmus 		fMessenger(messenger)
1128f03a0f9SStephan Aßmus 	{
1138f03a0f9SStephan Aßmus 	}
1148f03a0f9SStephan Aßmus 
1158f03a0f9SStephan Aßmus 	virtual void AuthorizationChanged()
1168f03a0f9SStephan Aßmus 	{
1178f03a0f9SStephan Aßmus 		if (fMessenger.IsValid())
1188f03a0f9SStephan Aßmus 			fMessenger.SendMessage(MSG_AUTHORIZATION_CHANGED);
1198f03a0f9SStephan Aßmus 	}
1208f03a0f9SStephan Aßmus 
1218f03a0f9SStephan Aßmus private:
1228f03a0f9SStephan Aßmus 	BMessenger	fMessenger;
1238f03a0f9SStephan Aßmus };
1248f03a0f9SStephan Aßmus 
1258f03a0f9SStephan Aßmus 
126f7c2983eSAxel Dörfler MainWindow::MainWindow(const BMessage& settings)
12704c9d578SStephan Aßmus 	:
128f7c2983eSAxel Dörfler 	BWindow(BRect(50, 50, 650, 550), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"),
12904c9d578SStephan Aßmus 		B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
13004c9d578SStephan Aßmus 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
131d5ef985eSStephan Aßmus 	fScreenshotWindow(NULL),
132e0a26dceSStephan Aßmus 	fUserMenu(NULL),
133e0a26dceSStephan Aßmus 	fLogInItem(NULL),
134e0a26dceSStephan Aßmus 	fLogOutItem(NULL),
1358f03a0f9SStephan Aßmus 	fModelListener(new MessageModelListener(BMessenger(this)), true),
1363094fef3SAndrew Lindesay 	fBulkLoadStateMachine(&fModel),
13704c9d578SStephan Aßmus 	fTerminating(false),
1386d519fd1SStephan Aßmus 	fSinglePackageMode(false),
13904c9d578SStephan Aßmus 	fModelWorker(B_BAD_THREAD_ID)
14004c9d578SStephan Aßmus {
141cbadcae1SHumdinger 	BMenuBar* menuBar = new BMenuBar("Main Menu");
14204c9d578SStephan Aßmus 	_BuildMenu(menuBar);
14304c9d578SStephan Aßmus 
144cbadcae1SHumdinger 	BMenuBar* userMenuBar = new BMenuBar("User Menu");
145e0a26dceSStephan Aßmus 	_BuildUserMenu(userMenuBar);
146e0a26dceSStephan Aßmus 	set_small_font(userMenuBar);
147e0a26dceSStephan Aßmus 	userMenuBar->SetExplicitMaxSize(BSize(B_SIZE_UNSET,
148e0a26dceSStephan Aßmus 		menuBar->MaxSize().height));
149e0a26dceSStephan Aßmus 
15004c9d578SStephan Aßmus 	fFilterView = new FilterView();
1514b930ccaSStephan Aßmus 	fFeaturedPackagesView = new FeaturedPackagesView();
15204c9d578SStephan Aßmus 	fPackageListView = new PackageListView(fModel.Lock());
15304c9d578SStephan Aßmus 	fPackageInfoView = new PackageInfoView(fModel.Lock(), this);
15404c9d578SStephan Aßmus 
15504c9d578SStephan Aßmus 	fSplitView = new BSplitView(B_VERTICAL, 5.0f);
15604c9d578SStephan Aßmus 
157125d42d9SJulian Harnath 	fWorkStatusView = new WorkStatusView("work status");
158125d42d9SJulian Harnath 	fPackageListView->AttachWorkStatusView(fWorkStatusView);
159125d42d9SJulian Harnath 
160*e00a489bSAugustin Cavalier 	fListTabs = new TabView(BMessenger(this),
161*e00a489bSAugustin Cavalier 		BMessage(MSG_SHOW_FEATURED_PACKAGES), "list tabs");
162*e00a489bSAugustin Cavalier 	fListTabs->AddTab(fFeaturedPackagesView);
163*e00a489bSAugustin Cavalier 	fListTabs->AddTab(fPackageListView);
1644b930ccaSStephan Aßmus 
16504c9d578SStephan Aßmus 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f)
166e0a26dceSStephan Aßmus 		.AddGroup(B_HORIZONTAL, 0.0f)
167e0a26dceSStephan Aßmus 			.Add(menuBar, 1.0f)
168e0a26dceSStephan Aßmus 			.Add(userMenuBar, 0.0f)
169e0a26dceSStephan Aßmus 		.End()
17004c9d578SStephan Aßmus 		.Add(fFilterView)
17104c9d578SStephan Aßmus 		.AddSplit(fSplitView)
17204c9d578SStephan Aßmus 			.AddGroup(B_VERTICAL)
173*e00a489bSAugustin Cavalier 				.Add(fListTabs)
17404c9d578SStephan Aßmus 				.SetInsets(
17504c9d578SStephan Aßmus 					B_USE_DEFAULT_SPACING, 0.0f,
17604c9d578SStephan Aßmus 					B_USE_DEFAULT_SPACING, 0.0f)
17704c9d578SStephan Aßmus 			.End()
17804c9d578SStephan Aßmus 			.Add(fPackageInfoView)
17904c9d578SStephan Aßmus 		.End()
180125d42d9SJulian Harnath 		.Add(fWorkStatusView)
18104c9d578SStephan Aßmus 	;
18204c9d578SStephan Aßmus 
18304c9d578SStephan Aßmus 	fSplitView->SetCollapsible(0, false);
18404c9d578SStephan Aßmus 	fSplitView->SetCollapsible(1, false);
18504c9d578SStephan Aßmus 
1868f03a0f9SStephan Aßmus 	fModel.AddListener(fModelListener);
1878f03a0f9SStephan Aßmus 
18804c9d578SStephan Aßmus 	// Restore settings
18904c9d578SStephan Aßmus 	BMessage columnSettings;
19004c9d578SStephan Aßmus 	if (settings.FindMessage("column settings", &columnSettings) == B_OK)
19104c9d578SStephan Aßmus 		fPackageListView->LoadState(&columnSettings);
19204c9d578SStephan Aßmus 
19304c9d578SStephan Aßmus 	bool showOption;
1942997e05bSStephan Aßmus 	if (settings.FindBool("show featured packages", &showOption) == B_OK)
1952997e05bSStephan Aßmus 		fModel.SetShowFeaturedPackages(showOption);
1962997e05bSStephan Aßmus 	if (settings.FindBool("show available packages", &showOption) == B_OK)
1972997e05bSStephan Aßmus 		fModel.SetShowAvailablePackages(showOption);
1982997e05bSStephan Aßmus 	if (settings.FindBool("show installed packages", &showOption) == B_OK)
1992997e05bSStephan Aßmus 		fModel.SetShowInstalledPackages(showOption);
20004c9d578SStephan Aßmus 	if (settings.FindBool("show develop packages", &showOption) == B_OK)
20104c9d578SStephan Aßmus 		fModel.SetShowDevelopPackages(showOption);
20204c9d578SStephan Aßmus 	if (settings.FindBool("show source packages", &showOption) == B_OK)
20304c9d578SStephan Aßmus 		fModel.SetShowSourcePackages(showOption);
20404c9d578SStephan Aßmus 
2052997e05bSStephan Aßmus 	if (fModel.ShowFeaturedPackages())
206*e00a489bSAugustin Cavalier 		fListTabs->Select(0);
2072997e05bSStephan Aßmus 	else
208*e00a489bSAugustin Cavalier 		fListTabs->Select(1);
2092997e05bSStephan Aßmus 
210f7c2983eSAxel Dörfler 	_RestoreUserName(settings);
211f7c2983eSAxel Dörfler 	_RestoreWindowFrame(settings);
212f7c2983eSAxel Dörfler 
21372fff6d3SJulian Harnath 	atomic_set(&fPackagesToShowListID, 0);
21472fff6d3SJulian Harnath 
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 
225f7c2983eSAxel Dörfler MainWindow::MainWindow(const BMessage& settings, const PackageInfoRef& package)
2266d519fd1SStephan Aßmus 	:
227f7c2983eSAxel 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),
230d78bfd8dSJulian Harnath 	fWorkStatusView(NULL),
231d5ef985eSStephan Aßmus 	fScreenshotWindow(NULL),
232e0a26dceSStephan Aßmus 	fUserMenu(NULL),
233e0a26dceSStephan Aßmus 	fLogInItem(NULL),
2346d519fd1SStephan Aßmus 	fLogOutItem(NULL),
2356d519fd1SStephan Aßmus 	fModelListener(new MessageModelListener(BMessenger(this)), true),
2363094fef3SAndrew Lindesay 	fBulkLoadStateMachine(&fModel),
2376d519fd1SStephan Aßmus 	fTerminating(false),
2386d519fd1SStephan Aßmus 	fSinglePackageMode(true),
2396d519fd1SStephan Aßmus 	fModelWorker(B_BAD_THREAD_ID)
2406d519fd1SStephan Aßmus {
2416d519fd1SStephan Aßmus 	fFilterView = new FilterView();
2426d519fd1SStephan Aßmus 	fPackageListView = new PackageListView(fModel.Lock());
2436d519fd1SStephan Aßmus 	fPackageInfoView = new PackageInfoView(fModel.Lock(), this);
2446d519fd1SStephan Aßmus 
2456d519fd1SStephan Aßmus 	BLayoutBuilder::Group<>(this, B_VERTICAL)
2466d519fd1SStephan Aßmus 		.Add(fPackageInfoView)
2476d519fd1SStephan Aßmus 		.SetInsets(0, B_USE_WINDOW_INSETS, 0, 0)
2486d519fd1SStephan Aßmus 	;
2496d519fd1SStephan Aßmus 
2506d519fd1SStephan Aßmus 	fModel.AddListener(fModelListener);
2516d519fd1SStephan Aßmus 
2526d519fd1SStephan Aßmus 	// Restore settings
253f7c2983eSAxel Dörfler 	_RestoreUserName(settings);
254f7c2983eSAxel Dörfler 	_RestoreWindowFrame(settings);
2556d519fd1SStephan Aßmus 
2566d519fd1SStephan Aßmus 	fPackageInfoView->SetPackage(package);
25763975654SStephan Aßmus 
25863975654SStephan Aßmus 	_InitWorkerThreads();
2596d519fd1SStephan Aßmus }
2606d519fd1SStephan Aßmus 
2616d519fd1SStephan Aßmus 
26204c9d578SStephan Aßmus MainWindow::~MainWindow()
26304c9d578SStephan Aßmus {
26404c9d578SStephan Aßmus 	BPackageRoster().StopWatching(this);
26504c9d578SStephan Aßmus 
26604c9d578SStephan Aßmus 	fTerminating = true;
26705bffa62SStephan Aßmus 	if (fModelWorker >= 0)
26804c9d578SStephan Aßmus 		wait_for_thread(fModelWorker, NULL);
26904c9d578SStephan Aßmus 
27004c9d578SStephan Aßmus 	delete_sem(fPendingActionsSem);
27105bffa62SStephan Aßmus 	if (fPendingActionsWorker >= 0)
27204c9d578SStephan Aßmus 		wait_for_thread(fPendingActionsWorker, NULL);
27304c9d578SStephan Aßmus 
27404c9d578SStephan Aßmus 	delete_sem(fPackageToPopulateSem);
27505bffa62SStephan Aßmus 	if (fPopulatePackageWorker >= 0)
27604c9d578SStephan Aßmus 		wait_for_thread(fPopulatePackageWorker, NULL);
277d5ef985eSStephan Aßmus 
27872fff6d3SJulian Harnath 	delete_sem(fNewPackagesToShowSem);
27972fff6d3SJulian Harnath 	delete_sem(fShowPackagesAcknowledgeSem);
28072fff6d3SJulian Harnath 	if (fShowPackagesWorker >= 0)
28172fff6d3SJulian Harnath 		wait_for_thread(fShowPackagesWorker, NULL);
28272fff6d3SJulian Harnath 
283d5ef985eSStephan Aßmus 	if (fScreenshotWindow != NULL && fScreenshotWindow->Lock())
284d5ef985eSStephan Aßmus 		fScreenshotWindow->Quit();
28504c9d578SStephan Aßmus }
28604c9d578SStephan Aßmus 
28704c9d578SStephan Aßmus 
28804c9d578SStephan Aßmus bool
28904c9d578SStephan Aßmus MainWindow::QuitRequested()
29004c9d578SStephan Aßmus {
29104c9d578SStephan Aßmus 	BMessage settings;
29204c9d578SStephan Aßmus 	StoreSettings(settings);
29304c9d578SStephan Aßmus 
29404c9d578SStephan Aßmus 	BMessage message(MSG_MAIN_WINDOW_CLOSED);
29504c9d578SStephan Aßmus 	message.AddMessage("window settings", &settings);
29604c9d578SStephan Aßmus 
29704c9d578SStephan Aßmus 	be_app->PostMessage(&message);
29804c9d578SStephan Aßmus 
29904c9d578SStephan Aßmus 	return true;
30004c9d578SStephan Aßmus }
30104c9d578SStephan Aßmus 
30204c9d578SStephan Aßmus 
30304c9d578SStephan Aßmus void
30404c9d578SStephan Aßmus MainWindow::MessageReceived(BMessage* message)
30504c9d578SStephan Aßmus {
30604c9d578SStephan Aßmus 	switch (message->what) {
30704c9d578SStephan Aßmus 		case MSG_MODEL_WORKER_DONE:
30804c9d578SStephan Aßmus 		{
30904c9d578SStephan Aßmus 			fModelWorker = B_BAD_THREAD_ID;
31004c9d578SStephan Aßmus 			_AdoptModel();
311b965ce70SHumdinger 			_UpdateAvailableRepositories();
312125d42d9SJulian Harnath 			fWorkStatusView->SetIdle();
31304c9d578SStephan Aßmus 			break;
31404c9d578SStephan Aßmus 		}
31504c9d578SStephan Aßmus 		case B_SIMPLE_DATA:
31604c9d578SStephan Aßmus 		case B_REFS_RECEIVED:
31704c9d578SStephan Aßmus 			// TODO: ?
31804c9d578SStephan Aßmus 			break;
31904c9d578SStephan Aßmus 
32004c9d578SStephan Aßmus 		case B_PACKAGE_UPDATE:
32104c9d578SStephan Aßmus 			// TODO: We should do a more selective update depending on the
32204c9d578SStephan Aßmus 			// "event", "location", and "change count" fields!
32304c9d578SStephan Aßmus 			_StartRefreshWorker(false);
32404c9d578SStephan Aßmus 			break;
32504c9d578SStephan Aßmus 
3265bf2b6ebSBrian Hill 		case MSG_REFRESH_REPOS:
32704c9d578SStephan Aßmus 			_StartRefreshWorker(true);
32804c9d578SStephan Aßmus 			break;
32904c9d578SStephan Aßmus 
3305bf2b6ebSBrian Hill 		case MSG_MANAGE_REPOS:
3315bf2b6ebSBrian Hill 			be_roster->Launch("application/x-vnd.Haiku-Repositories");
3325bf2b6ebSBrian Hill 			break;
3335bf2b6ebSBrian Hill 
334d144f952SAugustin Cavalier 		case MSG_SOFTWARE_UPDATER:
335d144f952SAugustin Cavalier 			be_roster->Launch("application/x-vnd.haiku-softwareupdater");
336d144f952SAugustin Cavalier 			break;
337d144f952SAugustin Cavalier 
33804c9d578SStephan Aßmus 		case MSG_LOG_IN:
3391bbda92dSStephan Aßmus 			_OpenLoginWindow(BMessage());
34004c9d578SStephan Aßmus 			break;
34104c9d578SStephan Aßmus 
3428f03a0f9SStephan Aßmus 		case MSG_LOG_OUT:
3438f03a0f9SStephan Aßmus 			fModel.SetUsername("");
3448f03a0f9SStephan Aßmus 			break;
3458f03a0f9SStephan Aßmus 
3468f03a0f9SStephan Aßmus 		case MSG_AUTHORIZATION_CHANGED:
3478f03a0f9SStephan Aßmus 			_UpdateAuthorization();
3488f03a0f9SStephan Aßmus 			break;
3498f03a0f9SStephan Aßmus 
3504fade61fSStephan Aßmus 		case MSG_SHOW_FEATURED_PACKAGES:
351*e00a489bSAugustin Cavalier 			// check to see if we aren't already on the current tab
352*e00a489bSAugustin Cavalier 			if (fListTabs->Selection() ==
353*e00a489bSAugustin Cavalier 					(fModel.ShowFeaturedPackages() ? 0 : 1))
354*e00a489bSAugustin Cavalier 				break;
3554fade61fSStephan Aßmus 			{
3564fade61fSStephan Aßmus 				BAutolock locker(fModel.Lock());
3574fade61fSStephan Aßmus 				fModel.SetShowFeaturedPackages(
358*e00a489bSAugustin Cavalier 					fListTabs->Selection() == 0);
3594fade61fSStephan Aßmus 			}
3604fade61fSStephan Aßmus 			_AdoptModel();
3614fade61fSStephan Aßmus 			break;
3624fade61fSStephan Aßmus 
363fdec4227SStephan Aßmus 		case MSG_SHOW_AVAILABLE_PACKAGES:
364fdec4227SStephan Aßmus 			{
365fdec4227SStephan Aßmus 				BAutolock locker(fModel.Lock());
366fdec4227SStephan Aßmus 				fModel.SetShowAvailablePackages(
367fdec4227SStephan Aßmus 					!fModel.ShowAvailablePackages());
368fdec4227SStephan Aßmus 			}
369fdec4227SStephan Aßmus 			_AdoptModel();
370fdec4227SStephan Aßmus 			break;
371fdec4227SStephan Aßmus 
372fdec4227SStephan Aßmus 		case MSG_SHOW_INSTALLED_PACKAGES:
373fdec4227SStephan Aßmus 			{
374fdec4227SStephan Aßmus 				BAutolock locker(fModel.Lock());
375fdec4227SStephan Aßmus 				fModel.SetShowInstalledPackages(
376fdec4227SStephan Aßmus 					!fModel.ShowInstalledPackages());
377fdec4227SStephan Aßmus 			}
378fdec4227SStephan Aßmus 			_AdoptModel();
379fdec4227SStephan Aßmus 			break;
380fdec4227SStephan Aßmus 
38104c9d578SStephan Aßmus 		case MSG_SHOW_SOURCE_PACKAGES:
38204c9d578SStephan Aßmus 			{
38304c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
38404c9d578SStephan Aßmus 				fModel.SetShowSourcePackages(!fModel.ShowSourcePackages());
38504c9d578SStephan Aßmus 			}
38604c9d578SStephan Aßmus 			_AdoptModel();
38704c9d578SStephan Aßmus 			break;
38804c9d578SStephan Aßmus 
38904c9d578SStephan Aßmus 		case MSG_SHOW_DEVELOP_PACKAGES:
39004c9d578SStephan Aßmus 			{
39104c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
39204c9d578SStephan Aßmus 				fModel.SetShowDevelopPackages(!fModel.ShowDevelopPackages());
39304c9d578SStephan Aßmus 			}
39404c9d578SStephan Aßmus 			_AdoptModel();
39504c9d578SStephan Aßmus 			break;
39604c9d578SStephan Aßmus 
397a9edb9bfSAndrew Lindesay 			// this may be triggered by, for example, a user rating being added
398a9edb9bfSAndrew Lindesay 			// or having been altered.
399a9edb9bfSAndrew Lindesay 		case MSG_SERVER_DATA_CHANGED:
400a9edb9bfSAndrew Lindesay 		{
401a9edb9bfSAndrew Lindesay 			BString name;
402a9edb9bfSAndrew Lindesay 			if (message->FindString("name", &name) == B_OK) {
403a9edb9bfSAndrew Lindesay 				BAutolock locker(fModel.Lock());
404a9edb9bfSAndrew Lindesay 				if (fPackageInfoView->Package()->Name() == name) {
405a9edb9bfSAndrew Lindesay 					_PopulatePackageAsync(true);
406a9edb9bfSAndrew Lindesay 				} else {
407a9edb9bfSAndrew Lindesay 					if (Logger::IsDebugEnabled()) {
408a9edb9bfSAndrew Lindesay 						printf("pkg [%s] is updated on the server, but is "
409a9edb9bfSAndrew Lindesay 							"not selected so will not be updated.\n",
410a9edb9bfSAndrew Lindesay 							name.String());
411a9edb9bfSAndrew Lindesay 					}
412a9edb9bfSAndrew Lindesay 				}
413a9edb9bfSAndrew Lindesay 			}
414a9edb9bfSAndrew Lindesay         	break;
415a9edb9bfSAndrew Lindesay         }
416a9edb9bfSAndrew Lindesay 
41704c9d578SStephan Aßmus 		case MSG_PACKAGE_SELECTED:
41804c9d578SStephan Aßmus 		{
41972992391SStephan Aßmus 			BString name;
42072992391SStephan Aßmus 			if (message->FindString("name", &name) == B_OK) {
42175ba9dbfSStephan Aßmus 				BAutolock locker(fModel.Lock());
42204c9d578SStephan Aßmus 				int count = fVisiblePackages.CountItems();
42304c9d578SStephan Aßmus 				for (int i = 0; i < count; i++) {
42404c9d578SStephan Aßmus 					const PackageInfoRef& package
42504c9d578SStephan Aßmus 						= fVisiblePackages.ItemAtFast(i);
42672992391SStephan Aßmus 					if (package.Get() != NULL && package->Name() == name) {
42775ba9dbfSStephan Aßmus 						locker.Unlock();
42804c9d578SStephan Aßmus 						_AdoptPackage(package);
42904c9d578SStephan Aßmus 						break;
43004c9d578SStephan Aßmus 					}
43104c9d578SStephan Aßmus 				}
43204c9d578SStephan Aßmus 			} else {
43304c9d578SStephan Aßmus 				_ClearPackage();
43404c9d578SStephan Aßmus 			}
43504c9d578SStephan Aßmus 			break;
43604c9d578SStephan Aßmus 		}
43704c9d578SStephan Aßmus 
43804c9d578SStephan Aßmus 		case MSG_CATEGORY_SELECTED:
43904c9d578SStephan Aßmus 		{
44004c9d578SStephan Aßmus 			BString name;
44104c9d578SStephan Aßmus 			if (message->FindString("name", &name) != B_OK)
44204c9d578SStephan Aßmus 				name = "";
44304c9d578SStephan Aßmus 			{
44404c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
44504c9d578SStephan Aßmus 				fModel.SetCategory(name);
44604c9d578SStephan Aßmus 			}
44704c9d578SStephan Aßmus 			_AdoptModel();
44804c9d578SStephan Aßmus 			break;
44904c9d578SStephan Aßmus 		}
45004c9d578SStephan Aßmus 
45104c9d578SStephan Aßmus 		case MSG_DEPOT_SELECTED:
45204c9d578SStephan Aßmus 		{
45304c9d578SStephan Aßmus 			BString name;
45404c9d578SStephan Aßmus 			if (message->FindString("name", &name) != B_OK)
45504c9d578SStephan Aßmus 				name = "";
45604c9d578SStephan Aßmus 			{
45704c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
45804c9d578SStephan Aßmus 				fModel.SetDepot(name);
45904c9d578SStephan Aßmus 			}
46004c9d578SStephan Aßmus 			_AdoptModel();
461b965ce70SHumdinger 			_UpdateAvailableRepositories();
46204c9d578SStephan Aßmus 			break;
46304c9d578SStephan Aßmus 		}
46404c9d578SStephan Aßmus 
46504c9d578SStephan Aßmus 		case MSG_SEARCH_TERMS_MODIFIED:
46604c9d578SStephan Aßmus 		{
46704c9d578SStephan Aßmus 			// TODO: Do this with a delay!
46804c9d578SStephan Aßmus 			BString searchTerms;
46904c9d578SStephan Aßmus 			if (message->FindString("search terms", &searchTerms) != B_OK)
47004c9d578SStephan Aßmus 				searchTerms = "";
47104c9d578SStephan Aßmus 			{
47204c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
47304c9d578SStephan Aßmus 				fModel.SetSearchTerms(searchTerms);
47404c9d578SStephan Aßmus 			}
47504c9d578SStephan Aßmus 			_AdoptModel();
47604c9d578SStephan Aßmus 			break;
47704c9d578SStephan Aßmus 		}
47804c9d578SStephan Aßmus 
479da651104SStephan Aßmus 		case MSG_PACKAGE_CHANGED:
48004c9d578SStephan Aßmus 		{
48104c9d578SStephan Aßmus 			PackageInfo* info;
48204c9d578SStephan Aßmus 			if (message->FindPointer("package", (void**)&info) == B_OK) {
48304c9d578SStephan Aßmus 				PackageInfoRef ref(info, true);
484da651104SStephan Aßmus 				uint32 changes;
485da651104SStephan Aßmus 				if (message->FindUInt32("changes", &changes) != B_OK)
486da651104SStephan Aßmus 					changes = 0;
487da651104SStephan Aßmus 				if ((changes & PKG_CHANGED_STATE) != 0) {
48804c9d578SStephan Aßmus 					BAutolock locker(fModel.Lock());
48904c9d578SStephan Aßmus 					fModel.SetPackageState(ref, ref->State());
49004c9d578SStephan Aßmus 				}
49157e51fffSStephan Aßmus 
49257e51fffSStephan Aßmus 				// Asynchronous updates to the package information
49357e51fffSStephan Aßmus 				// can mean that the package needs to be added or
49457e51fffSStephan Aßmus 				// removed to/from the visible packages when the current
49557e51fffSStephan Aßmus 				// filter parameters are re-evaluated on this package.
49657e51fffSStephan Aßmus 				bool wasVisible = fVisiblePackages.Contains(ref);
49757e51fffSStephan Aßmus 				bool isVisible;
49857e51fffSStephan Aßmus 				{
499da651104SStephan Aßmus 					BAutolock locker(fModel.Lock());
5000c6df5d5SStephan Aßmus 					// The package didn't get a chance yet to be in the
5010c6df5d5SStephan Aßmus 					// visible package list
50239f49f70SJulian Harnath 					isVisible = fModel.MatchesFilter(ref);
50357e51fffSStephan Aßmus 
50457e51fffSStephan Aßmus 					// Transfer this single package, otherwise we miss
50557e51fffSStephan Aßmus 					// other packages if they appear or disappear along
50657e51fffSStephan Aßmus 					// with this one before receive a notification for
50757e51fffSStephan Aßmus 					// them.
50857e51fffSStephan Aßmus 					if (isVisible) {
50957e51fffSStephan Aßmus 						fVisiblePackages.Add(ref);
51057e51fffSStephan Aßmus 					} else if (wasVisible)
51157e51fffSStephan Aßmus 						fVisiblePackages.Remove(ref);
51257e51fffSStephan Aßmus 				}
51357e51fffSStephan Aßmus 
51457e51fffSStephan Aßmus 				if (wasVisible != isVisible) {
51557e51fffSStephan Aßmus 					if (!isVisible) {
51657e51fffSStephan Aßmus 						fPackageListView->RemovePackage(ref);
51757e51fffSStephan Aßmus 						fFeaturedPackagesView->RemovePackage(ref);
51857e51fffSStephan Aßmus 					} else {
51957e51fffSStephan Aßmus 						fPackageListView->AddPackage(ref);
52057e51fffSStephan Aßmus 						if (ref->IsProminent())
521da651104SStephan Aßmus 							fFeaturedPackagesView->AddPackage(ref);
522da651104SStephan Aßmus 					}
523da651104SStephan Aßmus 				}
5244e6fbe03SJulian Harnath 
5254e6fbe03SJulian Harnath 				if (!fSinglePackageMode && (changes & PKG_CHANGED_STATE) != 0)
5264e6fbe03SJulian Harnath 					fWorkStatusView->PackageStatusChanged(ref);
52757e51fffSStephan Aßmus 			}
52804c9d578SStephan Aßmus 			break;
52904c9d578SStephan Aßmus 		}
53004c9d578SStephan Aßmus 
53104c9d578SStephan Aßmus 		case MSG_RATE_PACKAGE:
5321bbda92dSStephan Aßmus 			_RatePackage();
53304c9d578SStephan Aßmus 			break;
53404c9d578SStephan Aßmus 
535d5ef985eSStephan Aßmus 		case MSG_SHOW_SCREENSHOT:
536d5ef985eSStephan Aßmus 			_ShowScreenshot();
537d5ef985eSStephan Aßmus 			break;
538d5ef985eSStephan Aßmus 
539125d42d9SJulian Harnath 		case MSG_PACKAGE_WORKER_BUSY:
540125d42d9SJulian Harnath 		{
541125d42d9SJulian Harnath 			BString reason;
542125d42d9SJulian Harnath 			status_t status = message->FindString("reason", &reason);
543125d42d9SJulian Harnath 			if (status != B_OK)
544125d42d9SJulian Harnath 				break;
545d78bfd8dSJulian Harnath 			if (!fSinglePackageMode)
546125d42d9SJulian Harnath 				fWorkStatusView->SetBusy(reason);
547125d42d9SJulian Harnath 			break;
548125d42d9SJulian Harnath 		}
549125d42d9SJulian Harnath 
550125d42d9SJulian Harnath 		case MSG_PACKAGE_WORKER_IDLE:
551d78bfd8dSJulian Harnath 			if (!fSinglePackageMode)
552125d42d9SJulian Harnath 				fWorkStatusView->SetIdle();
553125d42d9SJulian Harnath 			break;
554125d42d9SJulian Harnath 
55572fff6d3SJulian Harnath 		case MSG_ADD_VISIBLE_PACKAGES:
55672fff6d3SJulian Harnath 		{
55772fff6d3SJulian Harnath 			struct SemaphoreReleaser {
55872fff6d3SJulian Harnath 				SemaphoreReleaser(sem_id semaphore)
55972fff6d3SJulian Harnath 					:
56072fff6d3SJulian Harnath 					fSemaphore(semaphore)
56172fff6d3SJulian Harnath 				{ }
56272fff6d3SJulian Harnath 
56372fff6d3SJulian Harnath 				~SemaphoreReleaser() { release_sem(fSemaphore); }
56472fff6d3SJulian Harnath 
56572fff6d3SJulian Harnath 				sem_id fSemaphore;
56672fff6d3SJulian Harnath 			};
56772fff6d3SJulian Harnath 
56872fff6d3SJulian Harnath 			// Make sure acknowledge semaphore is released even on error,
56972fff6d3SJulian Harnath 			// so the worker thread won't be blocked
57072fff6d3SJulian Harnath 			SemaphoreReleaser acknowledger(fShowPackagesAcknowledgeSem);
57172fff6d3SJulian Harnath 
57272fff6d3SJulian Harnath 			int32 numPackages = 0;
57372fff6d3SJulian Harnath 			type_code unused;
57472fff6d3SJulian Harnath 			status_t status = message->GetInfo("package_ref", &unused,
57572fff6d3SJulian Harnath 				&numPackages);
57672fff6d3SJulian Harnath 			if (status != B_OK || numPackages == 0)
57772fff6d3SJulian Harnath 				break;
57872fff6d3SJulian Harnath 
57972fff6d3SJulian Harnath 			int32 listID = 0;
58072fff6d3SJulian Harnath 			status = message->FindInt32("list_id", &listID);
58172fff6d3SJulian Harnath 			if (status != B_OK)
58272fff6d3SJulian Harnath 				break;
58372fff6d3SJulian Harnath 			if (listID != atomic_get(&fPackagesToShowListID)) {
58472fff6d3SJulian Harnath 				// list is outdated, ignore
58572fff6d3SJulian Harnath 				break;
58672fff6d3SJulian Harnath 			}
58772fff6d3SJulian Harnath 
58872fff6d3SJulian Harnath 			for (int i = 0; i < numPackages; i++) {
58972fff6d3SJulian Harnath 				PackageInfo* packageRaw = NULL;
59072fff6d3SJulian Harnath 				status = message->FindPointer("package_ref", i,
59172fff6d3SJulian Harnath 					(void**)&packageRaw);
59272fff6d3SJulian Harnath 				if (status != B_OK)
59372fff6d3SJulian Harnath 					break;
59472fff6d3SJulian Harnath 				PackageInfoRef package(packageRaw, true);
59572fff6d3SJulian Harnath 
59672fff6d3SJulian Harnath 				fPackageListView->AddPackage(package);
59772fff6d3SJulian Harnath 				if (package->IsProminent())
59872fff6d3SJulian Harnath 					fFeaturedPackagesView->AddPackage(package);
59972fff6d3SJulian Harnath 			}
60072fff6d3SJulian Harnath 			break;
60172fff6d3SJulian Harnath 		}
60272fff6d3SJulian Harnath 
60372fff6d3SJulian Harnath 		case MSG_UPDATE_SELECTED_PACKAGE:
60472fff6d3SJulian Harnath 		{
60572fff6d3SJulian Harnath 			const PackageInfoRef& selectedPackage = fPackageInfoView->Package();
60672fff6d3SJulian Harnath 			fFeaturedPackagesView->SelectPackage(selectedPackage, true);
60772fff6d3SJulian Harnath 			fPackageListView->SelectPackage(selectedPackage);
60872fff6d3SJulian Harnath 
60972fff6d3SJulian Harnath 			AutoLocker<BLocker> modelLocker(fModel.Lock());
61072fff6d3SJulian Harnath 			if (!fVisiblePackages.Contains(fPackageInfoView->Package()))
61172fff6d3SJulian Harnath 				fPackageInfoView->Clear();
61272fff6d3SJulian Harnath 			break;
61372fff6d3SJulian Harnath 		}
61472fff6d3SJulian Harnath 
61504c9d578SStephan Aßmus 		default:
61604c9d578SStephan Aßmus 			BWindow::MessageReceived(message);
61704c9d578SStephan Aßmus 			break;
61804c9d578SStephan Aßmus 	}
61904c9d578SStephan Aßmus }
62004c9d578SStephan Aßmus 
62104c9d578SStephan Aßmus 
62204c9d578SStephan Aßmus void
62304c9d578SStephan Aßmus MainWindow::StoreSettings(BMessage& settings) const
62404c9d578SStephan Aßmus {
625f7c2983eSAxel Dörfler 	settings.AddRect(_WindowFrameName(), Frame());
626f7c2983eSAxel Dörfler 	if (!fSinglePackageMode) {
62704c9d578SStephan Aßmus 		settings.AddRect("window frame", Frame());
62804c9d578SStephan Aßmus 
62904c9d578SStephan Aßmus 		BMessage columnSettings;
63004c9d578SStephan Aßmus 		fPackageListView->SaveState(&columnSettings);
63104c9d578SStephan Aßmus 
63204c9d578SStephan Aßmus 		settings.AddMessage("column settings", &columnSettings);
63304c9d578SStephan Aßmus 
6342997e05bSStephan Aßmus 		settings.AddBool("show featured packages",
6352997e05bSStephan Aßmus 			fModel.ShowFeaturedPackages());
6362997e05bSStephan Aßmus 		settings.AddBool("show available packages",
6372997e05bSStephan Aßmus 			fModel.ShowAvailablePackages());
6382997e05bSStephan Aßmus 		settings.AddBool("show installed packages",
6392997e05bSStephan Aßmus 			fModel.ShowInstalledPackages());
64004c9d578SStephan Aßmus 		settings.AddBool("show develop packages", fModel.ShowDevelopPackages());
64104c9d578SStephan Aßmus 		settings.AddBool("show source packages", fModel.ShowSourcePackages());
6426d519fd1SStephan Aßmus 	}
6438f03a0f9SStephan Aßmus 
6448f03a0f9SStephan Aßmus 	settings.AddString("username", fModel.Username());
64504c9d578SStephan Aßmus }
64604c9d578SStephan Aßmus 
64704c9d578SStephan Aßmus 
64804c9d578SStephan Aßmus void
64904c9d578SStephan Aßmus MainWindow::PackageChanged(const PackageInfoEvent& event)
65004c9d578SStephan Aßmus {
651a9edb9bfSAndrew Lindesay 	uint32 watchedChanges = PKG_CHANGED_STATE | PKG_CHANGED_PROMINENCE;
652a9edb9bfSAndrew Lindesay 	if ((event.Changes() & watchedChanges) != 0) {
65304c9d578SStephan Aßmus 		PackageInfoRef ref(event.Package());
654da651104SStephan Aßmus 		BMessage message(MSG_PACKAGE_CHANGED);
65504c9d578SStephan Aßmus 		message.AddPointer("package", ref.Get());
656da651104SStephan Aßmus 		message.AddUInt32("changes", event.Changes());
65704c9d578SStephan Aßmus 		ref.Detach();
65804c9d578SStephan Aßmus 			// reference needs to be released by MessageReceived();
65904c9d578SStephan Aßmus 		PostMessage(&message);
66004c9d578SStephan Aßmus 	}
66104c9d578SStephan Aßmus }
66204c9d578SStephan Aßmus 
66304c9d578SStephan Aßmus 
66404c9d578SStephan Aßmus status_t
66504c9d578SStephan Aßmus MainWindow::SchedulePackageActions(PackageActionList& list)
66604c9d578SStephan Aßmus {
66704c9d578SStephan Aßmus 	AutoLocker<BLocker> lock(&fPendingActionsLock);
66804c9d578SStephan Aßmus 	for (int32 i = 0; i < list.CountItems(); i++) {
66904c9d578SStephan Aßmus 		if (!fPendingActions.Add(list.ItemAtFast(i)))
67004c9d578SStephan Aßmus 			return B_NO_MEMORY;
67104c9d578SStephan Aßmus 	}
67204c9d578SStephan Aßmus 
67304c9d578SStephan Aßmus 	return release_sem_etc(fPendingActionsSem, list.CountItems(), 0);
67404c9d578SStephan Aßmus }
67504c9d578SStephan Aßmus 
67604c9d578SStephan Aßmus 
67704c9d578SStephan Aßmus Model*
67804c9d578SStephan Aßmus MainWindow::GetModel()
67904c9d578SStephan Aßmus {
68004c9d578SStephan Aßmus 	return &fModel;
68104c9d578SStephan Aßmus }
68204c9d578SStephan Aßmus 
68304c9d578SStephan Aßmus 
68404c9d578SStephan Aßmus void
68504c9d578SStephan Aßmus MainWindow::_BuildMenu(BMenuBar* menuBar)
68604c9d578SStephan Aßmus {
68704c9d578SStephan Aßmus 	BMenu* menu = new BMenu(B_TRANSLATE("Tools"));
6885bf2b6ebSBrian Hill 	menu->AddItem(new BMenuItem(B_TRANSLATE("Refresh repositories"),
6895bf2b6ebSBrian Hill 		new BMessage(MSG_REFRESH_REPOS)));
690d7f78130SHumdinger 	menu->AddItem(new BMenuItem(B_TRANSLATE("Manage repositories"
691d7f78130SHumdinger 		B_UTF8_ELLIPSIS), new BMessage(MSG_MANAGE_REPOS)));
692d144f952SAugustin Cavalier 	menu->AddItem(new BMenuItem(B_TRANSLATE("Check for updates"
693d144f952SAugustin Cavalier 		B_UTF8_ELLIPSIS), new BMessage(MSG_SOFTWARE_UPDATER)));
694e0a26dceSStephan Aßmus 
69504c9d578SStephan Aßmus 	menuBar->AddItem(menu);
69604c9d578SStephan Aßmus 
697b965ce70SHumdinger 	fRepositoryMenu = new BMenu(B_TRANSLATE("Repositories"));
698b965ce70SHumdinger 	menuBar->AddItem(fRepositoryMenu);
699b965ce70SHumdinger 
7004fade61fSStephan Aßmus 	menu = new BMenu(B_TRANSLATE("Show"));
7014fade61fSStephan Aßmus 
702fdec4227SStephan Aßmus 	fShowAvailablePackagesItem = new BMenuItem(
7034fade61fSStephan Aßmus 		B_TRANSLATE("Available packages"),
704fdec4227SStephan Aßmus 		new BMessage(MSG_SHOW_AVAILABLE_PACKAGES));
705fdec4227SStephan Aßmus 	menu->AddItem(fShowAvailablePackagesItem);
706fdec4227SStephan Aßmus 
707fdec4227SStephan Aßmus 	fShowInstalledPackagesItem = new BMenuItem(
7084fade61fSStephan Aßmus 		B_TRANSLATE("Installed packages"),
709fdec4227SStephan Aßmus 		new BMessage(MSG_SHOW_INSTALLED_PACKAGES));
710fdec4227SStephan Aßmus 	menu->AddItem(fShowInstalledPackagesItem);
711fdec4227SStephan Aßmus 
712fdec4227SStephan Aßmus 	menu->AddSeparatorItem();
713fdec4227SStephan Aßmus 
714fdec4227SStephan Aßmus 	fShowDevelopPackagesItem = new BMenuItem(
7154fade61fSStephan Aßmus 		B_TRANSLATE("Develop packages"),
716fdec4227SStephan Aßmus 		new BMessage(MSG_SHOW_DEVELOP_PACKAGES));
717fdec4227SStephan Aßmus 	menu->AddItem(fShowDevelopPackagesItem);
718fdec4227SStephan Aßmus 
719fdec4227SStephan Aßmus 	fShowSourcePackagesItem = new BMenuItem(
7204fade61fSStephan Aßmus 		B_TRANSLATE("Source packages"),
721fdec4227SStephan Aßmus 		new BMessage(MSG_SHOW_SOURCE_PACKAGES));
722fdec4227SStephan Aßmus 	menu->AddItem(fShowSourcePackagesItem);
723fdec4227SStephan Aßmus 
724fdec4227SStephan Aßmus 	menuBar->AddItem(menu);
72504c9d578SStephan Aßmus }
72604c9d578SStephan Aßmus 
72704c9d578SStephan Aßmus 
72804c9d578SStephan Aßmus void
729e0a26dceSStephan Aßmus MainWindow::_BuildUserMenu(BMenuBar* menuBar)
730e0a26dceSStephan Aßmus {
731e0a26dceSStephan Aßmus 	fUserMenu = new BMenu(B_TRANSLATE("Not logged in"));
732e0a26dceSStephan Aßmus 
733e0a26dceSStephan Aßmus 	fLogInItem = new BMenuItem(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS),
734e0a26dceSStephan Aßmus 		new BMessage(MSG_LOG_IN));
735e0a26dceSStephan Aßmus 	fUserMenu->AddItem(fLogInItem);
736e0a26dceSStephan Aßmus 
737e0a26dceSStephan Aßmus 	fLogOutItem = new BMenuItem(B_TRANSLATE("Log out"),
738e0a26dceSStephan Aßmus 		new BMessage(MSG_LOG_OUT));
739e0a26dceSStephan Aßmus 	fUserMenu->AddItem(fLogOutItem);
740e0a26dceSStephan Aßmus 
741e0a26dceSStephan Aßmus 	menuBar->AddItem(fUserMenu);
742e0a26dceSStephan Aßmus }
743e0a26dceSStephan Aßmus 
744e0a26dceSStephan Aßmus 
745e0a26dceSStephan Aßmus void
746f7c2983eSAxel Dörfler MainWindow::_RestoreUserName(const BMessage& settings)
747f7c2983eSAxel Dörfler {
748f7c2983eSAxel Dörfler 	BString username;
749f7c2983eSAxel Dörfler 	if (settings.FindString("username", &username) == B_OK
750f7c2983eSAxel Dörfler 		&& username.Length() > 0) {
751f7c2983eSAxel Dörfler 		fModel.SetUsername(username);
752f7c2983eSAxel Dörfler 	}
753f7c2983eSAxel Dörfler }
754f7c2983eSAxel Dörfler 
755f7c2983eSAxel Dörfler 
756f7c2983eSAxel Dörfler const char*
757f7c2983eSAxel Dörfler MainWindow::_WindowFrameName() const
758f7c2983eSAxel Dörfler {
759f7c2983eSAxel Dörfler 	if (fSinglePackageMode)
760f7c2983eSAxel Dörfler 		return "small window frame";
761f7c2983eSAxel Dörfler 
762f7c2983eSAxel Dörfler 	return "window frame";
763f7c2983eSAxel Dörfler }
764f7c2983eSAxel Dörfler 
765f7c2983eSAxel Dörfler 
766f7c2983eSAxel Dörfler void
767f7c2983eSAxel Dörfler MainWindow::_RestoreWindowFrame(const BMessage& settings)
768f7c2983eSAxel Dörfler {
769f7c2983eSAxel Dörfler 	BRect frame = Frame();
770f7c2983eSAxel Dörfler 
771f7c2983eSAxel Dörfler 	BRect windowFrame;
772f7c2983eSAxel Dörfler 	bool fromSettings = false;
773f7c2983eSAxel Dörfler 	if (settings.FindRect(_WindowFrameName(), &windowFrame) == B_OK) {
774f7c2983eSAxel Dörfler 		frame = windowFrame;
775f7c2983eSAxel Dörfler 		fromSettings = true;
776f7c2983eSAxel Dörfler 	} else if (!fSinglePackageMode) {
777f7c2983eSAxel Dörfler 		// Resize to occupy a certain screen size
778f7c2983eSAxel Dörfler 		BRect screenFrame = BScreen(this).Frame();
779f7c2983eSAxel Dörfler 		float width = frame.Width();
780f7c2983eSAxel Dörfler 		float height = frame.Height();
781f7c2983eSAxel Dörfler 		if (width < screenFrame.Width() * .666f
782f7c2983eSAxel Dörfler 			&& height < screenFrame.Height() * .666f) {
783f7c2983eSAxel Dörfler 			frame.bottom = frame.top + screenFrame.Height() * .666f;
784f7c2983eSAxel Dörfler 			frame.right = frame.left
785f7c2983eSAxel Dörfler 				+ std::min(screenFrame.Width() * .666f, height * 7 / 5);
786f7c2983eSAxel Dörfler 		}
787f7c2983eSAxel Dörfler 	}
788f7c2983eSAxel Dörfler 
789f7c2983eSAxel Dörfler 	MoveTo(frame.LeftTop());
790f7c2983eSAxel Dörfler 	ResizeTo(frame.Width(), frame.Height());
791f7c2983eSAxel Dörfler 
792f7c2983eSAxel Dörfler 	if (fromSettings)
7938e96ec34SAxel Dörfler 		MoveOnScreen();
794f7c2983eSAxel Dörfler 	else
795f7c2983eSAxel Dörfler 		CenterOnScreen();
796f7c2983eSAxel Dörfler }
797f7c2983eSAxel Dörfler 
798f7c2983eSAxel Dörfler 
799f7c2983eSAxel Dörfler void
80063975654SStephan Aßmus MainWindow::_InitWorkerThreads()
80163975654SStephan Aßmus {
80263975654SStephan Aßmus 	fPendingActionsSem = create_sem(0, "PendingPackageActions");
80363975654SStephan Aßmus 	if (fPendingActionsSem >= 0) {
80463975654SStephan Aßmus 		fPendingActionsWorker = spawn_thread(&_PackageActionWorker,
80563975654SStephan Aßmus 			"Planet Express", B_NORMAL_PRIORITY, this);
80663975654SStephan Aßmus 		if (fPendingActionsWorker >= 0)
80763975654SStephan Aßmus 			resume_thread(fPendingActionsWorker);
80809f82905SStephan Aßmus 	} else
80909f82905SStephan Aßmus 		fPendingActionsWorker = -1;
81063975654SStephan Aßmus 
81163975654SStephan Aßmus 	fPackageToPopulateSem = create_sem(0, "PopulatePackage");
81263975654SStephan Aßmus 	if (fPackageToPopulateSem >= 0) {
81363975654SStephan Aßmus 		fPopulatePackageWorker = spawn_thread(&_PopulatePackageWorker,
81463975654SStephan Aßmus 			"Package Populator", B_NORMAL_PRIORITY, this);
81563975654SStephan Aßmus 		if (fPopulatePackageWorker >= 0)
81663975654SStephan Aßmus 			resume_thread(fPopulatePackageWorker);
81709f82905SStephan Aßmus 	} else
81809f82905SStephan Aßmus 		fPopulatePackageWorker = -1;
81972fff6d3SJulian Harnath 
82072fff6d3SJulian Harnath 	fNewPackagesToShowSem = create_sem(0, "ShowPackages");
82172fff6d3SJulian Harnath 	fShowPackagesAcknowledgeSem = create_sem(0, "ShowPackagesAck");
82272fff6d3SJulian Harnath 	if (fNewPackagesToShowSem >= 0 && fShowPackagesAcknowledgeSem >= 0) {
82372fff6d3SJulian Harnath 		fShowPackagesWorker = spawn_thread(&_PackagesToShowWorker,
82472fff6d3SJulian Harnath 			"Good news everyone", B_NORMAL_PRIORITY, this);
82572fff6d3SJulian Harnath 		if (fShowPackagesWorker >= 0)
82672fff6d3SJulian Harnath 			resume_thread(fShowPackagesWorker);
82772fff6d3SJulian Harnath 	} else
82872fff6d3SJulian Harnath 		fShowPackagesWorker = -1;
82963975654SStephan Aßmus }
83063975654SStephan Aßmus 
83163975654SStephan Aßmus 
83263975654SStephan Aßmus void
83304c9d578SStephan Aßmus MainWindow::_AdoptModel()
83404c9d578SStephan Aßmus {
83504c9d578SStephan Aßmus 	fVisiblePackages = fModel.CreatePackageList();
83604c9d578SStephan Aßmus 
83772fff6d3SJulian Harnath 	{
83872fff6d3SJulian Harnath 		AutoLocker<BLocker> modelLocker(fModel.Lock());
83972fff6d3SJulian Harnath 		AutoLocker<BLocker> listLocker(fPackagesToShowListLock);
84072fff6d3SJulian Harnath 		fPackagesToShowList = fVisiblePackages;
84172fff6d3SJulian Harnath 		atomic_add(&fPackagesToShowListID, 1);
84272fff6d3SJulian Harnath 	}
84372fff6d3SJulian Harnath 
8444b930ccaSStephan Aßmus 	fFeaturedPackagesView->Clear();
84504c9d578SStephan Aßmus 	fPackageListView->Clear();
8464b930ccaSStephan Aßmus 
84772fff6d3SJulian Harnath 	release_sem(fNewPackagesToShowSem);
84804c9d578SStephan Aßmus 
84904c9d578SStephan Aßmus 	BAutolock locker(fModel.Lock());
850fdec4227SStephan Aßmus 	fShowAvailablePackagesItem->SetMarked(fModel.ShowAvailablePackages());
851fdec4227SStephan Aßmus 	fShowInstalledPackagesItem->SetMarked(fModel.ShowInstalledPackages());
852fdec4227SStephan Aßmus 	fShowSourcePackagesItem->SetMarked(fModel.ShowSourcePackages());
853fdec4227SStephan Aßmus 	fShowDevelopPackagesItem->SetMarked(fModel.ShowDevelopPackages());
854da651104SStephan Aßmus 
855b965ce70SHumdinger 	if (fModel.ShowFeaturedPackages())
856*e00a489bSAugustin Cavalier 		fListTabs->Select(0);
8574fade61fSStephan Aßmus 	else
858*e00a489bSAugustin Cavalier 		fListTabs->Select(1);
859b965ce70SHumdinger 
860b965ce70SHumdinger 	fFilterView->AdoptModel(fModel);
86104c9d578SStephan Aßmus }
86204c9d578SStephan Aßmus 
86304c9d578SStephan Aßmus 
86404c9d578SStephan Aßmus void
86504c9d578SStephan Aßmus MainWindow::_AdoptPackage(const PackageInfoRef& package)
86604c9d578SStephan Aßmus {
86775ba9dbfSStephan Aßmus 	{
86875ba9dbfSStephan Aßmus 		BAutolock locker(fModel.Lock());
86904c9d578SStephan Aßmus 		fPackageInfoView->SetPackage(package);
8701986ab9fSStephan Aßmus 
871664372abSStephan Aßmus 		if (fFeaturedPackagesView != NULL)
872664372abSStephan Aßmus 			fFeaturedPackagesView->SelectPackage(package);
8731986ab9fSStephan Aßmus 		if (fPackageListView != NULL)
8741986ab9fSStephan Aßmus 			fPackageListView->SelectPackage(package);
87575ba9dbfSStephan Aßmus 	}
87604c9d578SStephan Aßmus 
877a9edb9bfSAndrew Lindesay 	_PopulatePackageAsync(false);
87804c9d578SStephan Aßmus }
87904c9d578SStephan Aßmus 
88004c9d578SStephan Aßmus 
88104c9d578SStephan Aßmus void
88204c9d578SStephan Aßmus MainWindow::_ClearPackage()
88304c9d578SStephan Aßmus {
88404c9d578SStephan Aßmus 	fPackageInfoView->Clear();
88504c9d578SStephan Aßmus }
88604c9d578SStephan Aßmus 
88704c9d578SStephan Aßmus 
88804c9d578SStephan Aßmus void
88904c9d578SStephan Aßmus MainWindow::_RefreshRepositories(bool force)
89004c9d578SStephan Aßmus {
891448f707cSStephan Aßmus 	if (fSinglePackageMode)
892448f707cSStephan Aßmus 		return;
893448f707cSStephan Aßmus 
89404c9d578SStephan Aßmus 	BPackageRoster roster;
89504c9d578SStephan Aßmus 	BStringList repositoryNames;
89604c9d578SStephan Aßmus 
89704c9d578SStephan Aßmus 	status_t result = roster.GetRepositoryNames(repositoryNames);
89804c9d578SStephan Aßmus 	if (result != B_OK)
89904c9d578SStephan Aßmus 		return;
90004c9d578SStephan Aßmus 
90104c9d578SStephan Aßmus 	DecisionProvider decisionProvider;
90204c9d578SStephan Aßmus 	JobStateListener listener;
90304c9d578SStephan Aßmus 	BContext context(decisionProvider, listener);
90404c9d578SStephan Aßmus 
90504c9d578SStephan Aßmus 	BRepositoryCache cache;
90604c9d578SStephan Aßmus 	for (int32 i = 0; i < repositoryNames.CountStrings(); ++i) {
90704c9d578SStephan Aßmus 		const BString& repoName = repositoryNames.StringAt(i);
90804c9d578SStephan Aßmus 		BRepositoryConfig repoConfig;
90904c9d578SStephan Aßmus 		result = roster.GetRepositoryConfig(repoName, &repoConfig);
91004c9d578SStephan Aßmus 		if (result != B_OK) {
91104c9d578SStephan Aßmus 			// TODO: notify user
91204c9d578SStephan Aßmus 			continue;
91304c9d578SStephan Aßmus 		}
91404c9d578SStephan Aßmus 
91504c9d578SStephan Aßmus 		if (roster.GetRepositoryCache(repoName, &cache) != B_OK || force) {
91604c9d578SStephan Aßmus 			try {
91704c9d578SStephan Aßmus 				BRefreshRepositoryRequest refreshRequest(context, repoConfig);
91804c9d578SStephan Aßmus 
91904c9d578SStephan Aßmus 				result = refreshRequest.Process();
92004c9d578SStephan Aßmus 			} catch (BFatalErrorException ex) {
92104c9d578SStephan Aßmus 				BString message(B_TRANSLATE("An error occurred while "
92204c9d578SStephan Aßmus 					"refreshing the repository: %error% (%details%)"));
92304c9d578SStephan Aßmus  				message.ReplaceFirst("%error%", ex.Message());
92404c9d578SStephan Aßmus 				message.ReplaceFirst("%details%", ex.Details());
92504c9d578SStephan Aßmus 				_NotifyUser("Error", message.String());
92604c9d578SStephan Aßmus 			} catch (BException ex) {
92704c9d578SStephan Aßmus 				BString message(B_TRANSLATE("An error occurred while "
92804c9d578SStephan Aßmus 					"refreshing the repository: %error%"));
92904c9d578SStephan Aßmus 				message.ReplaceFirst("%error%", ex.Message());
93004c9d578SStephan Aßmus 				_NotifyUser("Error", message.String());
93104c9d578SStephan Aßmus 			}
93204c9d578SStephan Aßmus 		}
93304c9d578SStephan Aßmus 	}
93404c9d578SStephan Aßmus }
93504c9d578SStephan Aßmus 
93604c9d578SStephan Aßmus 
93704c9d578SStephan Aßmus void
9387b2c59b9SStephan Aßmus MainWindow::_RefreshPackageList(bool force)
93904c9d578SStephan Aßmus {
940448f707cSStephan Aßmus 	if (fSinglePackageMode)
941448f707cSStephan Aßmus 		return;
942448f707cSStephan Aßmus 
9436d18e980SAndrew Lindesay 	if (Logger::IsDebugEnabled())
9446d18e980SAndrew Lindesay 		printf("will refresh the package list\n");
9456d18e980SAndrew Lindesay 
94604c9d578SStephan Aßmus 	BPackageRoster roster;
94704c9d578SStephan Aßmus 	BStringList repositoryNames;
94804c9d578SStephan Aßmus 
94904c9d578SStephan Aßmus 	status_t result = roster.GetRepositoryNames(repositoryNames);
95004c9d578SStephan Aßmus 	if (result != B_OK)
95104c9d578SStephan Aßmus 		return;
95204c9d578SStephan Aßmus 
9533b17d8ddSAndrew Lindesay 	std::vector<DepotInfo> depots(repositoryNames.CountStrings());
95404c9d578SStephan Aßmus 	for (int32 i = 0; i < repositoryNames.CountStrings(); i++) {
95504c9d578SStephan Aßmus 		const BString& repoName = repositoryNames.StringAt(i);
956ebb1a01cSAndrew Lindesay 		DepotInfo depotInfo = DepotInfo(repoName);
957ebb1a01cSAndrew Lindesay 
958ebb1a01cSAndrew Lindesay 		BRepositoryConfig repoConfig;
959ebb1a01cSAndrew Lindesay 		status_t getRepositoryConfigStatus = roster.GetRepositoryConfig(
960ebb1a01cSAndrew Lindesay 			repoName, &repoConfig);
961ebb1a01cSAndrew Lindesay 
962ebb1a01cSAndrew Lindesay 		if (getRepositoryConfigStatus == B_OK) {
963ebb1a01cSAndrew Lindesay 			depotInfo.SetBaseURL(repoConfig.BaseURL());
9643b17d8ddSAndrew Lindesay 			depotInfo.SetURL(repoConfig.URL());
9653b17d8ddSAndrew Lindesay 
9663b17d8ddSAndrew Lindesay 			if (Logger::IsDebugEnabled()) {
9673b17d8ddSAndrew Lindesay 				printf("local repository [%s] info;\n"
9683b17d8ddSAndrew Lindesay 					" * base url [%s]\n"
9693b17d8ddSAndrew Lindesay 					" * url [%s]\n",
9703b17d8ddSAndrew Lindesay 					repoName.String(), repoConfig.BaseURL().String(),
9713b17d8ddSAndrew Lindesay 					repoConfig.URL().String());
9723b17d8ddSAndrew Lindesay 			}
973ebb1a01cSAndrew Lindesay 		} else {
974ebb1a01cSAndrew Lindesay 			printf("unable to obtain the repository config for local "
975ebb1a01cSAndrew Lindesay 				"repository '%s'; %s\n",
976ebb1a01cSAndrew Lindesay 				repoName.String(), strerror(getRepositoryConfigStatus));
977ebb1a01cSAndrew Lindesay 		}
978ebb1a01cSAndrew Lindesay 
9793b17d8ddSAndrew Lindesay 		depots[i] = depotInfo;
98004c9d578SStephan Aßmus 	}
98104c9d578SStephan Aßmus 
98204c9d578SStephan Aßmus 	PackageManager manager(B_PACKAGE_INSTALLATION_LOCATION_HOME);
98304c9d578SStephan Aßmus 	try {
98404c9d578SStephan Aßmus 		manager.Init(PackageManager::B_ADD_INSTALLED_REPOSITORIES
98504c9d578SStephan Aßmus 			| PackageManager::B_ADD_REMOTE_REPOSITORIES);
98604c9d578SStephan Aßmus 	} catch (BException ex) {
98704c9d578SStephan Aßmus 		BString message(B_TRANSLATE("An error occurred while "
98804c9d578SStephan Aßmus 			"initializing the package manager: %message%"));
98904c9d578SStephan Aßmus 		message.ReplaceFirst("%message%", ex.Message());
99004c9d578SStephan Aßmus 		_NotifyUser("Error", message.String());
99104c9d578SStephan Aßmus 		return;
99204c9d578SStephan Aßmus 	}
99304c9d578SStephan Aßmus 
99404c9d578SStephan Aßmus 	BObjectList<BSolverPackage> packages;
99504c9d578SStephan Aßmus 	result = manager.Solver()->FindPackages("",
99604c9d578SStephan Aßmus 		BSolver::B_FIND_CASE_INSENSITIVE | BSolver::B_FIND_IN_NAME
99704c9d578SStephan Aßmus 			| BSolver::B_FIND_IN_SUMMARY | BSolver::B_FIND_IN_DESCRIPTION
99804c9d578SStephan Aßmus 			| BSolver::B_FIND_IN_PROVIDES,
99904c9d578SStephan Aßmus 		packages);
100004c9d578SStephan Aßmus 	if (result != B_OK) {
100104c9d578SStephan Aßmus 		BString message(B_TRANSLATE("An error occurred while "
100204c9d578SStephan Aßmus 			"obtaining the package list: %message%"));
100304c9d578SStephan Aßmus 		message.ReplaceFirst("%message%", strerror(result));
100404c9d578SStephan Aßmus 		_NotifyUser("Error", message.String());
100504c9d578SStephan Aßmus 		return;
100604c9d578SStephan Aßmus 	}
100704c9d578SStephan Aßmus 
100804c9d578SStephan Aßmus 	if (packages.IsEmpty())
100904c9d578SStephan Aßmus 		return;
101004c9d578SStephan Aßmus 
101104c9d578SStephan Aßmus 	PackageInfoMap foundPackages;
101204c9d578SStephan Aßmus 		// if a given package is installed locally, we will potentially
101304c9d578SStephan Aßmus 		// get back multiple entries, one for each local installation
101404c9d578SStephan Aßmus 		// location, and one for each remote repository the package
101504c9d578SStephan Aßmus 		// is available in. The above map is used to ensure that in such
101604c9d578SStephan Aßmus 		// cases we consolidate the information, rather than displaying
101704c9d578SStephan Aßmus 		// duplicates
101804c9d578SStephan Aßmus 	PackageInfoMap remotePackages;
101904c9d578SStephan Aßmus 		// any package that we find in a remote repository goes in this map.
102004c9d578SStephan Aßmus 		// this is later used to discern which packages came from a local
102104c9d578SStephan Aßmus 		// installation only, as those must be handled a bit differently
102204c9d578SStephan Aßmus 		// upon uninstallation, since we'd no longer be able to pull them
102304c9d578SStephan Aßmus 		// down remotely.
102404c9d578SStephan Aßmus 	BStringList systemFlaggedPackages;
102504c9d578SStephan Aßmus 		// any packages flagged as a system package are added to this list.
102604c9d578SStephan Aßmus 		// such packages cannot be uninstalled, nor can any of their deps.
102704c9d578SStephan Aßmus 	PackageInfoMap systemInstalledPackages;
102804c9d578SStephan Aßmus 		// any packages installed in system are added to this list.
102904c9d578SStephan Aßmus 		// This is later used for dependency resolution of the actual
103004c9d578SStephan Aßmus 		// system packages in order to compute the list of protected
103104c9d578SStephan Aßmus 		// dependencies indicated above.
103204c9d578SStephan Aßmus 
103304c9d578SStephan Aßmus 	for (int32 i = 0; i < packages.CountItems(); i++) {
103404c9d578SStephan Aßmus 		BSolverPackage* package = packages.ItemAt(i);
103504c9d578SStephan Aßmus 		const BPackageInfo& repoPackageInfo = package->Info();
1036ebb1a01cSAndrew Lindesay 		const BString repositoryName = package->Repository()->Name();
103704c9d578SStephan Aßmus 		PackageInfoRef modelInfo;
103804c9d578SStephan Aßmus 		PackageInfoMap::iterator it = foundPackages.find(
103904c9d578SStephan Aßmus 			repoPackageInfo.Name());
104004c9d578SStephan Aßmus 		if (it != foundPackages.end())
104104c9d578SStephan Aßmus 			modelInfo.SetTo(it->second);
104204c9d578SStephan Aßmus 		else {
104304c9d578SStephan Aßmus 			// Add new package info
10446d519fd1SStephan Aßmus 			modelInfo.SetTo(new(std::nothrow) PackageInfo(repoPackageInfo),
104504c9d578SStephan Aßmus 				true);
104604c9d578SStephan Aßmus 
104704c9d578SStephan Aßmus 			if (modelInfo.Get() == NULL)
104804c9d578SStephan Aßmus 				return;
104904c9d578SStephan Aßmus 
105004c9d578SStephan Aßmus 			foundPackages[repoPackageInfo.Name()] = modelInfo;
105104c9d578SStephan Aßmus 		}
105204c9d578SStephan Aßmus 
10536ab878c0SAndrew Lindesay 		// The package list here considers those packages that are installed
10546ab878c0SAndrew Lindesay 		// in the system as well as those that exist in remote repositories.
10556ab878c0SAndrew Lindesay 		// It is better if the 'depot name' is from the remote repository
10566ab878c0SAndrew Lindesay 		// because then it will be possible to perform a rating on it later.
10576ab878c0SAndrew Lindesay 
10586ab878c0SAndrew Lindesay 		if (modelInfo->DepotName().IsEmpty()
10596ab878c0SAndrew Lindesay 			|| modelInfo->DepotName() == REPOSITORY_NAME_SYSTEM
10606ab878c0SAndrew Lindesay 			|| modelInfo->DepotName() == REPOSITORY_NAME_INSTALLED) {
10616ab878c0SAndrew Lindesay 			modelInfo->SetDepotName(repositoryName);
10626ab878c0SAndrew Lindesay 		}
10636ab878c0SAndrew Lindesay 
106404c9d578SStephan Aßmus 		modelInfo->AddListener(this);
106504c9d578SStephan Aßmus 
106604c9d578SStephan Aßmus 		BSolverRepository* repository = package->Repository();
10673b17d8ddSAndrew Lindesay 		BPackageManager::RemoteRepository* remoteRepository =
10683b17d8ddSAndrew Lindesay 			dynamic_cast<BPackageManager::RemoteRepository*>(repository);
10693b17d8ddSAndrew Lindesay 
10703b17d8ddSAndrew Lindesay 		if (remoteRepository != NULL) {
10713b17d8ddSAndrew Lindesay 
10723b17d8ddSAndrew Lindesay 			std::vector<DepotInfo>::iterator it;
10733b17d8ddSAndrew Lindesay 
10743b17d8ddSAndrew Lindesay 			for (it = depots.begin(); it != depots.end(); it++) {
10753b17d8ddSAndrew Lindesay 				if (RepositoryUrlUtils::EqualsOnUrlOrBaseUrl(
10763b17d8ddSAndrew Lindesay 					it->URL(), remoteRepository->Config().URL(),
10773b17d8ddSAndrew Lindesay 					it->BaseURL(), remoteRepository->Config().BaseURL())) {
10783b17d8ddSAndrew Lindesay 					break;
10793b17d8ddSAndrew Lindesay 				}
10803b17d8ddSAndrew Lindesay 			}
10813b17d8ddSAndrew Lindesay 
10823b17d8ddSAndrew Lindesay 			if (it == depots.end()) {
1083d13c3d89SAndrew Lindesay 				if (Logger::IsDebugEnabled()) {
10843b17d8ddSAndrew Lindesay 					printf("pkg [%s] repository [%s] not recognized"
10853b17d8ddSAndrew Lindesay 						" --> ignored\n",
1086d13c3d89SAndrew Lindesay 						modelInfo->Name().String(), repositoryName.String());
1087d13c3d89SAndrew Lindesay 				}
1088d13c3d89SAndrew Lindesay 			} else {
10893b17d8ddSAndrew Lindesay 				it->AddPackage(modelInfo);
10903b17d8ddSAndrew Lindesay 
10913b17d8ddSAndrew Lindesay 				if (Logger::IsTraceEnabled()) {
10923b17d8ddSAndrew Lindesay 					printf("pkg [%s] assigned to [%s]\n",
10933b17d8ddSAndrew Lindesay 						modelInfo->Name().String(), repositoryName.String());
10943b17d8ddSAndrew Lindesay 				}
1095d13c3d89SAndrew Lindesay 			}
1096d13c3d89SAndrew Lindesay 
109772992391SStephan Aßmus 			remotePackages[modelInfo->Name()] = modelInfo;
109804c9d578SStephan Aßmus 		} else {
109904c9d578SStephan Aßmus 			if (repository == static_cast<const BSolverRepository*>(
110004c9d578SStephan Aßmus 					manager.SystemRepository())) {
110104c9d578SStephan Aßmus 				modelInfo->AddInstallationLocation(
110204c9d578SStephan Aßmus 					B_PACKAGE_INSTALLATION_LOCATION_SYSTEM);
110304c9d578SStephan Aßmus 				if (!modelInfo->IsSystemPackage()) {
110404c9d578SStephan Aßmus 					systemInstalledPackages[repoPackageInfo.FileName()]
110504c9d578SStephan Aßmus 						= modelInfo;
110604c9d578SStephan Aßmus 				}
110704c9d578SStephan Aßmus 			} else if (repository == static_cast<const BSolverRepository*>(
110804c9d578SStephan Aßmus 					manager.HomeRepository())) {
110904c9d578SStephan Aßmus 				modelInfo->AddInstallationLocation(
111004c9d578SStephan Aßmus 					B_PACKAGE_INSTALLATION_LOCATION_HOME);
111104c9d578SStephan Aßmus 			}
111204c9d578SStephan Aßmus 		}
111304c9d578SStephan Aßmus 
111404c9d578SStephan Aßmus 		if (modelInfo->IsSystemPackage())
111504c9d578SStephan Aßmus 			systemFlaggedPackages.Add(repoPackageInfo.FileName());
111604c9d578SStephan Aßmus 	}
111704c9d578SStephan Aßmus 
11187b2c59b9SStephan Aßmus 	bool wasEmpty = fModel.Depots().IsEmpty();
11197b2c59b9SStephan Aßmus 	if (force || wasEmpty)
11203094fef3SAndrew Lindesay 		fBulkLoadStateMachine.Stop();
112104c9d578SStephan Aßmus 
11226b147523SStephan Aßmus 	BAutolock lock(fModel.Lock());
11237b2c59b9SStephan Aßmus 
11247b2c59b9SStephan Aßmus 	if (force)
112504c9d578SStephan Aßmus 		fModel.Clear();
112604c9d578SStephan Aßmus 
112704c9d578SStephan Aßmus 	// filter remote packages from the found list
112804c9d578SStephan Aßmus 	// any packages remaining will be locally installed packages
112904c9d578SStephan Aßmus 	// that weren't acquired from a repository
113004c9d578SStephan Aßmus 	for (PackageInfoMap::iterator it = remotePackages.begin();
113104c9d578SStephan Aßmus 			it != remotePackages.end(); it++) {
113204c9d578SStephan Aßmus 		foundPackages.erase(it->first);
113304c9d578SStephan Aßmus 	}
113404c9d578SStephan Aßmus 
113504c9d578SStephan Aßmus 	if (!foundPackages.empty()) {
113604c9d578SStephan Aßmus 		BString repoName = B_TRANSLATE("Local");
11373b17d8ddSAndrew Lindesay 		depots.push_back(DepotInfo(repoName));
11383b17d8ddSAndrew Lindesay 
113904c9d578SStephan Aßmus 		for (PackageInfoMap::iterator it = foundPackages.begin();
114004c9d578SStephan Aßmus 				it != foundPackages.end(); ++it) {
11413b17d8ddSAndrew Lindesay 			depots.back().AddPackage(it->second);
114204c9d578SStephan Aßmus 		}
114304c9d578SStephan Aßmus 	}
114404c9d578SStephan Aßmus 
11453b17d8ddSAndrew Lindesay 	{
11463b17d8ddSAndrew Lindesay 		std::vector<DepotInfo>::iterator it;
11473b17d8ddSAndrew Lindesay 
11483b17d8ddSAndrew Lindesay 		for (it = depots.begin(); it != depots.end(); it++) {
11493b17d8ddSAndrew Lindesay 			if (fModel.HasDepot(it->Name()))
11503b17d8ddSAndrew Lindesay 				fModel.SyncDepot(*it);
11517b2c59b9SStephan Aßmus 			else
11523b17d8ddSAndrew Lindesay 				fModel.AddDepot(*it);
11533b17d8ddSAndrew Lindesay 		}
115404c9d578SStephan Aßmus 	}
115504c9d578SStephan Aßmus 
115604c9d578SStephan Aßmus 	// start retrieving package icons and average ratings
11573094fef3SAndrew Lindesay 	if (force || wasEmpty) {
11583094fef3SAndrew Lindesay 			fBulkLoadStateMachine.Start();
11593094fef3SAndrew Lindesay 	}
116004c9d578SStephan Aßmus 
116104c9d578SStephan Aßmus 	// compute the OS package dependencies
116204c9d578SStephan Aßmus 	try {
116304c9d578SStephan Aßmus 		// create the solver
116404c9d578SStephan Aßmus 		BSolver* solver;
116504c9d578SStephan Aßmus 		status_t error = BSolver::Create(solver);
116604c9d578SStephan Aßmus 		if (error != B_OK)
116704c9d578SStephan Aßmus 			throw BFatalErrorException(error, "Failed to create solver.");
116804c9d578SStephan Aßmus 
116904c9d578SStephan Aßmus 		ObjectDeleter<BSolver> solverDeleter(solver);
117004c9d578SStephan Aßmus 		BPath systemPath;
117104c9d578SStephan Aßmus 		error = find_directory(B_SYSTEM_PACKAGES_DIRECTORY, &systemPath);
117204c9d578SStephan Aßmus 		if (error != B_OK) {
117304c9d578SStephan Aßmus 			throw BFatalErrorException(error,
117404c9d578SStephan Aßmus 				"Unable to retrieve system packages directory.");
117504c9d578SStephan Aßmus 		}
117604c9d578SStephan Aßmus 
117704c9d578SStephan Aßmus 		// add the "installed" repository with the given packages
117804c9d578SStephan Aßmus 		BSolverRepository installedRepository;
117904c9d578SStephan Aßmus 		{
118004c9d578SStephan Aßmus 			BRepositoryBuilder installedRepositoryBuilder(installedRepository,
11816ab878c0SAndrew Lindesay 				REPOSITORY_NAME_INSTALLED);
118204c9d578SStephan Aßmus 			for (int32 i = 0; i < systemFlaggedPackages.CountStrings(); i++) {
118304c9d578SStephan Aßmus 				BPath packagePath(systemPath);
118404c9d578SStephan Aßmus 				packagePath.Append(systemFlaggedPackages.StringAt(i));
118504c9d578SStephan Aßmus 				installedRepositoryBuilder.AddPackage(packagePath.Path());
118604c9d578SStephan Aßmus 			}
118704c9d578SStephan Aßmus 			installedRepositoryBuilder.AddToSolver(solver, true);
118804c9d578SStephan Aßmus 		}
118904c9d578SStephan Aßmus 
119004c9d578SStephan Aßmus 		// add system repository
119104c9d578SStephan Aßmus 		BSolverRepository systemRepository;
119204c9d578SStephan Aßmus 		{
119304c9d578SStephan Aßmus 			BRepositoryBuilder systemRepositoryBuilder(systemRepository,
11946ab878c0SAndrew Lindesay 				REPOSITORY_NAME_SYSTEM);
119504c9d578SStephan Aßmus 			for (PackageInfoMap::iterator it = systemInstalledPackages.begin();
119604c9d578SStephan Aßmus 					it != systemInstalledPackages.end(); it++) {
119704c9d578SStephan Aßmus 				BPath packagePath(systemPath);
119804c9d578SStephan Aßmus 				packagePath.Append(it->first);
119904c9d578SStephan Aßmus 				systemRepositoryBuilder.AddPackage(packagePath.Path());
120004c9d578SStephan Aßmus 			}
120104c9d578SStephan Aßmus 			systemRepositoryBuilder.AddToSolver(solver, false);
120204c9d578SStephan Aßmus 		}
120304c9d578SStephan Aßmus 
120404c9d578SStephan Aßmus 		// solve
120504c9d578SStephan Aßmus 		error = solver->VerifyInstallation();
120604c9d578SStephan Aßmus 		if (error != B_OK) {
120704c9d578SStephan Aßmus 			throw BFatalErrorException(error, "Failed to compute packages to "
120804c9d578SStephan Aßmus 				"install.");
120904c9d578SStephan Aßmus 		}
121004c9d578SStephan Aßmus 
121104c9d578SStephan Aßmus 		BSolverResult solverResult;
121204c9d578SStephan Aßmus 		error = solver->GetResult(solverResult);
121304c9d578SStephan Aßmus 		if (error != B_OK) {
121404c9d578SStephan Aßmus 			throw BFatalErrorException(error, "Failed to retrieve system "
121504c9d578SStephan Aßmus 				"package dependency list.");
121604c9d578SStephan Aßmus 		}
121704c9d578SStephan Aßmus 
121804c9d578SStephan Aßmus 		for (int32 i = 0; const BSolverResultElement* element
121904c9d578SStephan Aßmus 				= solverResult.ElementAt(i); i++) {
122004c9d578SStephan Aßmus 			BSolverPackage* package = element->Package();
122104c9d578SStephan Aßmus 			if (element->Type() == BSolverResultElement::B_TYPE_INSTALL) {
122204c9d578SStephan Aßmus 				PackageInfoMap::iterator it = systemInstalledPackages.find(
122304c9d578SStephan Aßmus 					package->Info().FileName());
122404c9d578SStephan Aßmus 				if (it != systemInstalledPackages.end())
122504c9d578SStephan Aßmus 					it->second->SetSystemDependency(true);
122604c9d578SStephan Aßmus 			}
122704c9d578SStephan Aßmus 		}
122804c9d578SStephan Aßmus 	} catch (BFatalErrorException ex) {
122904c9d578SStephan Aßmus 		printf("Fatal exception occurred while resolving system dependencies: "
123004c9d578SStephan Aßmus 			"%s, details: %s\n", strerror(ex.Error()), ex.Details().String());
123104c9d578SStephan Aßmus 	} catch (BNothingToDoException) {
123204c9d578SStephan Aßmus 		// do nothing
123304c9d578SStephan Aßmus 	} catch (BException ex) {
123404c9d578SStephan Aßmus 		printf("Exception occurred while resolving system dependencies: %s\n",
123504c9d578SStephan Aßmus 			ex.Message().String());
123604c9d578SStephan Aßmus 	} catch (...) {
123704c9d578SStephan Aßmus 		printf("Unknown exception occurred while resolving system "
123804c9d578SStephan Aßmus 			"dependencies.\n");
123904c9d578SStephan Aßmus 	}
12406d18e980SAndrew Lindesay 
12416d18e980SAndrew Lindesay 	if (Logger::IsDebugEnabled())
12426d18e980SAndrew Lindesay 		printf("did refresh the package list\n");
124304c9d578SStephan Aßmus }
124404c9d578SStephan Aßmus 
124504c9d578SStephan Aßmus 
124604c9d578SStephan Aßmus void
124704c9d578SStephan Aßmus MainWindow::_StartRefreshWorker(bool force)
124804c9d578SStephan Aßmus {
124904c9d578SStephan Aßmus 	if (fModelWorker != B_BAD_THREAD_ID)
125004c9d578SStephan Aßmus 		return;
125104c9d578SStephan Aßmus 
125204c9d578SStephan Aßmus 	RefreshWorkerParameters* parameters = new(std::nothrow)
125304c9d578SStephan Aßmus 		RefreshWorkerParameters(this, force);
125404c9d578SStephan Aßmus 	if (parameters == NULL)
125504c9d578SStephan Aßmus 		return;
125604c9d578SStephan Aßmus 
1257bc622f6bSHumdinger 	fWorkStatusView->SetBusy(B_TRANSLATE("Refreshing" B_UTF8_ELLIPSIS));
1258125d42d9SJulian Harnath 
125904c9d578SStephan Aßmus 	ObjectDeleter<RefreshWorkerParameters> deleter(parameters);
126004c9d578SStephan Aßmus 	fModelWorker = spawn_thread(&_RefreshModelThreadWorker, "model loader",
126104c9d578SStephan Aßmus 		B_LOW_PRIORITY, parameters);
126204c9d578SStephan Aßmus 
126304c9d578SStephan Aßmus 	if (fModelWorker > 0) {
126404c9d578SStephan Aßmus 		deleter.Detach();
126504c9d578SStephan Aßmus 		resume_thread(fModelWorker);
126604c9d578SStephan Aßmus 	}
126704c9d578SStephan Aßmus }
126804c9d578SStephan Aßmus 
126904c9d578SStephan Aßmus 
127004c9d578SStephan Aßmus status_t
127104c9d578SStephan Aßmus MainWindow::_RefreshModelThreadWorker(void* arg)
127204c9d578SStephan Aßmus {
127304c9d578SStephan Aßmus 	RefreshWorkerParameters* parameters
127404c9d578SStephan Aßmus 		= reinterpret_cast<RefreshWorkerParameters*>(arg);
127504c9d578SStephan Aßmus 	MainWindow* mainWindow = parameters->window;
127604c9d578SStephan Aßmus 	ObjectDeleter<RefreshWorkerParameters> deleter(parameters);
127704c9d578SStephan Aßmus 
127804c9d578SStephan Aßmus 	BMessenger messenger(mainWindow);
127904c9d578SStephan Aßmus 
128004c9d578SStephan Aßmus 	mainWindow->_RefreshRepositories(parameters->forceRefresh);
128104c9d578SStephan Aßmus 
128204c9d578SStephan Aßmus 	if (mainWindow->fTerminating)
128304c9d578SStephan Aßmus 		return B_OK;
128404c9d578SStephan Aßmus 
12857b2c59b9SStephan Aßmus 	mainWindow->_RefreshPackageList(parameters->forceRefresh);
128604c9d578SStephan Aßmus 
128704c9d578SStephan Aßmus 	messenger.SendMessage(MSG_MODEL_WORKER_DONE);
128804c9d578SStephan Aßmus 
128904c9d578SStephan Aßmus 	return B_OK;
129004c9d578SStephan Aßmus }
129104c9d578SStephan Aßmus 
129204c9d578SStephan Aßmus 
129304c9d578SStephan Aßmus status_t
129404c9d578SStephan Aßmus MainWindow::_PackageActionWorker(void* arg)
129504c9d578SStephan Aßmus {
129604c9d578SStephan Aßmus 	MainWindow* window = reinterpret_cast<MainWindow*>(arg);
129704c9d578SStephan Aßmus 
129804c9d578SStephan Aßmus 	while (acquire_sem(window->fPendingActionsSem) == B_OK) {
129904c9d578SStephan Aßmus 		PackageActionRef ref;
130004c9d578SStephan Aßmus 		{
130104c9d578SStephan Aßmus 			AutoLocker<BLocker> lock(&window->fPendingActionsLock);
130204c9d578SStephan Aßmus 			ref = window->fPendingActions.ItemAt(0);
130304c9d578SStephan Aßmus 			if (ref.Get() == NULL)
130404c9d578SStephan Aßmus 				break;
130504c9d578SStephan Aßmus 			window->fPendingActions.Remove(0);
130604c9d578SStephan Aßmus 		}
130704c9d578SStephan Aßmus 
1308125d42d9SJulian Harnath 		BMessenger messenger(window);
1309125d42d9SJulian Harnath 		BMessage busyMessage(MSG_PACKAGE_WORKER_BUSY);
1310125d42d9SJulian Harnath 		BString text(ref->Label());
1311bc622f6bSHumdinger 		text << B_UTF8_ELLIPSIS;
1312125d42d9SJulian Harnath 		busyMessage.AddString("reason", text);
1313125d42d9SJulian Harnath 
1314125d42d9SJulian Harnath 		messenger.SendMessage(&busyMessage);
131504c9d578SStephan Aßmus 		ref->Perform();
1316125d42d9SJulian Harnath 		messenger.SendMessage(MSG_PACKAGE_WORKER_IDLE);
131704c9d578SStephan Aßmus 	}
131804c9d578SStephan Aßmus 
131904c9d578SStephan Aßmus 	return 0;
132004c9d578SStephan Aßmus }
132104c9d578SStephan Aßmus 
132204c9d578SStephan Aßmus 
1323a9edb9bfSAndrew Lindesay /*! This method will cause the package to have its data refreshed from
1324a9edb9bfSAndrew Lindesay     the server application.  The refresh happens in the background; this method
1325a9edb9bfSAndrew Lindesay     is asynchronous.
1326a9edb9bfSAndrew Lindesay */
1327a9edb9bfSAndrew Lindesay 
1328a9edb9bfSAndrew Lindesay void
1329a9edb9bfSAndrew Lindesay MainWindow::_PopulatePackageAsync(bool forcePopulate)
1330a9edb9bfSAndrew Lindesay {
1331a9edb9bfSAndrew Lindesay 		// Trigger asynchronous package population from the web-app
1332a9edb9bfSAndrew Lindesay 	{
1333a9edb9bfSAndrew Lindesay 		AutoLocker<BLocker> lock(&fPackageToPopulateLock);
1334a9edb9bfSAndrew Lindesay 		fPackageToPopulate = fPackageInfoView->Package();
1335a9edb9bfSAndrew Lindesay 		fForcePopulatePackage = forcePopulate;
1336a9edb9bfSAndrew Lindesay 	}
1337a9edb9bfSAndrew Lindesay 	release_sem_etc(fPackageToPopulateSem, 1, 0);
1338a9edb9bfSAndrew Lindesay 
1339a9edb9bfSAndrew Lindesay 	if (Logger::IsDebugEnabled()) {
1340a9edb9bfSAndrew Lindesay 		printf("pkg [%s] will be updated from the server.\n",
1341a9edb9bfSAndrew Lindesay 			fPackageToPopulate->Name().String());
1342a9edb9bfSAndrew Lindesay 	}
1343a9edb9bfSAndrew Lindesay }
1344a9edb9bfSAndrew Lindesay 
1345a9edb9bfSAndrew Lindesay 
1346a9edb9bfSAndrew Lindesay /*! This method will run in the background.  The thread will block until there
1347a9edb9bfSAndrew Lindesay     is a package to be updated.  When the thread unblocks, it will update the
1348a9edb9bfSAndrew Lindesay     package with information from the server.
1349a9edb9bfSAndrew Lindesay */
1350a9edb9bfSAndrew Lindesay 
135104c9d578SStephan Aßmus status_t
135204c9d578SStephan Aßmus MainWindow::_PopulatePackageWorker(void* arg)
135304c9d578SStephan Aßmus {
135404c9d578SStephan Aßmus 	MainWindow* window = reinterpret_cast<MainWindow*>(arg);
135504c9d578SStephan Aßmus 
135604c9d578SStephan Aßmus 	while (acquire_sem(window->fPackageToPopulateSem) == B_OK) {
135704c9d578SStephan Aßmus 		PackageInfoRef package;
1358a9edb9bfSAndrew Lindesay 		bool force;
135904c9d578SStephan Aßmus 		{
136004c9d578SStephan Aßmus 			AutoLocker<BLocker> lock(&window->fPackageToPopulateLock);
136104c9d578SStephan Aßmus 			package = window->fPackageToPopulate;
1362a9edb9bfSAndrew Lindesay 			force = window->fForcePopulatePackage;
136304c9d578SStephan Aßmus 		}
136404c9d578SStephan Aßmus 
136504c9d578SStephan Aßmus 		if (package.Get() != NULL) {
1366a9edb9bfSAndrew Lindesay 			uint32 populateFlags = Model::POPULATE_USER_RATINGS
1367a9edb9bfSAndrew Lindesay 				| Model::POPULATE_SCREEN_SHOTS
1368a9edb9bfSAndrew Lindesay 				| Model::POPULATE_CHANGELOG;
1369a9edb9bfSAndrew Lindesay 
1370a9edb9bfSAndrew Lindesay 			if (force)
1371a9edb9bfSAndrew Lindesay 				populateFlags |= Model::POPULATE_FORCE;
1372a9edb9bfSAndrew Lindesay 
1373a9edb9bfSAndrew Lindesay 			window->fModel.PopulatePackage(package, populateFlags);
1374a9edb9bfSAndrew Lindesay 
1375a9edb9bfSAndrew Lindesay 			if (Logger::IsDebugEnabled()) {
1376a9edb9bfSAndrew Lindesay 				printf("populating package [%s]\n",
1377a9edb9bfSAndrew Lindesay 					package->Name().String());
1378a9edb9bfSAndrew Lindesay 			}
137904c9d578SStephan Aßmus 		}
138004c9d578SStephan Aßmus 	}
138104c9d578SStephan Aßmus 
138204c9d578SStephan Aßmus 	return 0;
138304c9d578SStephan Aßmus }
138404c9d578SStephan Aßmus 
138504c9d578SStephan Aßmus 
138672fff6d3SJulian Harnath /* static */ status_t
138772fff6d3SJulian Harnath MainWindow::_PackagesToShowWorker(void* arg)
138872fff6d3SJulian Harnath {
138972fff6d3SJulian Harnath 	MainWindow* window = reinterpret_cast<MainWindow*>(arg);
139072fff6d3SJulian Harnath 
139172fff6d3SJulian Harnath 	while (acquire_sem(window->fNewPackagesToShowSem) == B_OK) {
139272fff6d3SJulian Harnath 		PackageList packageList;
139372fff6d3SJulian Harnath 		int32 listID = 0;
139472fff6d3SJulian Harnath 		{
139572fff6d3SJulian Harnath 			AutoLocker<BLocker> lock(&window->fPackagesToShowListLock);
139672fff6d3SJulian Harnath 			packageList = window->fPackagesToShowList;
139772fff6d3SJulian Harnath 			listID = atomic_get(&window->fPackagesToShowListID);
139872fff6d3SJulian Harnath 			window->fPackagesToShowList.Clear();
139972fff6d3SJulian Harnath 		}
140072fff6d3SJulian Harnath 
140172fff6d3SJulian Harnath 		// Add packages to list views in batches of kPackagesPerUpdate so we
140272fff6d3SJulian Harnath 		// don't block the window thread for long with each iteration
140372fff6d3SJulian Harnath 		enum {
140472fff6d3SJulian Harnath 			kPackagesPerUpdate = 20
140572fff6d3SJulian Harnath 		};
140672fff6d3SJulian Harnath 		uint32 packagesInMessage = 0;
140772fff6d3SJulian Harnath 		BMessage message(MSG_ADD_VISIBLE_PACKAGES);
140872fff6d3SJulian Harnath 		BMessenger messenger(window);
140972fff6d3SJulian Harnath 		bool listIsOutdated = false;
141072fff6d3SJulian Harnath 
141172fff6d3SJulian Harnath 		for (int i = 0; i < packageList.CountItems(); i++) {
141272fff6d3SJulian Harnath 			const PackageInfoRef& package = packageList.ItemAtFast(i);
141372fff6d3SJulian Harnath 
141472fff6d3SJulian Harnath 			if (packagesInMessage >= kPackagesPerUpdate) {
141572fff6d3SJulian Harnath 				if (listID != atomic_get(&window->fPackagesToShowListID)) {
141672fff6d3SJulian Harnath 					// The model was changed again in the meantime, and thus
141772fff6d3SJulian Harnath 					// our package list isn't current anymore. Send no further
141872fff6d3SJulian Harnath 					// messags based on this list and go back to start.
141972fff6d3SJulian Harnath 					listIsOutdated = true;
142072fff6d3SJulian Harnath 					break;
142172fff6d3SJulian Harnath 				}
142272fff6d3SJulian Harnath 
142372fff6d3SJulian Harnath 				message.AddInt32("list_id", listID);
142472fff6d3SJulian Harnath 				messenger.SendMessage(&message);
142572fff6d3SJulian Harnath 				message.MakeEmpty();
142672fff6d3SJulian Harnath 				packagesInMessage = 0;
142772fff6d3SJulian Harnath 
142872fff6d3SJulian Harnath 				// Don't spam the window's message queue, which would make it
142972fff6d3SJulian Harnath 				// unresponsive (i.e. allows UI messages to get in between our
143072fff6d3SJulian Harnath 				// messages). When it has processed the message we just sent,
143172fff6d3SJulian Harnath 				// it will let us know by releasing the semaphore.
143272fff6d3SJulian Harnath 				acquire_sem(window->fShowPackagesAcknowledgeSem);
143372fff6d3SJulian Harnath 			}
143472fff6d3SJulian Harnath 			package->AcquireReference();
143572fff6d3SJulian Harnath 			message.AddPointer("package_ref", package.Get());
143672fff6d3SJulian Harnath 			packagesInMessage++;
143772fff6d3SJulian Harnath 		}
143872fff6d3SJulian Harnath 
143972fff6d3SJulian Harnath 		if (listIsOutdated)
144072fff6d3SJulian Harnath 			continue;
144172fff6d3SJulian Harnath 
144272fff6d3SJulian Harnath 		// Send remaining package infos, if any, which didn't make it into
144372fff6d3SJulian Harnath 		// the last message (count < kPackagesPerUpdate)
144472fff6d3SJulian Harnath 		if (packagesInMessage > 0) {
144572fff6d3SJulian Harnath 			message.AddInt32("list_id", listID);
144672fff6d3SJulian Harnath 			messenger.SendMessage(&message);
144772fff6d3SJulian Harnath 			acquire_sem(window->fShowPackagesAcknowledgeSem);
144872fff6d3SJulian Harnath 		}
144972fff6d3SJulian Harnath 
145072fff6d3SJulian Harnath 		// Update selected package in list views
145172fff6d3SJulian Harnath 		messenger.SendMessage(MSG_UPDATE_SELECTED_PACKAGE);
145272fff6d3SJulian Harnath 	}
145372fff6d3SJulian Harnath 
145472fff6d3SJulian Harnath 	return 0;
145572fff6d3SJulian Harnath }
145672fff6d3SJulian Harnath 
145772fff6d3SJulian Harnath 
145804c9d578SStephan Aßmus void
145904c9d578SStephan Aßmus MainWindow::_NotifyUser(const char* title, const char* message)
146004c9d578SStephan Aßmus {
146104c9d578SStephan Aßmus 	BAlert* alert = new(std::nothrow) BAlert(title, message,
146204c9d578SStephan Aßmus 		B_TRANSLATE("Close"));
146304c9d578SStephan Aßmus 
146404c9d578SStephan Aßmus 	if (alert != NULL)
146504c9d578SStephan Aßmus 		alert->Go();
146604c9d578SStephan Aßmus }
146704c9d578SStephan Aßmus 
146804c9d578SStephan Aßmus 
146904c9d578SStephan Aßmus void
14701bbda92dSStephan Aßmus MainWindow::_OpenLoginWindow(const BMessage& onSuccessMessage)
147104c9d578SStephan Aßmus {
147204c9d578SStephan Aßmus 	UserLoginWindow* window = new UserLoginWindow(this,
147304c9d578SStephan Aßmus 		BRect(0, 0, 500, 400), fModel);
14741bbda92dSStephan Aßmus 
14751bbda92dSStephan Aßmus 	if (onSuccessMessage.what != 0)
14761bbda92dSStephan Aßmus 		window->SetOnSuccessMessage(BMessenger(this), onSuccessMessage);
14771bbda92dSStephan Aßmus 
147804c9d578SStephan Aßmus 	window->Show();
147904c9d578SStephan Aßmus }
148004c9d578SStephan Aßmus 
14818f03a0f9SStephan Aßmus 
14828f03a0f9SStephan Aßmus void
14838f03a0f9SStephan Aßmus MainWindow::_UpdateAuthorization()
14848f03a0f9SStephan Aßmus {
14858f03a0f9SStephan Aßmus 	BString username(fModel.Username());
1486e0a26dceSStephan Aßmus 	bool hasUser = !username.IsEmpty();
1487e0a26dceSStephan Aßmus 
14886d519fd1SStephan Aßmus 	if (fLogOutItem != NULL)
1489e0a26dceSStephan Aßmus 		fLogOutItem->SetEnabled(hasUser);
1490e0a26dceSStephan Aßmus 	if (fLogInItem != NULL) {
1491e0a26dceSStephan Aßmus 		if (hasUser)
1492e0a26dceSStephan Aßmus 			fLogInItem->SetLabel(B_TRANSLATE("Switch account" B_UTF8_ELLIPSIS));
1493e0a26dceSStephan Aßmus 		else
1494e0a26dceSStephan Aßmus 			fLogInItem->SetLabel(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS));
1495e0a26dceSStephan Aßmus 	}
1496e0a26dceSStephan Aßmus 
1497e0a26dceSStephan Aßmus 	if (fUserMenu != NULL) {
1498e0a26dceSStephan Aßmus 		BString label;
1499e0a26dceSStephan Aßmus 		if (username.Length() == 0) {
1500e0a26dceSStephan Aßmus 			label = B_TRANSLATE("Not logged in");
1501e0a26dceSStephan Aßmus 		} else {
1502e0a26dceSStephan Aßmus 			label = B_TRANSLATE("Logged in as %User%");
1503e0a26dceSStephan Aßmus 			label.ReplaceAll("%User%", username);
1504e0a26dceSStephan Aßmus 		}
1505e0a26dceSStephan Aßmus 		fUserMenu->Superitem()->SetLabel(label);
1506e0a26dceSStephan Aßmus 	}
15078f03a0f9SStephan Aßmus }
15081bbda92dSStephan Aßmus 
15091bbda92dSStephan Aßmus 
15101bbda92dSStephan Aßmus void
1511b965ce70SHumdinger MainWindow::_UpdateAvailableRepositories()
1512b965ce70SHumdinger {
1513b965ce70SHumdinger 	fRepositoryMenu->RemoveItems(0, fRepositoryMenu->CountItems(), true);
1514b965ce70SHumdinger 
1515b965ce70SHumdinger 	fRepositoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All repositories"),
1516b965ce70SHumdinger 		new BMessage(MSG_DEPOT_SELECTED)));
1517b965ce70SHumdinger 
1518b965ce70SHumdinger 	fRepositoryMenu->AddItem(new BSeparatorItem());
1519b965ce70SHumdinger 
1520b965ce70SHumdinger 	bool foundSelectedDepot = false;
1521b965ce70SHumdinger 	const DepotList& depots = fModel.Depots();
1522b965ce70SHumdinger 	for (int i = 0; i < depots.CountItems(); i++) {
1523b965ce70SHumdinger 		const DepotInfo& depot = depots.ItemAtFast(i);
1524d13c3d89SAndrew Lindesay 
1525d13c3d89SAndrew Lindesay 		if (depot.Name().Length() != 0) {
1526b965ce70SHumdinger 			BMessage* message = new BMessage(MSG_DEPOT_SELECTED);
1527b965ce70SHumdinger 			message->AddString("name", depot.Name());
1528b965ce70SHumdinger 			BMenuItem* item = new BMenuItem(depot.Name(), message);
1529b965ce70SHumdinger 			fRepositoryMenu->AddItem(item);
1530b965ce70SHumdinger 
1531b965ce70SHumdinger 			if (depot.Name() == fModel.Depot()) {
1532b965ce70SHumdinger 				item->SetMarked(true);
1533b965ce70SHumdinger 				foundSelectedDepot = true;
1534b965ce70SHumdinger 			}
1535b965ce70SHumdinger 		}
1536d13c3d89SAndrew Lindesay 	}
1537b965ce70SHumdinger 
1538b965ce70SHumdinger 	if (!foundSelectedDepot)
1539b965ce70SHumdinger 		fRepositoryMenu->ItemAt(0)->SetMarked(true);
1540b965ce70SHumdinger }
1541b965ce70SHumdinger 
1542b965ce70SHumdinger 
1543a9edb9bfSAndrew Lindesay bool
1544a9edb9bfSAndrew Lindesay MainWindow::_SelectedPackageHasWebAppRepositoryCode()
1545a9edb9bfSAndrew Lindesay {
1546a9edb9bfSAndrew Lindesay 	const PackageInfoRef& package = fPackageInfoView->Package();
15476ab878c0SAndrew Lindesay 	const BString depotName = package->DepotName();
1548a9edb9bfSAndrew Lindesay 
15496ab878c0SAndrew Lindesay 	if (depotName.IsEmpty()) {
15506ab878c0SAndrew Lindesay 		if (Logger::IsDebugEnabled()) {
15516ab878c0SAndrew Lindesay 			printf("the package [%s] has no depot name\n",
15526ab878c0SAndrew Lindesay 				package->Name().String());
15536ab878c0SAndrew Lindesay 		}
15546ab878c0SAndrew Lindesay 	} else {
15556ab878c0SAndrew Lindesay 		const DepotInfo* depot = fModel.DepotForName(depotName);
1556a9edb9bfSAndrew Lindesay 
15576ab878c0SAndrew Lindesay 		if (depot == NULL) {
15586ab878c0SAndrew Lindesay 			printf("the depot [%s] was not able to be found\n",
15596ab878c0SAndrew Lindesay 				depotName.String());
15606ab878c0SAndrew Lindesay 		} else {
15616ab878c0SAndrew Lindesay 			BString repositoryCode = depot->WebAppRepositoryCode();
1562a9edb9bfSAndrew Lindesay 
15636ab878c0SAndrew Lindesay 			if (repositoryCode.IsEmpty()) {
15646ab878c0SAndrew Lindesay 				printf("the depot [%s] has no web app repository code\n",
15656ab878c0SAndrew Lindesay 					depotName.String());
15666ab878c0SAndrew Lindesay 			} else {
15676ab878c0SAndrew Lindesay 				return true;
15686ab878c0SAndrew Lindesay 			}
15696ab878c0SAndrew Lindesay 		}
15706ab878c0SAndrew Lindesay 	}
15716ab878c0SAndrew Lindesay 
15726ab878c0SAndrew Lindesay 	return false;
1573a9edb9bfSAndrew Lindesay }
1574a9edb9bfSAndrew Lindesay 
1575a9edb9bfSAndrew Lindesay 
1576b965ce70SHumdinger void
15771bbda92dSStephan Aßmus MainWindow::_RatePackage()
15781bbda92dSStephan Aßmus {
1579a9edb9bfSAndrew Lindesay 	if (!_SelectedPackageHasWebAppRepositoryCode()) {
1580a9edb9bfSAndrew Lindesay 		BAlert* alert = new(std::nothrow) BAlert(
1581cbadcae1SHumdinger 			B_TRANSLATE("Rating not possible"),
1582cbadcae1SHumdinger 			B_TRANSLATE("This package doesn't seem to be on the HaikuDepot "
1583cbadcae1SHumdinger 				"Server, so it's not possible to create a new rating "
1584cbadcae1SHumdinger 				"or edit an existing rating."),
1585a9edb9bfSAndrew Lindesay 			B_TRANSLATE("OK"));
1586a9edb9bfSAndrew Lindesay 		alert->Go();
1587a9edb9bfSAndrew Lindesay     	return;
1588a9edb9bfSAndrew Lindesay 	}
1589a9edb9bfSAndrew Lindesay 
15901bbda92dSStephan Aßmus 	if (fModel.Username().IsEmpty()) {
15911bbda92dSStephan Aßmus 		BAlert* alert = new(std::nothrow) BAlert(
15921bbda92dSStephan Aßmus 			B_TRANSLATE("Not logged in"),
15931bbda92dSStephan Aßmus 			B_TRANSLATE("You need to be logged into an account before you "
15941bbda92dSStephan Aßmus 				"can rate packages."),
15951bbda92dSStephan Aßmus 			B_TRANSLATE("Cancel"),
15961bbda92dSStephan Aßmus 			B_TRANSLATE("Login or Create account"));
15971bbda92dSStephan Aßmus 
15981bbda92dSStephan Aßmus 		if (alert == NULL)
15991bbda92dSStephan Aßmus 			return;
16001bbda92dSStephan Aßmus 
16011bbda92dSStephan Aßmus 		int32 choice = alert->Go();
16021bbda92dSStephan Aßmus 		if (choice == 1)
16031bbda92dSStephan Aßmus 			_OpenLoginWindow(BMessage(MSG_RATE_PACKAGE));
16041bbda92dSStephan Aßmus 		return;
16051bbda92dSStephan Aßmus 	}
16061bbda92dSStephan Aßmus 
16071bbda92dSStephan Aßmus 	// TODO: Allow only one RatePackageWindow
16081bbda92dSStephan Aßmus 	// TODO: Mechanism for remembering the window frame
16091bbda92dSStephan Aßmus 	RatePackageWindow* window = new RatePackageWindow(this,
16101bbda92dSStephan Aßmus 		BRect(0, 0, 500, 400), fModel);
16111bbda92dSStephan Aßmus 	window->SetPackage(fPackageInfoView->Package());
16121bbda92dSStephan Aßmus 	window->Show();
16131bbda92dSStephan Aßmus }
1614d5ef985eSStephan Aßmus 
1615d5ef985eSStephan Aßmus 
1616d5ef985eSStephan Aßmus void
1617d5ef985eSStephan Aßmus MainWindow::_ShowScreenshot()
1618d5ef985eSStephan Aßmus {
1619d5ef985eSStephan Aßmus 	// TODO: Mechanism for remembering the window frame
1620d5ef985eSStephan Aßmus 	if (fScreenshotWindow == NULL)
1621d5ef985eSStephan Aßmus 		fScreenshotWindow = new ScreenshotWindow(this, BRect(0, 0, 500, 400));
1622d5ef985eSStephan Aßmus 
1623d5ef985eSStephan Aßmus 	if (fScreenshotWindow->LockWithTimeout(1000) != B_OK)
1624d5ef985eSStephan Aßmus 		return;
1625d5ef985eSStephan Aßmus 
1626d5ef985eSStephan Aßmus 	fScreenshotWindow->SetPackage(fPackageInfoView->Package());
1627d5ef985eSStephan Aßmus 
1628d5ef985eSStephan Aßmus 	if (fScreenshotWindow->IsHidden())
1629d5ef985eSStephan Aßmus 		fScreenshotWindow->Show();
1630d5ef985eSStephan Aßmus 	else
1631d5ef985eSStephan Aßmus 		fScreenshotWindow->Activate();
1632d5ef985eSStephan Aßmus 
1633d5ef985eSStephan Aßmus 	fScreenshotWindow->Unlock();
1634d5ef985eSStephan Aßmus }
1635