xref: /haiku/src/apps/haikudepot/ui/MainWindow.cpp (revision 8cc3ed34bc750057f65c4eb7d69bdbd65a4f7256)
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.
688af15cfSAndrew Lindesay  * Copyright 2016-2024, 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 #include "MainWindow.h"
1104c9d578SStephan Aßmus 
1204c9d578SStephan Aßmus #include <map>
133b17d8ddSAndrew Lindesay #include <vector>
1404c9d578SStephan Aßmus 
1504c9d578SStephan Aßmus #include <stdio.h>
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>
2584674570SAndrew Lindesay #include <MessageRunner.h>
2604c9d578SStephan Aßmus #include <Messenger.h>
275bf2b6ebSBrian Hill #include <Roster.h>
28f7c2983eSAxel Dörfler #include <Screen.h>
2904c9d578SStephan Aßmus #include <ScrollView.h>
3004c9d578SStephan Aßmus #include <StringList.h>
310a9c9029SStephan Aßmus #include <StringView.h>
3204c9d578SStephan Aßmus #include <TabView.h>
3304c9d578SStephan Aßmus 
343369e03dSAndrew Lindesay #include "AppUtils.h"
3504c9d578SStephan Aßmus #include "AutoDeleter.h"
3604c9d578SStephan Aßmus #include "AutoLocker.h"
3704c9d578SStephan Aßmus #include "DecisionProvider.h"
384b930ccaSStephan Aßmus #include "FeaturedPackagesView.h"
3904c9d578SStephan Aßmus #include "FilterView.h"
40d668d227SAndrew Lindesay #include "LocaleUtils.h"
41d13c3d89SAndrew Lindesay #include "Logger.h"
4204c9d578SStephan Aßmus #include "PackageInfoView.h"
4304c9d578SStephan Aßmus #include "PackageListView.h"
4404c9d578SStephan Aßmus #include "PackageManager.h"
453369e03dSAndrew Lindesay #include "ProcessCoordinator.h"
463369e03dSAndrew Lindesay #include "ProcessCoordinatorFactory.h"
4704c9d578SStephan Aßmus #include "RatePackageWindow.h"
484b3c808eSAndrew Lindesay #include "RatingUtils.h"
49d5ef985eSStephan Aßmus #include "ScreenshotWindow.h"
50133ebab6SAndrew Lindesay #include "SettingsWindow.h"
5195c7b018SAndrew Lindesay #include "ShuttingDownWindow.h"
5210cd325cSAndrew Lindesay #include "ToLatestUserUsageConditionsWindow.h"
5304c9d578SStephan Aßmus #include "UserLoginWindow.h"
5401339a54SAndrew Lindesay #include "UserUsageConditionsWindow.h"
55125d42d9SJulian Harnath #include "WorkStatusView.h"
56d668d227SAndrew Lindesay #include "support.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 {
645bf2b6ebSBrian Hill 	MSG_REFRESH_REPOS						= 'mrrp',
655bf2b6ebSBrian Hill 	MSG_MANAGE_REPOS						= 'mmrp',
66d144f952SAugustin Cavalier 	MSG_SOFTWARE_UPDATER					= 'mswu',
67133ebab6SAndrew Lindesay 	MSG_SETTINGS							= 'stgs',
6804c9d578SStephan Aßmus 	MSG_LOG_IN								= 'lgin',
698f03a0f9SStephan Aßmus 	MSG_AUTHORIZATION_CHANGED				= 'athc',
7089b16bb4SAndrew Lindesay 	MSG_CATEGORIES_LIST_CHANGED				= 'clic',
71da651104SStephan Aßmus 	MSG_PACKAGE_CHANGED						= 'pchd',
72409af934SAndrew Lindesay 	MSG_PROCESS_COORDINATOR_CHANGED			= 'pccd',
733369e03dSAndrew Lindesay 	MSG_WORK_STATUS_CHANGE					= 'wsch',
743369e03dSAndrew Lindesay 	MSG_WORK_STATUS_CLEAR					= 'wscl',
7584674570SAndrew Lindesay 	MSG_INCREMENT_VIEW_COUNTER				= 'icrv',
7688af15cfSAndrew Lindesay 	MSG_SCREENSHOT_CACHED					= 'ssca',
77fdec4227SStephan Aßmus 
78ccf707d0SAndrew Lindesay 	MSG_CHANGE_PACKAGE_LIST_VIEW_MODE		= 'cplm',
79fdec4227SStephan Aßmus 	MSG_SHOW_AVAILABLE_PACKAGES				= 'savl',
80fdec4227SStephan Aßmus 	MSG_SHOW_INSTALLED_PACKAGES				= 'sins',
8104c9d578SStephan Aßmus 	MSG_SHOW_SOURCE_PACKAGES				= 'ssrc',
8204c9d578SStephan Aßmus 	MSG_SHOW_DEVELOP_PACKAGES				= 'sdvl'
8304c9d578SStephan Aßmus };
8404c9d578SStephan Aßmus 
8510cd325cSAndrew Lindesay #define KEY_ERROR_STATUS				"errorStatus"
86ccf707d0SAndrew Lindesay 
8784674570SAndrew Lindesay const bigtime_t kIncrementViewCounterDelayMicros = 3 * 1000 * 1000;
8884674570SAndrew Lindesay 
89ccf707d0SAndrew Lindesay #define TAB_PROMINENT_PACKAGES	0
90ccf707d0SAndrew Lindesay #define TAB_ALL_PACKAGES		1
9104c9d578SStephan Aßmus 
9204c9d578SStephan Aßmus using namespace BPackageKit;
9304c9d578SStephan Aßmus using namespace BPackageKit::BManager::BPrivate;
9404c9d578SStephan Aßmus 
9504c9d578SStephan Aßmus 
9604c9d578SStephan Aßmus typedef std::map<BString, PackageInfoRef> PackageInfoMap;
9704c9d578SStephan Aßmus 
9804c9d578SStephan Aßmus 
9904c9d578SStephan Aßmus struct RefreshWorkerParameters {
10004c9d578SStephan Aßmus 	MainWindow* window;
10104c9d578SStephan Aßmus 	bool forceRefresh;
10204c9d578SStephan Aßmus 
10304c9d578SStephan Aßmus 	RefreshWorkerParameters(MainWindow* window, bool forceRefresh)
10404c9d578SStephan Aßmus 		:
10504c9d578SStephan Aßmus 		window(window),
10604c9d578SStephan Aßmus 		forceRefresh(forceRefresh)
10704c9d578SStephan Aßmus 	{
10804c9d578SStephan Aßmus 	}
10904c9d578SStephan Aßmus };
11004c9d578SStephan Aßmus 
11104c9d578SStephan Aßmus 
11289b16bb4SAndrew Lindesay class MainWindowModelListener : public ModelListener {
1138f03a0f9SStephan Aßmus public:
11489b16bb4SAndrew Lindesay 	MainWindowModelListener(const BMessenger& messenger)
1158f03a0f9SStephan Aßmus 		:
1168f03a0f9SStephan Aßmus 		fMessenger(messenger)
1178f03a0f9SStephan Aßmus 	{
1188f03a0f9SStephan Aßmus 	}
1198f03a0f9SStephan Aßmus 
1208f03a0f9SStephan Aßmus 	virtual void AuthorizationChanged()
1218f03a0f9SStephan Aßmus 	{
1228f03a0f9SStephan Aßmus 		if (fMessenger.IsValid())
1238f03a0f9SStephan Aßmus 			fMessenger.SendMessage(MSG_AUTHORIZATION_CHANGED);
1248f03a0f9SStephan Aßmus 	}
1258f03a0f9SStephan Aßmus 
12689b16bb4SAndrew Lindesay 	virtual void CategoryListChanged()
12789b16bb4SAndrew Lindesay 	{
12889b16bb4SAndrew Lindesay 		if (fMessenger.IsValid())
12989b16bb4SAndrew Lindesay 			fMessenger.SendMessage(MSG_CATEGORIES_LIST_CHANGED);
13089b16bb4SAndrew Lindesay 	}
13189b16bb4SAndrew Lindesay 
13288af15cfSAndrew Lindesay 	virtual void ScreenshotCached(const ScreenshotCoordinate& coordinate)
13388af15cfSAndrew Lindesay 	{
13488af15cfSAndrew Lindesay 		if (fMessenger.IsValid()) {
13588af15cfSAndrew Lindesay 			BMessage message(MSG_SCREENSHOT_CACHED);
13688af15cfSAndrew Lindesay 			if (coordinate.Archive(&message) != B_OK)
13788af15cfSAndrew Lindesay 				debugger("unable to serialize a screenshot coordinate");
13888af15cfSAndrew Lindesay 			fMessenger.SendMessage(&message);
13988af15cfSAndrew Lindesay 		}
14088af15cfSAndrew Lindesay 	}
14188af15cfSAndrew Lindesay 
1428f03a0f9SStephan Aßmus private:
1438f03a0f9SStephan Aßmus 	BMessenger	fMessenger;
1448f03a0f9SStephan Aßmus };
1458f03a0f9SStephan Aßmus 
1468f03a0f9SStephan Aßmus 
147409af934SAndrew Lindesay class MainWindowPackageInfoListener : public PackageInfoListener {
148409af934SAndrew Lindesay public:
149409af934SAndrew Lindesay 	MainWindowPackageInfoListener(MainWindow* mainWindow)
150409af934SAndrew Lindesay 		:
151409af934SAndrew Lindesay 		fMainWindow(mainWindow)
152409af934SAndrew Lindesay 	{
153409af934SAndrew Lindesay 	}
154409af934SAndrew Lindesay 
155409af934SAndrew Lindesay 	~MainWindowPackageInfoListener()
156409af934SAndrew Lindesay 	{
157409af934SAndrew Lindesay 	}
158409af934SAndrew Lindesay 
159409af934SAndrew Lindesay private:
160409af934SAndrew Lindesay 	// PackageInfoListener
161409af934SAndrew Lindesay 	virtual	void PackageChanged(const PackageInfoEvent& event)
162409af934SAndrew Lindesay 	{
163409af934SAndrew Lindesay 		fMainWindow->PackageChanged(event);
164409af934SAndrew Lindesay 	}
165409af934SAndrew Lindesay 
166409af934SAndrew Lindesay private:
167409af934SAndrew Lindesay 	MainWindow*	fMainWindow;
168409af934SAndrew Lindesay };
169409af934SAndrew Lindesay 
170409af934SAndrew Lindesay 
171f7c2983eSAxel Dörfler MainWindow::MainWindow(const BMessage& settings)
17204c9d578SStephan Aßmus 	:
173f7c2983eSAxel Dörfler 	BWindow(BRect(50, 50, 650, 550), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"),
17404c9d578SStephan Aßmus 		B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
17504c9d578SStephan Aßmus 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
176d5ef985eSStephan Aßmus 	fScreenshotWindow(NULL),
17795c7b018SAndrew Lindesay 	fShuttingDownWindow(NULL),
178e0a26dceSStephan Aßmus 	fUserMenu(NULL),
179e0a26dceSStephan Aßmus 	fLogInItem(NULL),
180e0a26dceSStephan Aßmus 	fLogOutItem(NULL),
181976cadf1SAndrew Lindesay 	fUsersUserUsageConditionsMenuItem(NULL),
18289b16bb4SAndrew Lindesay 	fModelListener(new MainWindowModelListener(BMessenger(this)), true),
18310cd325cSAndrew Lindesay 	fCoordinator(NULL),
18495c7b018SAndrew Lindesay 	fShouldCloseWhenNoProcessesToCoordinate(false),
18584674570SAndrew Lindesay 	fSinglePackageMode(false),
18684674570SAndrew Lindesay 	fIncrementViewCounterDelayedRunner(NULL)
18704c9d578SStephan Aßmus {
18810cd325cSAndrew Lindesay 	if ((fCoordinatorRunningSem = create_sem(1, "ProcessCoordinatorSem")) < B_OK)
18910cd325cSAndrew Lindesay 		debugger("unable to create the process coordinator semaphore");
19010cd325cSAndrew Lindesay 
191ad2df681SAndrew Lindesay 	_InitPreferredLanguage();
192ad2df681SAndrew Lindesay 
193409af934SAndrew Lindesay 	fPackageInfoListener = PackageInfoListenerRef(
194409af934SAndrew Lindesay 		new MainWindowPackageInfoListener(this), true);
195409af934SAndrew Lindesay 
196cbadcae1SHumdinger 	BMenuBar* menuBar = new BMenuBar("Main Menu");
19704c9d578SStephan Aßmus 	_BuildMenu(menuBar);
19804c9d578SStephan Aßmus 
199cbadcae1SHumdinger 	BMenuBar* userMenuBar = new BMenuBar("User Menu");
200e0a26dceSStephan Aßmus 	_BuildUserMenu(userMenuBar);
201e0a26dceSStephan Aßmus 	set_small_font(userMenuBar);
202e0a26dceSStephan Aßmus 	userMenuBar->SetExplicitMaxSize(BSize(B_SIZE_UNSET,
203e0a26dceSStephan Aßmus 		menuBar->MaxSize().height));
204e0a26dceSStephan Aßmus 
20504c9d578SStephan Aßmus 	fFilterView = new FilterView();
206f0e491d3SAndrew Lindesay 	fFeaturedPackagesView = new FeaturedPackagesView(fModel);
207f0e491d3SAndrew Lindesay 	fPackageListView = new PackageListView(&fModel);
208f0e491d3SAndrew Lindesay 	fPackageInfoView = new PackageInfoView(&fModel, this);
20904c9d578SStephan Aßmus 
21004c9d578SStephan Aßmus 	fSplitView = new BSplitView(B_VERTICAL, 5.0f);
21104c9d578SStephan Aßmus 
212125d42d9SJulian Harnath 	fWorkStatusView = new WorkStatusView("work status");
213125d42d9SJulian Harnath 	fPackageListView->AttachWorkStatusView(fWorkStatusView);
214125d42d9SJulian Harnath 
215e00a489bSAugustin Cavalier 	fListTabs = new TabView(BMessenger(this),
216ccf707d0SAndrew Lindesay 		BMessage(MSG_CHANGE_PACKAGE_LIST_VIEW_MODE), "list tabs");
217e00a489bSAugustin Cavalier 	fListTabs->AddTab(fFeaturedPackagesView);
218e00a489bSAugustin Cavalier 	fListTabs->AddTab(fPackageListView);
2194b930ccaSStephan Aßmus 
22004c9d578SStephan Aßmus 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f)
221e0a26dceSStephan Aßmus 		.AddGroup(B_HORIZONTAL, 0.0f)
222e0a26dceSStephan Aßmus 			.Add(menuBar, 1.0f)
223e0a26dceSStephan Aßmus 			.Add(userMenuBar, 0.0f)
224e0a26dceSStephan Aßmus 		.End()
22504c9d578SStephan Aßmus 		.Add(fFilterView)
22604c9d578SStephan Aßmus 		.AddSplit(fSplitView)
22704c9d578SStephan Aßmus 			.AddGroup(B_VERTICAL)
228e00a489bSAugustin Cavalier 				.Add(fListTabs)
22904c9d578SStephan Aßmus 				.SetInsets(
23004c9d578SStephan Aßmus 					B_USE_DEFAULT_SPACING, 0.0f,
23104c9d578SStephan Aßmus 					B_USE_DEFAULT_SPACING, 0.0f)
23204c9d578SStephan Aßmus 			.End()
23304c9d578SStephan Aßmus 			.Add(fPackageInfoView)
23404c9d578SStephan Aßmus 		.End()
235125d42d9SJulian Harnath 		.Add(fWorkStatusView)
23604c9d578SStephan Aßmus 	;
23704c9d578SStephan Aßmus 
23804c9d578SStephan Aßmus 	fSplitView->SetCollapsible(0, false);
23904c9d578SStephan Aßmus 	fSplitView->SetCollapsible(1, false);
24004c9d578SStephan Aßmus 
2418f03a0f9SStephan Aßmus 	fModel.AddListener(fModelListener);
2428f03a0f9SStephan Aßmus 
24304c9d578SStephan Aßmus 	BMessage columnSettings;
24404c9d578SStephan Aßmus 	if (settings.FindMessage("column settings", &columnSettings) == B_OK)
24504c9d578SStephan Aßmus 		fPackageListView->LoadState(&columnSettings);
24604c9d578SStephan Aßmus 
247ccf707d0SAndrew Lindesay 	_RestoreModelSettings(settings);
248133ebab6SAndrew Lindesay 	_MaybePromptCanShareAnonymousUserData(settings);
24904c9d578SStephan Aßmus 
250ccf707d0SAndrew Lindesay 	if (fModel.PackageListViewMode() == PROMINENT)
251ccf707d0SAndrew Lindesay 		fListTabs->Select(TAB_PROMINENT_PACKAGES);
2522997e05bSStephan Aßmus 	else
253ccf707d0SAndrew Lindesay 		fListTabs->Select(TAB_ALL_PACKAGES);
2542997e05bSStephan Aßmus 
255d2d4866dSAndrew Lindesay 	_RestoreNickname(settings);
25610cd325cSAndrew Lindesay 	_UpdateAuthorization();
257f7c2983eSAxel Dörfler 	_RestoreWindowFrame(settings);
258f7c2983eSAxel Dörfler 
2598f03a0f9SStephan Aßmus 	// start worker threads
26004c9d578SStephan Aßmus 	BPackageRoster().StartWatching(this,
26104c9d578SStephan Aßmus 		B_WATCH_PACKAGE_INSTALLATION_LOCATIONS);
26204c9d578SStephan Aßmus 
2639883929bSAndrew Lindesay 	_AdoptModel();
2649883929bSAndrew Lindesay 	_StartBulkLoad();
26504c9d578SStephan Aßmus }
26604c9d578SStephan Aßmus 
26704c9d578SStephan Aßmus 
26875a70554SAndrew Lindesay /*!	This constructor is used when the application is loaded for the purpose of
26975a70554SAndrew Lindesay 	viewing an HPKG file.
27075a70554SAndrew Lindesay */
27175a70554SAndrew Lindesay 
272afe7affbSAndrew Lindesay MainWindow::MainWindow(const BMessage& settings, PackageInfoRef& package)
2736d519fd1SStephan Aßmus 	:
274f7c2983eSAxel Dörfler 	BWindow(BRect(50, 50, 650, 350), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"),
2756d519fd1SStephan Aßmus 		B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
2766d519fd1SStephan Aßmus 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
2779883929bSAndrew Lindesay 	fFeaturedPackagesView(NULL),
2789883929bSAndrew Lindesay 	fPackageListView(NULL),
279d78bfd8dSJulian Harnath 	fWorkStatusView(NULL),
280d5ef985eSStephan Aßmus 	fScreenshotWindow(NULL),
28195c7b018SAndrew Lindesay 	fShuttingDownWindow(NULL),
282e0a26dceSStephan Aßmus 	fUserMenu(NULL),
283e0a26dceSStephan Aßmus 	fLogInItem(NULL),
2846d519fd1SStephan Aßmus 	fLogOutItem(NULL),
285976cadf1SAndrew Lindesay 	fUsersUserUsageConditionsMenuItem(NULL),
28689b16bb4SAndrew Lindesay 	fModelListener(new MainWindowModelListener(BMessenger(this)), true),
28710cd325cSAndrew Lindesay 	fCoordinator(NULL),
28895c7b018SAndrew Lindesay 	fShouldCloseWhenNoProcessesToCoordinate(false),
28984674570SAndrew Lindesay 	fSinglePackageMode(true),
29084674570SAndrew Lindesay 	fIncrementViewCounterDelayedRunner(NULL)
2916d519fd1SStephan Aßmus {
29275a70554SAndrew Lindesay 	BString title = B_TRANSLATE("HaikuDepot - %PackageName% %PackageVersion%");
29375a70554SAndrew Lindesay 	title.ReplaceAll("%PackageName%", package->Name());
29475a70554SAndrew Lindesay 	title.ReplaceAll("%PackageVersion%", package->Version().ToString());
29575a70554SAndrew Lindesay 	SetTitle(title);
29675a70554SAndrew Lindesay 
29710cd325cSAndrew Lindesay 	if ((fCoordinatorRunningSem = create_sem(1, "ProcessCoordinatorSem")) < B_OK)
29810cd325cSAndrew Lindesay 		debugger("unable to create the process coordinator semaphore");
29910cd325cSAndrew Lindesay 
300ad2df681SAndrew Lindesay 	_InitPreferredLanguage();
301ad2df681SAndrew Lindesay 
302409af934SAndrew Lindesay 	fPackageInfoListener = PackageInfoListenerRef(
303409af934SAndrew Lindesay 		new MainWindowPackageInfoListener(this), true);
304409af934SAndrew Lindesay 
3056d519fd1SStephan Aßmus 	fFilterView = new FilterView();
306f0e491d3SAndrew Lindesay 	fPackageInfoView = new PackageInfoView(&fModel, this);
30787016f8fSAndrew Lindesay 	fWorkStatusView = new WorkStatusView("work status");
3086d519fd1SStephan Aßmus 
3096d519fd1SStephan Aßmus 	BLayoutBuilder::Group<>(this, B_VERTICAL)
3106d519fd1SStephan Aßmus 		.Add(fPackageInfoView)
31187016f8fSAndrew Lindesay 		.Add(fWorkStatusView)
3126d519fd1SStephan Aßmus 		.SetInsets(0, B_USE_WINDOW_INSETS, 0, 0)
3136d519fd1SStephan Aßmus 	;
3146d519fd1SStephan Aßmus 
3156d519fd1SStephan Aßmus 	fModel.AddListener(fModelListener);
3166d519fd1SStephan Aßmus 
317afe7affbSAndrew Lindesay 	// add the single package into the model so that any internal
318afe7affbSAndrew Lindesay 	// business logic is able to find the package.
319afe7affbSAndrew Lindesay 	DepotInfoRef depot(new DepotInfo("single-pkg-depot"), true);
320afe7affbSAndrew Lindesay 	depot->AddPackage(package);
321afe7affbSAndrew Lindesay 	fModel.MergeOrAddDepot(depot);
322afe7affbSAndrew Lindesay 
3236d519fd1SStephan Aßmus 	// Restore settings
324d2d4866dSAndrew Lindesay 	_RestoreNickname(settings);
325ccf707d0SAndrew Lindesay 	_UpdateAuthorization();
326f7c2983eSAxel Dörfler 	_RestoreWindowFrame(settings);
3276d519fd1SStephan Aßmus 
3286d519fd1SStephan Aßmus 	fPackageInfoView->SetPackage(package);
32963975654SStephan Aßmus 
330afe7affbSAndrew Lindesay 	// start worker threads
331afe7affbSAndrew Lindesay 	BPackageRoster().StartWatching(this,
332afe7affbSAndrew Lindesay 		B_WATCH_PACKAGE_INSTALLATION_LOCATIONS);
3336d519fd1SStephan Aßmus }
3346d519fd1SStephan Aßmus 
3356d519fd1SStephan Aßmus 
33604c9d578SStephan Aßmus MainWindow::~MainWindow()
33704c9d578SStephan Aßmus {
33810cd325cSAndrew Lindesay 	_SpinUntilProcessCoordinatorComplete();
33910cd325cSAndrew Lindesay 	delete_sem(fCoordinatorRunningSem);
34010cd325cSAndrew Lindesay 	fCoordinatorRunningSem = 0;
34110cd325cSAndrew Lindesay 
34204c9d578SStephan Aßmus 	BPackageRoster().StopWatching(this);
34304c9d578SStephan Aßmus 
34495c7b018SAndrew Lindesay 	if (fScreenshotWindow != NULL) {
34595c7b018SAndrew Lindesay 		if (fScreenshotWindow->Lock())
346d5ef985eSStephan Aßmus 			fScreenshotWindow->Quit();
34704c9d578SStephan Aßmus 	}
34804c9d578SStephan Aßmus 
34995c7b018SAndrew Lindesay 	if (fShuttingDownWindow != NULL) {
35095c7b018SAndrew Lindesay 		if (fShuttingDownWindow->Lock())
35195c7b018SAndrew Lindesay 			fShuttingDownWindow->Quit();
35295c7b018SAndrew Lindesay 	}
353d5562247SAugustin Cavalier 
3544329a83fSAugustin Cavalier 	// We must clear the model early to release references.
355d5562247SAugustin Cavalier 	fModel.Clear();
35695c7b018SAndrew Lindesay }
35795c7b018SAndrew Lindesay 
35804c9d578SStephan Aßmus 
35904c9d578SStephan Aßmus bool
36004c9d578SStephan Aßmus MainWindow::QuitRequested()
36104c9d578SStephan Aßmus {
36204c9d578SStephan Aßmus 
36310cd325cSAndrew Lindesay 	_StopProcessCoordinators();
3643369e03dSAndrew Lindesay 
36595c7b018SAndrew Lindesay 	// If there are any processes in flight we need to be careful to make
36695c7b018SAndrew Lindesay 	// sure that they are cleanly completed before actually quitting.  By
36795c7b018SAndrew Lindesay 	// turning on the `fShouldCloseWhenNoProcessesToCoordinate` flag, when
36895c7b018SAndrew Lindesay 	// the process coordination has completed then it will detect this and
36995c7b018SAndrew Lindesay 	// quit again.
37095c7b018SAndrew Lindesay 
37195c7b018SAndrew Lindesay 	{
37295c7b018SAndrew Lindesay 		AutoLocker<BLocker> lock(&fCoordinatorLock);
37395c7b018SAndrew Lindesay 		fShouldCloseWhenNoProcessesToCoordinate = true;
37495c7b018SAndrew Lindesay 
375409af934SAndrew Lindesay 		if (fCoordinator != NULL) {
37695c7b018SAndrew Lindesay 			HDINFO("a coordinator is running --> will wait before quitting...");
37795c7b018SAndrew Lindesay 
37895c7b018SAndrew Lindesay 			if (fShuttingDownWindow == NULL)
37995c7b018SAndrew Lindesay 				fShuttingDownWindow = new ShuttingDownWindow(this);
38095c7b018SAndrew Lindesay 			fShuttingDownWindow->Show();
38195c7b018SAndrew Lindesay 
38295c7b018SAndrew Lindesay 			return false;
38395c7b018SAndrew Lindesay 		}
38495c7b018SAndrew Lindesay 	}
38595c7b018SAndrew Lindesay 
38695c7b018SAndrew Lindesay 	BMessage settings;
38795c7b018SAndrew Lindesay 	StoreSettings(settings);
38895c7b018SAndrew Lindesay 	BMessage message(MSG_MAIN_WINDOW_CLOSED);
38995c7b018SAndrew Lindesay 	message.AddMessage(KEY_WINDOW_SETTINGS, &settings);
39095c7b018SAndrew Lindesay 	be_app->PostMessage(&message);
39195c7b018SAndrew Lindesay 
39295c7b018SAndrew Lindesay 	if (fShuttingDownWindow != NULL) {
39395c7b018SAndrew Lindesay 		if (fShuttingDownWindow->Lock())
39495c7b018SAndrew Lindesay 			fShuttingDownWindow->Quit();
39595c7b018SAndrew Lindesay 		fShuttingDownWindow = NULL;
39695c7b018SAndrew Lindesay 	}
39795c7b018SAndrew Lindesay 
39804c9d578SStephan Aßmus 	return true;
39904c9d578SStephan Aßmus }
40004c9d578SStephan Aßmus 
40104c9d578SStephan Aßmus 
40204c9d578SStephan Aßmus void
40304c9d578SStephan Aßmus MainWindow::MessageReceived(BMessage* message)
40404c9d578SStephan Aßmus {
40504c9d578SStephan Aßmus 	switch (message->what) {
4063369e03dSAndrew Lindesay 		case MSG_BULK_LOAD_DONE:
40710cd325cSAndrew Lindesay 		{
40810cd325cSAndrew Lindesay 			int64 errorStatus64;
40910cd325cSAndrew Lindesay 			if (message->FindInt64(KEY_ERROR_STATUS, &errorStatus64) == B_OK)
41010cd325cSAndrew Lindesay 				_BulkLoadCompleteReceived((status_t) errorStatus64);
41110cd325cSAndrew Lindesay 			else
412fa5c8097SAndrew Lindesay 				HDERROR("expected [%s] value in message", KEY_ERROR_STATUS);
41304c9d578SStephan Aßmus 			break;
41410cd325cSAndrew Lindesay 		}
41504c9d578SStephan Aßmus 		case B_SIMPLE_DATA:
41604c9d578SStephan Aßmus 		case B_REFS_RECEIVED:
41704c9d578SStephan Aßmus 			// TODO: ?
41804c9d578SStephan Aßmus 			break;
41904c9d578SStephan Aßmus 
42004c9d578SStephan Aßmus 		case B_PACKAGE_UPDATE:
421f32d5c5cSAndrew Lindesay 			_HandleExternalPackageUpdateMessageReceived(message);
42204c9d578SStephan Aßmus 			break;
42304c9d578SStephan Aßmus 
4245bf2b6ebSBrian Hill 		case MSG_REFRESH_REPOS:
4253369e03dSAndrew Lindesay 			_StartBulkLoad(true);
4263369e03dSAndrew Lindesay 			break;
4273369e03dSAndrew Lindesay 
42810cd325cSAndrew Lindesay 		case MSG_WORK_STATUS_CLEAR:
42910cd325cSAndrew Lindesay 			_HandleWorkStatusClear();
43010cd325cSAndrew Lindesay 			break;
43110cd325cSAndrew Lindesay 
4323369e03dSAndrew Lindesay 		case MSG_WORK_STATUS_CHANGE:
4333369e03dSAndrew Lindesay 			_HandleWorkStatusChangeMessageReceived(message);
43404c9d578SStephan Aßmus 			break;
43504c9d578SStephan Aßmus 
4365bf2b6ebSBrian Hill 		case MSG_MANAGE_REPOS:
4375bf2b6ebSBrian Hill 			be_roster->Launch("application/x-vnd.Haiku-Repositories");
4385bf2b6ebSBrian Hill 			break;
4395bf2b6ebSBrian Hill 
440d144f952SAugustin Cavalier 		case MSG_SOFTWARE_UPDATER:
441d144f952SAugustin Cavalier 			be_roster->Launch("application/x-vnd.haiku-softwareupdater");
442d144f952SAugustin Cavalier 			break;
443d144f952SAugustin Cavalier 
44404c9d578SStephan Aßmus 		case MSG_LOG_IN:
4451bbda92dSStephan Aßmus 			_OpenLoginWindow(BMessage());
44604c9d578SStephan Aßmus 			break;
44704c9d578SStephan Aßmus 
448133ebab6SAndrew Lindesay 		case MSG_SETTINGS:
449133ebab6SAndrew Lindesay 			_OpenSettingsWindow();
450133ebab6SAndrew Lindesay 			break;
451133ebab6SAndrew Lindesay 
4528f03a0f9SStephan Aßmus 		case MSG_LOG_OUT:
453d2d4866dSAndrew Lindesay 			fModel.SetNickname("");
4548f03a0f9SStephan Aßmus 			break;
4558f03a0f9SStephan Aßmus 
45601339a54SAndrew Lindesay 		case MSG_VIEW_LATEST_USER_USAGE_CONDITIONS:
457d2d4866dSAndrew Lindesay 			_ViewUserUsageConditions(LATEST);
458d2d4866dSAndrew Lindesay 			break;
459d2d4866dSAndrew Lindesay 
460d2d4866dSAndrew Lindesay 		case MSG_VIEW_USERS_USER_USAGE_CONDITIONS:
461d2d4866dSAndrew Lindesay 			_ViewUserUsageConditions(USER);
46201339a54SAndrew Lindesay 			break;
46301339a54SAndrew Lindesay 
4648f03a0f9SStephan Aßmus 		case MSG_AUTHORIZATION_CHANGED:
46510cd325cSAndrew Lindesay 			_StartUserVerify();
4668f03a0f9SStephan Aßmus 			_UpdateAuthorization();
4678f03a0f9SStephan Aßmus 			break;
4688f03a0f9SStephan Aßmus 
46988af15cfSAndrew Lindesay 		case MSG_SCREENSHOT_CACHED:
47088af15cfSAndrew Lindesay 			_HandleScreenshotCached(message);
47188af15cfSAndrew Lindesay 			break;
47288af15cfSAndrew Lindesay 
47389b16bb4SAndrew Lindesay 		case MSG_CATEGORIES_LIST_CHANGED:
47489b16bb4SAndrew Lindesay 			fFilterView->AdoptModel(fModel);
47589b16bb4SAndrew Lindesay 			break;
47689b16bb4SAndrew Lindesay 
477ccf707d0SAndrew Lindesay 		case MSG_CHANGE_PACKAGE_LIST_VIEW_MODE:
478ccf707d0SAndrew Lindesay 			_HandleChangePackageListViewMode();
4794fade61fSStephan Aßmus 			break;
4804fade61fSStephan Aßmus 
481fdec4227SStephan Aßmus 		case MSG_SHOW_AVAILABLE_PACKAGES:
482fdec4227SStephan Aßmus 			{
483fdec4227SStephan Aßmus 				BAutolock locker(fModel.Lock());
484363fc60bSAndrew Lindesay 				PackageFilterModel* filterModel = fModel.PackageFilter();
485363fc60bSAndrew Lindesay 				filterModel->SetShowAvailablePackages(!filterModel->ShowAvailablePackages());
486fdec4227SStephan Aßmus 			}
487fdec4227SStephan Aßmus 			_AdoptModel();
488fdec4227SStephan Aßmus 			break;
489fdec4227SStephan Aßmus 
490fdec4227SStephan Aßmus 		case MSG_SHOW_INSTALLED_PACKAGES:
491fdec4227SStephan Aßmus 			{
492fdec4227SStephan Aßmus 				BAutolock locker(fModel.Lock());
493363fc60bSAndrew Lindesay 				PackageFilterModel* filterModel = fModel.PackageFilter();
494363fc60bSAndrew Lindesay 				filterModel->SetShowInstalledPackages(!filterModel->ShowInstalledPackages());
495fdec4227SStephan Aßmus 			}
496fdec4227SStephan Aßmus 			_AdoptModel();
497fdec4227SStephan Aßmus 			break;
498fdec4227SStephan Aßmus 
49904c9d578SStephan Aßmus 		case MSG_SHOW_SOURCE_PACKAGES:
50004c9d578SStephan Aßmus 			{
50104c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
502363fc60bSAndrew Lindesay 				PackageFilterModel* filterModel = fModel.PackageFilter();
503363fc60bSAndrew Lindesay 				filterModel->SetShowSourcePackages(!filterModel->ShowSourcePackages());
50404c9d578SStephan Aßmus 			}
50504c9d578SStephan Aßmus 			_AdoptModel();
50604c9d578SStephan Aßmus 			break;
50704c9d578SStephan Aßmus 
50804c9d578SStephan Aßmus 		case MSG_SHOW_DEVELOP_PACKAGES:
50904c9d578SStephan Aßmus 			{
51004c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
511363fc60bSAndrew Lindesay 				PackageFilterModel* filterModel = fModel.PackageFilter();
512363fc60bSAndrew Lindesay 				filterModel->SetShowDevelopPackages(!filterModel->ShowDevelopPackages());
51304c9d578SStephan Aßmus 			}
51404c9d578SStephan Aßmus 			_AdoptModel();
51504c9d578SStephan Aßmus 			break;
51604c9d578SStephan Aßmus 
517a9edb9bfSAndrew Lindesay 			// this may be triggered by, for example, a user rating being added
518a9edb9bfSAndrew Lindesay 			// or having been altered.
519a9edb9bfSAndrew Lindesay 		case MSG_SERVER_DATA_CHANGED:
520a9edb9bfSAndrew Lindesay 		{
521a9edb9bfSAndrew Lindesay 			BString name;
522a9edb9bfSAndrew Lindesay 			if (message->FindString("name", &name) == B_OK) {
523a9edb9bfSAndrew Lindesay 				BAutolock locker(fModel.Lock());
524a9edb9bfSAndrew Lindesay 				if (fPackageInfoView->Package()->Name() == name) {
525a9edb9bfSAndrew Lindesay 					_PopulatePackageAsync(true);
526a9edb9bfSAndrew Lindesay 				} else {
527f96d1f4dSAndrew Lindesay 					HDDEBUG("pkg [%s] is updated on the server, but is "
528f96d1f4dSAndrew Lindesay 						"not selected so will not be updated.",
529fa5c8097SAndrew Lindesay 						name.String());
530a9edb9bfSAndrew Lindesay 				}
531a9edb9bfSAndrew Lindesay 			}
532a9edb9bfSAndrew Lindesay 			break;
533a9edb9bfSAndrew Lindesay 		}
534a9edb9bfSAndrew Lindesay 
53584674570SAndrew Lindesay 		case MSG_INCREMENT_VIEW_COUNTER:
53684674570SAndrew Lindesay 			_HandleIncrementViewCounter(message);
53784674570SAndrew Lindesay 			break;
53884674570SAndrew Lindesay 
53904c9d578SStephan Aßmus 		case MSG_PACKAGE_SELECTED:
54004c9d578SStephan Aßmus 		{
54172992391SStephan Aßmus 			BString name;
54272992391SStephan Aßmus 			if (message->FindString("name", &name) == B_OK) {
543c4199192SAndrew Lindesay 				PackageInfoRef package;
544c4199192SAndrew Lindesay 				{
54575ba9dbfSStephan Aßmus 					BAutolock locker(fModel.Lock());
546c4199192SAndrew Lindesay 					package = fModel.PackageForName(name);
547c4199192SAndrew Lindesay 				}
5486f07feadSAndrew Lindesay 				if (!package.IsSet() || name != package->Name())
549c4199192SAndrew Lindesay 					debugger("unable to find the named package");
550133ebab6SAndrew Lindesay 				else {
55104c9d578SStephan Aßmus 					_AdoptPackage(package);
55284674570SAndrew Lindesay 					_SetupDelayedIncrementViewCounter(package);
553133ebab6SAndrew Lindesay 				}
55404c9d578SStephan Aßmus 			} else {
55504c9d578SStephan Aßmus 				_ClearPackage();
55604c9d578SStephan Aßmus 			}
55704c9d578SStephan Aßmus 			break;
55804c9d578SStephan Aßmus 		}
55904c9d578SStephan Aßmus 
56004c9d578SStephan Aßmus 		case MSG_CATEGORY_SELECTED:
56104c9d578SStephan Aßmus 		{
56289b16bb4SAndrew Lindesay 			BString code;
56389b16bb4SAndrew Lindesay 			if (message->FindString("code", &code) != B_OK)
56489b16bb4SAndrew Lindesay 				code = "";
56504c9d578SStephan Aßmus 			{
56604c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
567363fc60bSAndrew Lindesay 				fModel.PackageFilter()->SetCategory(code);
56804c9d578SStephan Aßmus 			}
56904c9d578SStephan Aßmus 			_AdoptModel();
57004c9d578SStephan Aßmus 			break;
57104c9d578SStephan Aßmus 		}
57204c9d578SStephan Aßmus 
57304c9d578SStephan Aßmus 		case MSG_DEPOT_SELECTED:
57404c9d578SStephan Aßmus 		{
57504c9d578SStephan Aßmus 			BString name;
57604c9d578SStephan Aßmus 			if (message->FindString("name", &name) != B_OK)
57704c9d578SStephan Aßmus 				name = "";
57804c9d578SStephan Aßmus 			{
57904c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
580363fc60bSAndrew Lindesay 				fModel.PackageFilter()->SetDepotName(name);
58104c9d578SStephan Aßmus 			}
58204c9d578SStephan Aßmus 			_AdoptModel();
583b965ce70SHumdinger 			_UpdateAvailableRepositories();
58404c9d578SStephan Aßmus 			break;
58504c9d578SStephan Aßmus 		}
58604c9d578SStephan Aßmus 
58704c9d578SStephan Aßmus 		case MSG_SEARCH_TERMS_MODIFIED:
58804c9d578SStephan Aßmus 		{
58904c9d578SStephan Aßmus 			// TODO: Do this with a delay!
59004c9d578SStephan Aßmus 			BString searchTerms;
59104c9d578SStephan Aßmus 			if (message->FindString("search terms", &searchTerms) != B_OK)
59204c9d578SStephan Aßmus 				searchTerms = "";
59304c9d578SStephan Aßmus 			{
59404c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
595363fc60bSAndrew Lindesay 				fModel.PackageFilter()->SetSearchTerms(searchTerms);
59604c9d578SStephan Aßmus 			}
59704c9d578SStephan Aßmus 			_AdoptModel();
59804c9d578SStephan Aßmus 			break;
59904c9d578SStephan Aßmus 		}
60004c9d578SStephan Aßmus 
601da651104SStephan Aßmus 		case MSG_PACKAGE_CHANGED:
60204c9d578SStephan Aßmus 		{
60304c9d578SStephan Aßmus 			PackageInfo* info;
60404c9d578SStephan Aßmus 			if (message->FindPointer("package", (void**)&info) == B_OK) {
60504c9d578SStephan Aßmus 				PackageInfoRef ref(info, true);
6060b69420bSAndrew Lindesay 				fFeaturedPackagesView->BeginAddRemove();
607c4199192SAndrew Lindesay 				_AddRemovePackageFromLists(ref);
6080b69420bSAndrew Lindesay 				fFeaturedPackagesView->EndAddRemove();
60910cd325cSAndrew Lindesay 			}
61004c9d578SStephan Aßmus 			break;
61104c9d578SStephan Aßmus 		}
61204c9d578SStephan Aßmus 
613409af934SAndrew Lindesay 		case MSG_PROCESS_COORDINATOR_CHANGED:
614409af934SAndrew Lindesay 		{
615409af934SAndrew Lindesay 			ProcessCoordinatorState state(message);
616409af934SAndrew Lindesay 			_HandleProcessCoordinatorChanged(state);
617409af934SAndrew Lindesay 			break;
618409af934SAndrew Lindesay 		}
619409af934SAndrew Lindesay 
62004c9d578SStephan Aßmus 		case MSG_RATE_PACKAGE:
6211bbda92dSStephan Aßmus 			_RatePackage();
62204c9d578SStephan Aßmus 			break;
62304c9d578SStephan Aßmus 
624d5ef985eSStephan Aßmus 		case MSG_SHOW_SCREENSHOT:
625d5ef985eSStephan Aßmus 			_ShowScreenshot();
626d5ef985eSStephan Aßmus 			break;
627d5ef985eSStephan Aßmus 
628125d42d9SJulian Harnath 		case MSG_PACKAGE_WORKER_BUSY:
629125d42d9SJulian Harnath 		{
630125d42d9SJulian Harnath 			BString reason;
631125d42d9SJulian Harnath 			status_t status = message->FindString("reason", &reason);
632125d42d9SJulian Harnath 			if (status != B_OK)
633125d42d9SJulian Harnath 				break;
634125d42d9SJulian Harnath 			fWorkStatusView->SetBusy(reason);
635125d42d9SJulian Harnath 			break;
636125d42d9SJulian Harnath 		}
637125d42d9SJulian Harnath 
638125d42d9SJulian Harnath 		case MSG_PACKAGE_WORKER_IDLE:
639125d42d9SJulian Harnath 			fWorkStatusView->SetIdle();
640125d42d9SJulian Harnath 			break;
641125d42d9SJulian Harnath 
64210cd325cSAndrew Lindesay 		case MSG_USER_USAGE_CONDITIONS_NOT_LATEST:
64310cd325cSAndrew Lindesay 		{
64410cd325cSAndrew Lindesay 			BMessage userDetailMsg;
64510cd325cSAndrew Lindesay 			if (message->FindMessage("userDetail", &userDetailMsg) != B_OK) {
64610cd325cSAndrew Lindesay 				debugger("expected the [userDetail] data to be carried in the "
64710cd325cSAndrew Lindesay 					"message.");
64810cd325cSAndrew Lindesay 			}
64910cd325cSAndrew Lindesay 			UserDetail userDetail(&userDetailMsg);
65010cd325cSAndrew Lindesay 			_HandleUserUsageConditionsNotLatest(userDetail);
65110cd325cSAndrew Lindesay 			break;
65210cd325cSAndrew Lindesay 		}
65310cd325cSAndrew Lindesay 
65404c9d578SStephan Aßmus 		default:
65504c9d578SStephan Aßmus 			BWindow::MessageReceived(message);
65604c9d578SStephan Aßmus 			break;
65704c9d578SStephan Aßmus 	}
65804c9d578SStephan Aßmus }
65904c9d578SStephan Aßmus 
66004c9d578SStephan Aßmus 
661ccf707d0SAndrew Lindesay static const char*
662ccf707d0SAndrew Lindesay main_window_package_list_view_mode_str(package_list_view_mode mode)
663ccf707d0SAndrew Lindesay {
664ccf707d0SAndrew Lindesay 	if (mode == PROMINENT)
665ccf707d0SAndrew Lindesay 		return "PROMINENT";
666ccf707d0SAndrew Lindesay 	return "ALL";
667ccf707d0SAndrew Lindesay }
668ccf707d0SAndrew Lindesay 
669ccf707d0SAndrew Lindesay 
670ccf707d0SAndrew Lindesay static package_list_view_mode
671ccf707d0SAndrew Lindesay main_window_str_to_package_list_view_mode(const BString& str)
672ccf707d0SAndrew Lindesay {
673ccf707d0SAndrew Lindesay 	if (str == "PROMINENT")
674ccf707d0SAndrew Lindesay 		return PROMINENT;
675ccf707d0SAndrew Lindesay 	return ALL;
676ccf707d0SAndrew Lindesay }
677ccf707d0SAndrew Lindesay 
678ccf707d0SAndrew Lindesay 
67904c9d578SStephan Aßmus void
6804b347fccSAndrew Lindesay MainWindow::StoreSettings(BMessage& settings)
68104c9d578SStephan Aßmus {
682f7c2983eSAxel Dörfler 	settings.AddRect(_WindowFrameName(), Frame());
683f7c2983eSAxel Dörfler 	if (!fSinglePackageMode) {
68404c9d578SStephan Aßmus 		settings.AddRect("window frame", Frame());
68504c9d578SStephan Aßmus 
68604c9d578SStephan Aßmus 		BMessage columnSettings;
6879883929bSAndrew Lindesay 		if (fPackageListView != NULL)
68804c9d578SStephan Aßmus 			fPackageListView->SaveState(&columnSettings);
68904c9d578SStephan Aßmus 
69004c9d578SStephan Aßmus 		settings.AddMessage("column settings", &columnSettings);
69104c9d578SStephan Aßmus 
692133ebab6SAndrew Lindesay 		settings.AddString(SETTING_PACKAGE_LIST_VIEW_MODE,
693ccf707d0SAndrew Lindesay 			main_window_package_list_view_mode_str(
694ccf707d0SAndrew Lindesay 				fModel.PackageListViewMode()));
695363fc60bSAndrew Lindesay 
696133ebab6SAndrew Lindesay 		settings.AddBool(SETTING_SHOW_AVAILABLE_PACKAGES,
697363fc60bSAndrew Lindesay 			fModel.PackageFilter()->ShowAvailablePackages());
698133ebab6SAndrew Lindesay 		settings.AddBool(SETTING_SHOW_INSTALLED_PACKAGES,
699363fc60bSAndrew Lindesay 			fModel.PackageFilter()->ShowInstalledPackages());
700133ebab6SAndrew Lindesay 		settings.AddBool(SETTING_SHOW_DEVELOP_PACKAGES,
701363fc60bSAndrew Lindesay 			fModel.PackageFilter()->ShowDevelopPackages());
702133ebab6SAndrew Lindesay 		settings.AddBool(SETTING_SHOW_SOURCE_PACKAGES,
703363fc60bSAndrew Lindesay 			fModel.PackageFilter()->ShowSourcePackages());
704363fc60bSAndrew Lindesay 
705133ebab6SAndrew Lindesay 		settings.AddBool(SETTING_CAN_SHARE_ANONYMOUS_USER_DATA,
706133ebab6SAndrew Lindesay 			fModel.CanShareAnonymousUsageData());
7076d519fd1SStephan Aßmus 	}
7088f03a0f9SStephan Aßmus 
709d2d4866dSAndrew Lindesay 	settings.AddString("username", fModel.Nickname());
71004c9d578SStephan Aßmus }
71104c9d578SStephan Aßmus 
71204c9d578SStephan Aßmus 
71304c9d578SStephan Aßmus void
714a18f873fSAndrew Lindesay MainWindow::Consume(ProcessCoordinator *item)
715a18f873fSAndrew Lindesay {
716a18f873fSAndrew Lindesay 	_AddProcessCoordinator(item);
717a18f873fSAndrew Lindesay }
718a18f873fSAndrew Lindesay 
719a18f873fSAndrew Lindesay 
720a18f873fSAndrew Lindesay void
72104c9d578SStephan Aßmus MainWindow::PackageChanged(const PackageInfoEvent& event)
72204c9d578SStephan Aßmus {
723*8cc3ed34SAndrew Lindesay 	uint32 watchedChanges = PKG_CHANGED_STATE | PKG_CHANGED_CLASSIFICATION;
724a9edb9bfSAndrew Lindesay 	if ((event.Changes() & watchedChanges) != 0) {
72504c9d578SStephan Aßmus 		PackageInfoRef ref(event.Package());
726da651104SStephan Aßmus 		BMessage message(MSG_PACKAGE_CHANGED);
72704c9d578SStephan Aßmus 		message.AddPointer("package", ref.Get());
72804c9d578SStephan Aßmus 		ref.Detach();
72904c9d578SStephan Aßmus 			// reference needs to be released by MessageReceived();
73004c9d578SStephan Aßmus 		PostMessage(&message);
73104c9d578SStephan Aßmus 	}
73204c9d578SStephan Aßmus }
73304c9d578SStephan Aßmus 
73404c9d578SStephan Aßmus 
73504c9d578SStephan Aßmus void
73604c9d578SStephan Aßmus MainWindow::_BuildMenu(BMenuBar* menuBar)
73704c9d578SStephan Aßmus {
7380b6928f1SHumdinger 	BMenu* menu = new BMenu(B_TRANSLATE_SYSTEM_NAME("HaikuDepot"));
7393369e03dSAndrew Lindesay 	fRefreshRepositoriesItem = new BMenuItem(
7403369e03dSAndrew Lindesay 		B_TRANSLATE("Refresh repositories"), new BMessage(MSG_REFRESH_REPOS));
7413369e03dSAndrew Lindesay 	menu->AddItem(fRefreshRepositoriesItem);
742d7f78130SHumdinger 	menu->AddItem(new BMenuItem(B_TRANSLATE("Manage repositories"
743d7f78130SHumdinger 		B_UTF8_ELLIPSIS), new BMessage(MSG_MANAGE_REPOS)));
744d144f952SAugustin Cavalier 	menu->AddItem(new BMenuItem(B_TRANSLATE("Check for updates"
745d144f952SAugustin Cavalier 		B_UTF8_ELLIPSIS), new BMessage(MSG_SOFTWARE_UPDATER)));
7460b6928f1SHumdinger 	menu->AddSeparatorItem();
7470b6928f1SHumdinger 	menu->AddItem(new BMenuItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS),
748e1ae57abSJoachim Mairböck 		new BMessage(MSG_SETTINGS), ','));
7490b6928f1SHumdinger 	menu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
7500b6928f1SHumdinger 		new BMessage(B_QUIT_REQUESTED), 'Q'));
75104c9d578SStephan Aßmus 	menuBar->AddItem(menu);
75204c9d578SStephan Aßmus 
753b965ce70SHumdinger 	fRepositoryMenu = new BMenu(B_TRANSLATE("Repositories"));
754b965ce70SHumdinger 	menuBar->AddItem(fRepositoryMenu);
755b965ce70SHumdinger 
7564fade61fSStephan Aßmus 	menu = new BMenu(B_TRANSLATE("Show"));
7574fade61fSStephan Aßmus 
758fdec4227SStephan Aßmus 	fShowAvailablePackagesItem = new BMenuItem(
7594fade61fSStephan Aßmus 		B_TRANSLATE("Available packages"),
760fdec4227SStephan Aßmus 		new BMessage(MSG_SHOW_AVAILABLE_PACKAGES));
761fdec4227SStephan Aßmus 	menu->AddItem(fShowAvailablePackagesItem);
762fdec4227SStephan Aßmus 
763fdec4227SStephan Aßmus 	fShowInstalledPackagesItem = new BMenuItem(
7644fade61fSStephan Aßmus 		B_TRANSLATE("Installed packages"),
765fdec4227SStephan Aßmus 		new BMessage(MSG_SHOW_INSTALLED_PACKAGES));
766fdec4227SStephan Aßmus 	menu->AddItem(fShowInstalledPackagesItem);
767fdec4227SStephan Aßmus 
768fdec4227SStephan Aßmus 	menu->AddSeparatorItem();
769fdec4227SStephan Aßmus 
770fdec4227SStephan Aßmus 	fShowDevelopPackagesItem = new BMenuItem(
7714fade61fSStephan Aßmus 		B_TRANSLATE("Develop packages"),
772fdec4227SStephan Aßmus 		new BMessage(MSG_SHOW_DEVELOP_PACKAGES));
773fdec4227SStephan Aßmus 	menu->AddItem(fShowDevelopPackagesItem);
774fdec4227SStephan Aßmus 
775fdec4227SStephan Aßmus 	fShowSourcePackagesItem = new BMenuItem(
7764fade61fSStephan Aßmus 		B_TRANSLATE("Source packages"),
777fdec4227SStephan Aßmus 		new BMessage(MSG_SHOW_SOURCE_PACKAGES));
778fdec4227SStephan Aßmus 	menu->AddItem(fShowSourcePackagesItem);
779fdec4227SStephan Aßmus 
780fdec4227SStephan Aßmus 	menuBar->AddItem(menu);
78104c9d578SStephan Aßmus }
78204c9d578SStephan Aßmus 
78304c9d578SStephan Aßmus 
78404c9d578SStephan Aßmus void
785e0a26dceSStephan Aßmus MainWindow::_BuildUserMenu(BMenuBar* menuBar)
786e0a26dceSStephan Aßmus {
787e0a26dceSStephan Aßmus 	fUserMenu = new BMenu(B_TRANSLATE("Not logged in"));
788e0a26dceSStephan Aßmus 
789e0a26dceSStephan Aßmus 	fLogInItem = new BMenuItem(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS),
790e0a26dceSStephan Aßmus 		new BMessage(MSG_LOG_IN));
791e0a26dceSStephan Aßmus 	fUserMenu->AddItem(fLogInItem);
792e0a26dceSStephan Aßmus 
793e0a26dceSStephan Aßmus 	fLogOutItem = new BMenuItem(B_TRANSLATE("Log out"),
794e0a26dceSStephan Aßmus 		new BMessage(MSG_LOG_OUT));
795e0a26dceSStephan Aßmus 	fUserMenu->AddItem(fLogOutItem);
796e0a26dceSStephan Aßmus 
7970c82f64bSAndrew Lindesay 	BMenuItem *latestUserUsageConditionsMenuItem =
7981448ced0SHumdinger 		new BMenuItem(B_TRANSLATE("View latest usage conditions"
79901339a54SAndrew Lindesay 			B_UTF8_ELLIPSIS),
80001339a54SAndrew Lindesay 			new BMessage(MSG_VIEW_LATEST_USER_USAGE_CONDITIONS));
8010c82f64bSAndrew Lindesay 	fUserMenu->AddItem(latestUserUsageConditionsMenuItem);
80201339a54SAndrew Lindesay 
803d2d4866dSAndrew Lindesay 	fUsersUserUsageConditionsMenuItem =
804d2d4866dSAndrew Lindesay 		new BMenuItem(B_TRANSLATE("View agreed usage conditions"
805d2d4866dSAndrew Lindesay 			B_UTF8_ELLIPSIS),
806d2d4866dSAndrew Lindesay 			new BMessage(MSG_VIEW_USERS_USER_USAGE_CONDITIONS));
807d2d4866dSAndrew Lindesay 	fUserMenu->AddItem(fUsersUserUsageConditionsMenuItem);
808d2d4866dSAndrew Lindesay 
809e0a26dceSStephan Aßmus 	menuBar->AddItem(fUserMenu);
810e0a26dceSStephan Aßmus }
811e0a26dceSStephan Aßmus 
812e0a26dceSStephan Aßmus 
813e0a26dceSStephan Aßmus void
814d2d4866dSAndrew Lindesay MainWindow::_RestoreNickname(const BMessage& settings)
815f7c2983eSAxel Dörfler {
816d2d4866dSAndrew Lindesay 	BString nickname;
817d2d4866dSAndrew Lindesay 	if (settings.FindString("username", &nickname) == B_OK
818d2d4866dSAndrew Lindesay 		&& nickname.Length() > 0) {
819d2d4866dSAndrew Lindesay 		fModel.SetNickname(nickname);
820f7c2983eSAxel Dörfler 	}
821f7c2983eSAxel Dörfler }
822f7c2983eSAxel Dörfler 
823f7c2983eSAxel Dörfler 
824f7c2983eSAxel Dörfler const char*
825f7c2983eSAxel Dörfler MainWindow::_WindowFrameName() const
826f7c2983eSAxel Dörfler {
827f7c2983eSAxel Dörfler 	if (fSinglePackageMode)
828f7c2983eSAxel Dörfler 		return "small window frame";
829f7c2983eSAxel Dörfler 
830f7c2983eSAxel Dörfler 	return "window frame";
831f7c2983eSAxel Dörfler }
832f7c2983eSAxel Dörfler 
833f7c2983eSAxel Dörfler 
834f7c2983eSAxel Dörfler void
835f7c2983eSAxel Dörfler MainWindow::_RestoreWindowFrame(const BMessage& settings)
836f7c2983eSAxel Dörfler {
837f7c2983eSAxel Dörfler 	BRect frame = Frame();
838f7c2983eSAxel Dörfler 
839f7c2983eSAxel Dörfler 	BRect windowFrame;
840f7c2983eSAxel Dörfler 	bool fromSettings = false;
841f7c2983eSAxel Dörfler 	if (settings.FindRect(_WindowFrameName(), &windowFrame) == B_OK) {
842f7c2983eSAxel Dörfler 		frame = windowFrame;
843f7c2983eSAxel Dörfler 		fromSettings = true;
844f7c2983eSAxel Dörfler 	} else if (!fSinglePackageMode) {
845f7c2983eSAxel Dörfler 		// Resize to occupy a certain screen size
846f7c2983eSAxel Dörfler 		BRect screenFrame = BScreen(this).Frame();
847f7c2983eSAxel Dörfler 		float width = frame.Width();
848f7c2983eSAxel Dörfler 		float height = frame.Height();
849f7c2983eSAxel Dörfler 		if (width < screenFrame.Width() * .666f
850f7c2983eSAxel Dörfler 			&& height < screenFrame.Height() * .666f) {
851f7c2983eSAxel Dörfler 			frame.bottom = frame.top + screenFrame.Height() * .666f;
852f7c2983eSAxel Dörfler 			frame.right = frame.left
853f7c2983eSAxel Dörfler 				+ std::min(screenFrame.Width() * .666f, height * 7 / 5);
854f7c2983eSAxel Dörfler 		}
855f7c2983eSAxel Dörfler 	}
856f7c2983eSAxel Dörfler 
857f7c2983eSAxel Dörfler 	MoveTo(frame.LeftTop());
858f7c2983eSAxel Dörfler 	ResizeTo(frame.Width(), frame.Height());
859f7c2983eSAxel Dörfler 
860f7c2983eSAxel Dörfler 	if (fromSettings)
8618e96ec34SAxel Dörfler 		MoveOnScreen();
862f7c2983eSAxel Dörfler 	else
863f7c2983eSAxel Dörfler 		CenterOnScreen();
864f7c2983eSAxel Dörfler }
865f7c2983eSAxel Dörfler 
866f7c2983eSAxel Dörfler 
867f7c2983eSAxel Dörfler void
868ccf707d0SAndrew Lindesay MainWindow::_RestoreModelSettings(const BMessage& settings)
869ccf707d0SAndrew Lindesay {
870ccf707d0SAndrew Lindesay 	BString packageListViewMode;
871133ebab6SAndrew Lindesay 	if (settings.FindString(SETTING_PACKAGE_LIST_VIEW_MODE,
872ccf707d0SAndrew Lindesay 			&packageListViewMode) == B_OK) {
873ccf707d0SAndrew Lindesay 		fModel.SetPackageListViewMode(
874ccf707d0SAndrew Lindesay 			main_window_str_to_package_list_view_mode(packageListViewMode));
875ccf707d0SAndrew Lindesay 	}
876ccf707d0SAndrew Lindesay 
877ccf707d0SAndrew Lindesay 	bool showOption;
878363fc60bSAndrew Lindesay 
879133ebab6SAndrew Lindesay 	if (settings.FindBool(SETTING_SHOW_AVAILABLE_PACKAGES, &showOption) == B_OK)
880363fc60bSAndrew Lindesay 		fModel.PackageFilter()->SetShowAvailablePackages(showOption);
881133ebab6SAndrew Lindesay 	if (settings.FindBool(SETTING_SHOW_INSTALLED_PACKAGES, &showOption) == B_OK)
882363fc60bSAndrew Lindesay 		fModel.PackageFilter()->SetShowInstalledPackages(showOption);
883133ebab6SAndrew Lindesay 	if (settings.FindBool(SETTING_SHOW_DEVELOP_PACKAGES, &showOption) == B_OK)
884363fc60bSAndrew Lindesay 		fModel.PackageFilter()->SetShowDevelopPackages(showOption);
885133ebab6SAndrew Lindesay 	if (settings.FindBool(SETTING_SHOW_SOURCE_PACKAGES, &showOption) == B_OK)
886363fc60bSAndrew Lindesay 		fModel.PackageFilter()->SetShowSourcePackages(showOption);
887363fc60bSAndrew Lindesay 
888133ebab6SAndrew Lindesay 	if (settings.FindBool(SETTING_CAN_SHARE_ANONYMOUS_USER_DATA,
889133ebab6SAndrew Lindesay 			&showOption) == B_OK) {
890133ebab6SAndrew Lindesay 		fModel.SetCanShareAnonymousUsageData(showOption);
891133ebab6SAndrew Lindesay 	}
892133ebab6SAndrew Lindesay }
893133ebab6SAndrew Lindesay 
894133ebab6SAndrew Lindesay 
895133ebab6SAndrew Lindesay void
896133ebab6SAndrew Lindesay MainWindow::_MaybePromptCanShareAnonymousUserData(const BMessage& settings)
897133ebab6SAndrew Lindesay {
898133ebab6SAndrew Lindesay 	bool showOption;
899133ebab6SAndrew Lindesay 	if (settings.FindBool(SETTING_CAN_SHARE_ANONYMOUS_USER_DATA,
900133ebab6SAndrew Lindesay 			&showOption) == B_NAME_NOT_FOUND) {
901133ebab6SAndrew Lindesay 		_PromptCanShareAnonymousUserData();
902133ebab6SAndrew Lindesay 	}
903133ebab6SAndrew Lindesay }
904133ebab6SAndrew Lindesay 
905133ebab6SAndrew Lindesay 
906133ebab6SAndrew Lindesay void
907133ebab6SAndrew Lindesay MainWindow::_PromptCanShareAnonymousUserData()
908133ebab6SAndrew Lindesay {
909133ebab6SAndrew Lindesay 	BAlert* alert = new(std::nothrow) BAlert(
910133ebab6SAndrew Lindesay 		B_TRANSLATE("Sending anonymous usage data"),
911133ebab6SAndrew Lindesay 		B_TRANSLATE("Would it be acceptable to send anonymous usage data to the"
912133ebab6SAndrew Lindesay 			" HaikuDepotServer system from this computer? You can change your"
913133ebab6SAndrew Lindesay 			" preference in the \"Settings\" window later."),
914133ebab6SAndrew Lindesay 		B_TRANSLATE("No"),
915133ebab6SAndrew Lindesay 		B_TRANSLATE("Yes"));
916133ebab6SAndrew Lindesay 
917133ebab6SAndrew Lindesay 	int32 result = alert->Go();
918133ebab6SAndrew Lindesay 	fModel.SetCanShareAnonymousUsageData(1 == result);
919ccf707d0SAndrew Lindesay }
920ccf707d0SAndrew Lindesay 
921ccf707d0SAndrew Lindesay 
922ccf707d0SAndrew Lindesay void
923d668d227SAndrew Lindesay MainWindow::_InitPreferredLanguage()
924d668d227SAndrew Lindesay {
925d668d227SAndrew Lindesay 	LanguageRepository* repository = fModel.Languages();
926d668d227SAndrew Lindesay 	LanguageRef defaultLanguage = LocaleUtils::DeriveDefaultLanguage(repository);
927d668d227SAndrew Lindesay 	repository->AddLanguage(defaultLanguage);
928d668d227SAndrew Lindesay 	fModel.SetPreferredLanguage(defaultLanguage);
929d668d227SAndrew Lindesay }
930d668d227SAndrew Lindesay 
931d668d227SAndrew Lindesay 
932d668d227SAndrew Lindesay void
933c4199192SAndrew Lindesay MainWindow::_AdoptModelControls()
93404c9d578SStephan Aßmus {
9359883929bSAndrew Lindesay 	if (fSinglePackageMode)
9369883929bSAndrew Lindesay 		return;
9379883929bSAndrew Lindesay 
93804c9d578SStephan Aßmus 	BAutolock locker(fModel.Lock());
939363fc60bSAndrew Lindesay 	fShowAvailablePackagesItem->SetMarked(fModel.PackageFilter()->ShowAvailablePackages());
940363fc60bSAndrew Lindesay 	fShowInstalledPackagesItem->SetMarked(fModel.PackageFilter()->ShowInstalledPackages());
941363fc60bSAndrew Lindesay 	fShowSourcePackagesItem->SetMarked(fModel.PackageFilter()->ShowSourcePackages());
942363fc60bSAndrew Lindesay 	fShowDevelopPackagesItem->SetMarked(fModel.PackageFilter()->ShowDevelopPackages());
943da651104SStephan Aßmus 
944ccf707d0SAndrew Lindesay 	if (fModel.PackageListViewMode() == PROMINENT)
945ccf707d0SAndrew Lindesay 		fListTabs->Select(TAB_PROMINENT_PACKAGES);
9464fade61fSStephan Aßmus 	else
947ccf707d0SAndrew Lindesay 		fListTabs->Select(TAB_ALL_PACKAGES);
948b965ce70SHumdinger 
949b965ce70SHumdinger 	fFilterView->AdoptModel(fModel);
95004c9d578SStephan Aßmus }
95104c9d578SStephan Aßmus 
95204c9d578SStephan Aßmus 
95304c9d578SStephan Aßmus void
954c4199192SAndrew Lindesay MainWindow::_AdoptModel()
955c4199192SAndrew Lindesay {
956fa5c8097SAndrew Lindesay 	HDTRACE("adopting model to main window ui");
957c4199192SAndrew Lindesay 
958c4199192SAndrew Lindesay 	if (fSinglePackageMode)
959c4199192SAndrew Lindesay 		return;
960c4199192SAndrew Lindesay 
96105880d13SAndrew Lindesay 	std::vector<DepotInfoRef> depots = _CreateSnapshotOfDepots();
96205880d13SAndrew Lindesay 	std::vector<DepotInfoRef>::iterator it;
9630b69420bSAndrew Lindesay 
9640b69420bSAndrew Lindesay 	fFeaturedPackagesView->BeginAddRemove();
9650b69420bSAndrew Lindesay 
96605880d13SAndrew Lindesay 	for (it = depots.begin(); it != depots.end(); it++) {
96705880d13SAndrew Lindesay 		DepotInfoRef depotInfoRef = *it;
968d75b4d61SAndrew Lindesay 		for (int i = 0; i < depotInfoRef->CountPackages(); i++) {
969d75b4d61SAndrew Lindesay 			PackageInfoRef package = depotInfoRef->PackageAtIndex(i);
970d75b4d61SAndrew Lindesay 			_AddRemovePackageFromLists(package);
971d75b4d61SAndrew Lindesay 		}
972c4199192SAndrew Lindesay 	}
973c4199192SAndrew Lindesay 
9740b69420bSAndrew Lindesay 	fFeaturedPackagesView->EndAddRemove();
9750b69420bSAndrew Lindesay 
976c4199192SAndrew Lindesay 	_AdoptModelControls();
977c4199192SAndrew Lindesay }
978c4199192SAndrew Lindesay 
979c4199192SAndrew Lindesay 
980c4199192SAndrew Lindesay void
981c4199192SAndrew Lindesay MainWindow::_AddRemovePackageFromLists(const PackageInfoRef& package)
982c4199192SAndrew Lindesay {
983c4199192SAndrew Lindesay 	bool matches;
984c4199192SAndrew Lindesay 
985c4199192SAndrew Lindesay 	{
986c4199192SAndrew Lindesay 		AutoLocker<BLocker> modelLocker(fModel.Lock());
987363fc60bSAndrew Lindesay 		matches = fModel.PackageFilter()->Filter()->AcceptsPackage(package);
988c4199192SAndrew Lindesay 	}
989c4199192SAndrew Lindesay 
990c4199192SAndrew Lindesay 	if (matches) {
991*8cc3ed34SAndrew Lindesay 		PackageClassificationInfoRef classification = package->PackageClassificationInfo();
992*8cc3ed34SAndrew Lindesay 
993*8cc3ed34SAndrew Lindesay 		if (classification.IsSet()) {
994*8cc3ed34SAndrew Lindesay 			if (classification->IsProminent())
995c4199192SAndrew Lindesay 				fFeaturedPackagesView->AddPackage(package);
996*8cc3ed34SAndrew Lindesay 		}
997*8cc3ed34SAndrew Lindesay 
998c4199192SAndrew Lindesay 		fPackageListView->AddPackage(package);
999c4199192SAndrew Lindesay 	} else {
1000c4199192SAndrew Lindesay 		fFeaturedPackagesView->RemovePackage(package);
1001c4199192SAndrew Lindesay 		fPackageListView->RemovePackage(package);
1002c4199192SAndrew Lindesay 	}
1003c4199192SAndrew Lindesay }
1004c4199192SAndrew Lindesay 
1005c4199192SAndrew Lindesay 
1006c4199192SAndrew Lindesay void
100784674570SAndrew Lindesay MainWindow::_SetupDelayedIncrementViewCounter(const PackageInfoRef package) {
100884674570SAndrew Lindesay 	if (fIncrementViewCounterDelayedRunner != NULL) {
100984674570SAndrew Lindesay 		fIncrementViewCounterDelayedRunner->SetCount(0);
101084674570SAndrew Lindesay 		delete fIncrementViewCounterDelayedRunner;
101184674570SAndrew Lindesay 	}
101284674570SAndrew Lindesay 	BMessage message(MSG_INCREMENT_VIEW_COUNTER);
101384674570SAndrew Lindesay 	message.SetString("name", package->Name());
101484674570SAndrew Lindesay 	fIncrementViewCounterDelayedRunner =
101584674570SAndrew Lindesay 		new BMessageRunner(BMessenger(this), &message,
101684674570SAndrew Lindesay 			kIncrementViewCounterDelayMicros, 1);
101784674570SAndrew Lindesay 	if (fIncrementViewCounterDelayedRunner->InitCheck()
101884674570SAndrew Lindesay 			!= B_OK) {
101984674570SAndrew Lindesay 		HDERROR("unable to init the increment view counter");
102084674570SAndrew Lindesay 	}
102184674570SAndrew Lindesay }
102284674570SAndrew Lindesay 
102384674570SAndrew Lindesay 
102484674570SAndrew Lindesay void
102584674570SAndrew Lindesay MainWindow::_HandleIncrementViewCounter(const BMessage* message)
102684674570SAndrew Lindesay {
102784674570SAndrew Lindesay 	BString name;
102884674570SAndrew Lindesay 	if (message->FindString("name", &name) == B_OK) {
102984674570SAndrew Lindesay 		const PackageInfoRef& viewedPackage =
103084674570SAndrew Lindesay 			fPackageInfoView->Package();
103184674570SAndrew Lindesay 		if (viewedPackage.IsSet()) {
103284674570SAndrew Lindesay 			if (viewedPackage->Name() == name)
103384674570SAndrew Lindesay 				_IncrementViewCounter(viewedPackage);
103484674570SAndrew Lindesay 			else
103584674570SAndrew Lindesay 				HDINFO("incr. view counter; name mismatch");
103684674570SAndrew Lindesay 		} else
103784674570SAndrew Lindesay 			HDINFO("incr. view counter; no viewed pkg");
103884674570SAndrew Lindesay 	} else
103984674570SAndrew Lindesay 		HDERROR("incr. view counter; no name");
104084674570SAndrew Lindesay 	fIncrementViewCounterDelayedRunner->SetCount(0);
104184674570SAndrew Lindesay 	delete fIncrementViewCounterDelayedRunner;
104284674570SAndrew Lindesay 	fIncrementViewCounterDelayedRunner = NULL;
104384674570SAndrew Lindesay }
104484674570SAndrew Lindesay 
104584674570SAndrew Lindesay 
104684674570SAndrew Lindesay void
1047409af934SAndrew Lindesay MainWindow::_IncrementViewCounter(const PackageInfoRef package)
1048133ebab6SAndrew Lindesay {
1049133ebab6SAndrew Lindesay 	bool shouldIncrementViewCounter = false;
1050133ebab6SAndrew Lindesay 
1051133ebab6SAndrew Lindesay 	{
1052133ebab6SAndrew Lindesay 		AutoLocker<BLocker> modelLocker(fModel.Lock());
1053133ebab6SAndrew Lindesay 		bool canShareAnonymousUsageData = fModel.CanShareAnonymousUsageData();
1054133ebab6SAndrew Lindesay 		if (canShareAnonymousUsageData && !package->Viewed()) {
1055133ebab6SAndrew Lindesay 			package->SetViewed();
1056133ebab6SAndrew Lindesay 			shouldIncrementViewCounter = true;
1057133ebab6SAndrew Lindesay 		}
1058133ebab6SAndrew Lindesay 	}
1059133ebab6SAndrew Lindesay 
1060133ebab6SAndrew Lindesay 	if (shouldIncrementViewCounter) {
1061467ffecdSAugustin Cavalier 		ProcessCoordinator* incrementViewCoordinator =
1062133ebab6SAndrew Lindesay 			ProcessCoordinatorFactory::CreateIncrementViewCounter(
1063133ebab6SAndrew Lindesay 				&fModel, package);
1064467ffecdSAugustin Cavalier 		_AddProcessCoordinator(incrementViewCoordinator);
1065133ebab6SAndrew Lindesay 	}
1066133ebab6SAndrew Lindesay }
1067133ebab6SAndrew Lindesay 
1068133ebab6SAndrew Lindesay 
1069133ebab6SAndrew Lindesay void
107004c9d578SStephan Aßmus MainWindow::_AdoptPackage(const PackageInfoRef& package)
107104c9d578SStephan Aßmus {
107275ba9dbfSStephan Aßmus 	{
107375ba9dbfSStephan Aßmus 		BAutolock locker(fModel.Lock());
107404c9d578SStephan Aßmus 		fPackageInfoView->SetPackage(package);
10751986ab9fSStephan Aßmus 
1076664372abSStephan Aßmus 		if (fFeaturedPackagesView != NULL)
1077664372abSStephan Aßmus 			fFeaturedPackagesView->SelectPackage(package);
10781986ab9fSStephan Aßmus 		if (fPackageListView != NULL)
10791986ab9fSStephan Aßmus 			fPackageListView->SelectPackage(package);
108075ba9dbfSStephan Aßmus 	}
108104c9d578SStephan Aßmus 
1082a9edb9bfSAndrew Lindesay 	_PopulatePackageAsync(false);
108304c9d578SStephan Aßmus }
108404c9d578SStephan Aßmus 
108504c9d578SStephan Aßmus 
108604c9d578SStephan Aßmus void
108704c9d578SStephan Aßmus MainWindow::_ClearPackage()
108804c9d578SStephan Aßmus {
108904c9d578SStephan Aßmus 	fPackageInfoView->Clear();
109004c9d578SStephan Aßmus }
109104c9d578SStephan Aßmus 
109204c9d578SStephan Aßmus 
109304c9d578SStephan Aßmus void
10943369e03dSAndrew Lindesay MainWindow::_StartBulkLoad(bool force)
109504c9d578SStephan Aßmus {
1096c4199192SAndrew Lindesay 	if (fFeaturedPackagesView != NULL)
1097c4199192SAndrew Lindesay 		fFeaturedPackagesView->Clear();
1098c4199192SAndrew Lindesay 	if (fPackageListView != NULL)
1099c4199192SAndrew Lindesay 		fPackageListView->Clear();
1100c4199192SAndrew Lindesay 	fPackageInfoView->Clear();
1101c4199192SAndrew Lindesay 
110210cd325cSAndrew Lindesay 	fRefreshRepositoriesItem->SetEnabled(false);
110310cd325cSAndrew Lindesay 	ProcessCoordinator* bulkLoadCoordinator =
110410cd325cSAndrew Lindesay 		ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
1105409af934SAndrew Lindesay 			fPackageInfoListener, &fModel, force);
110610cd325cSAndrew Lindesay 	_AddProcessCoordinator(bulkLoadCoordinator);
110704c9d578SStephan Aßmus }
110804c9d578SStephan Aßmus 
110904c9d578SStephan Aßmus 
111004c9d578SStephan Aßmus void
111110cd325cSAndrew Lindesay MainWindow::_BulkLoadCompleteReceived(status_t errorStatus)
111204c9d578SStephan Aßmus {
111310cd325cSAndrew Lindesay 	if (errorStatus != B_OK) {
11143369e03dSAndrew Lindesay 		AppUtils::NotifySimpleError(
11151448ced0SHumdinger 			B_TRANSLATE("Package update error"),
11163369e03dSAndrew Lindesay 			B_TRANSLATE("While updating package data, a problem has arisen "
11173369e03dSAndrew Lindesay 				"that may cause data to be outdated or missing from the "
11183369e03dSAndrew Lindesay 				"application's display. Additional details regarding this "
11193369e03dSAndrew Lindesay 				"problem may be able to be obtained from the application "
1120b21c9447SAndrew Lindesay 				"logs."
1121b21c9447SAndrew Lindesay 				ALERT_MSG_LOGS_USER_GUIDE));
112204c9d578SStephan Aßmus 	}
112310cd325cSAndrew Lindesay 
11243369e03dSAndrew Lindesay 	fRefreshRepositoriesItem->SetEnabled(true);
112510cd325cSAndrew Lindesay 	_AdoptModel();
112610cd325cSAndrew Lindesay 	_UpdateAvailableRepositories();
1127ccf707d0SAndrew Lindesay 
1128ccf707d0SAndrew Lindesay 	// if after loading everything in, it transpires that there are no
1129ccf707d0SAndrew Lindesay 	// featured packages then the featured packages should be disabled
1130ccf707d0SAndrew Lindesay 	// and the user should be switched to the "all packages" view so
1131ccf707d0SAndrew Lindesay 	// that they are not presented with a blank window!
1132ccf707d0SAndrew Lindesay 
1133ccf707d0SAndrew Lindesay 	bool hasProminentPackages = fModel.HasAnyProminentPackages();
1134ccf707d0SAndrew Lindesay 	fListTabs->TabAt(TAB_PROMINENT_PACKAGES)->SetEnabled(hasProminentPackages);
1135ccf707d0SAndrew Lindesay 	if (!hasProminentPackages
1136ccf707d0SAndrew Lindesay 			&& fListTabs->Selection() == TAB_PROMINENT_PACKAGES) {
1137ccf707d0SAndrew Lindesay 		fModel.SetPackageListViewMode(ALL);
1138ccf707d0SAndrew Lindesay 		fListTabs->Select(TAB_ALL_PACKAGES);
1139ccf707d0SAndrew Lindesay 	}
114004c9d578SStephan Aßmus }
114104c9d578SStephan Aßmus 
114204c9d578SStephan Aßmus 
11433369e03dSAndrew Lindesay void
114410cd325cSAndrew Lindesay MainWindow::_NotifyWorkStatusClear()
114504c9d578SStephan Aßmus {
114610cd325cSAndrew Lindesay 	BMessage message(MSG_WORK_STATUS_CLEAR);
114710cd325cSAndrew Lindesay 	this->PostMessage(&message, this);
114810cd325cSAndrew Lindesay }
114910cd325cSAndrew Lindesay 
115010cd325cSAndrew Lindesay 
115110cd325cSAndrew Lindesay void
115210cd325cSAndrew Lindesay MainWindow::_HandleWorkStatusClear()
115310cd325cSAndrew Lindesay {
115410cd325cSAndrew Lindesay 	fWorkStatusView->SetText("");
11553369e03dSAndrew Lindesay 	fWorkStatusView->SetIdle();
11563369e03dSAndrew Lindesay }
115704c9d578SStephan Aßmus 
115804c9d578SStephan Aßmus 
11593369e03dSAndrew Lindesay /*! Sends off a message to the Window so that it can change the status view
11603369e03dSAndrew Lindesay     on the front-end in the UI thread.
11613369e03dSAndrew Lindesay */
116204c9d578SStephan Aßmus 
11633369e03dSAndrew Lindesay void
11643369e03dSAndrew Lindesay MainWindow::_NotifyWorkStatusChange(const BString& text, float progress)
11653369e03dSAndrew Lindesay {
11663369e03dSAndrew Lindesay 	BMessage message(MSG_WORK_STATUS_CHANGE);
116704c9d578SStephan Aßmus 
11683369e03dSAndrew Lindesay 	if (!text.IsEmpty())
11693369e03dSAndrew Lindesay 		message.AddString(KEY_WORK_STATUS_TEXT, text);
11703369e03dSAndrew Lindesay 	message.AddFloat(KEY_WORK_STATUS_PROGRESS, progress);
117104c9d578SStephan Aßmus 
11723369e03dSAndrew Lindesay 	this->PostMessage(&message, this);
11733369e03dSAndrew Lindesay }
117404c9d578SStephan Aßmus 
11753369e03dSAndrew Lindesay 
1176f32d5c5cSAndrew Lindesay void
1177f32d5c5cSAndrew Lindesay MainWindow::_HandleExternalPackageUpdateMessageReceived(const BMessage* message)
1178f32d5c5cSAndrew Lindesay {
1179f32d5c5cSAndrew Lindesay 	BStringList addedPackageNames;
1180f32d5c5cSAndrew Lindesay 	BStringList removedPackageNames;
1181f32d5c5cSAndrew Lindesay 
1182f32d5c5cSAndrew Lindesay 	if (message->FindStrings("added package names",
1183f32d5c5cSAndrew Lindesay 			&addedPackageNames) == B_OK) {
1184f32d5c5cSAndrew Lindesay 		addedPackageNames.Sort();
11850ebb9177SAndrew Lindesay 		AutoLocker<BLocker> locker(fModel.Lock());
11860ebb9177SAndrew Lindesay 		fModel.SetStateForPackagesByName(addedPackageNames, ACTIVATED);
1187f32d5c5cSAndrew Lindesay 	}
1188f32d5c5cSAndrew Lindesay 	else
1189f32d5c5cSAndrew Lindesay 		HDINFO("no [added package names] key in inbound message");
1190f32d5c5cSAndrew Lindesay 
1191f32d5c5cSAndrew Lindesay 	if (message->FindStrings("removed package names",
1192f32d5c5cSAndrew Lindesay 			&removedPackageNames) == B_OK) {
1193f32d5c5cSAndrew Lindesay 		removedPackageNames.Sort();
11940ebb9177SAndrew Lindesay 		AutoLocker<BLocker> locker(fModel.Lock());
11950ebb9177SAndrew Lindesay 		fModel.SetStateForPackagesByName(addedPackageNames, UNINSTALLED);
1196f32d5c5cSAndrew Lindesay 	} else
1197f32d5c5cSAndrew Lindesay 		HDINFO("no [removed package names] key in inbound message");
1198f32d5c5cSAndrew Lindesay }
1199f32d5c5cSAndrew Lindesay 
1200f32d5c5cSAndrew Lindesay 
12013369e03dSAndrew Lindesay void
12023369e03dSAndrew Lindesay MainWindow::_HandleWorkStatusChangeMessageReceived(const BMessage* message)
12033369e03dSAndrew Lindesay {
12049883929bSAndrew Lindesay 	if (fWorkStatusView == NULL)
12059883929bSAndrew Lindesay 		return;
12069883929bSAndrew Lindesay 
12073369e03dSAndrew Lindesay 	BString text;
12083369e03dSAndrew Lindesay 	float progress;
12093369e03dSAndrew Lindesay 
12103369e03dSAndrew Lindesay 	if (message->FindString(KEY_WORK_STATUS_TEXT, &text) == B_OK)
12113369e03dSAndrew Lindesay 		fWorkStatusView->SetText(text);
12123369e03dSAndrew Lindesay 
1213a18f873fSAndrew Lindesay 	if (message->FindFloat(KEY_WORK_STATUS_PROGRESS, &progress) == B_OK) {
1214a18f873fSAndrew Lindesay 		if (progress < 0.0f)
1215a18f873fSAndrew Lindesay 			fWorkStatusView->SetBusy();
1216a18f873fSAndrew Lindesay 		else
12173369e03dSAndrew Lindesay 			fWorkStatusView->SetProgress(progress);
1218a18f873fSAndrew Lindesay 	} else {
1219a18f873fSAndrew Lindesay 		HDERROR("work status change missing progress on update message");
1220a18f873fSAndrew Lindesay 		fWorkStatusView->SetProgress(0.0f);
122104c9d578SStephan Aßmus 	}
122204c9d578SStephan Aßmus }
122304c9d578SStephan Aßmus 
122404c9d578SStephan Aßmus 
12258266f4d7SAugustin Cavalier /*! Initially only superficial data is loaded from the server into the data
12268266f4d7SAugustin Cavalier 	model of the packages.  When the package is viewed, additional data needs
12278266f4d7SAugustin Cavalier 	to be populated including ratings.
12288266f4d7SAugustin Cavalier 
12298266f4d7SAugustin Cavalier 	This method will cause the package to have its data refreshed from
1230a9edb9bfSAndrew Lindesay 	the server application.  The refresh happens in the background; this method
1231a9edb9bfSAndrew Lindesay 	is asynchronous.
1232a9edb9bfSAndrew Lindesay */
1233a9edb9bfSAndrew Lindesay 
1234a9edb9bfSAndrew Lindesay void
1235a9edb9bfSAndrew Lindesay MainWindow::_PopulatePackageAsync(bool forcePopulate)
1236a9edb9bfSAndrew Lindesay {
12378266f4d7SAugustin Cavalier 	const PackageInfoRef package = fPackageInfoView->Package();
1238a9edb9bfSAndrew Lindesay 
12398266f4d7SAugustin Cavalier 	if (!fModel.CanPopulatePackage(package))
12408266f4d7SAugustin Cavalier 		return;
12418266f4d7SAugustin Cavalier 
12428266f4d7SAugustin Cavalier 	const char* packageNameStr = package->Name().String();
12438266f4d7SAugustin Cavalier 
12448266f4d7SAugustin Cavalier 	if (package->HasChangelog() && (forcePopulate || package->Changelog().IsEmpty())) {
12458266f4d7SAugustin Cavalier 		_AddProcessCoordinator(
12468266f4d7SAugustin Cavalier 			ProcessCoordinatorFactory::PopulatePkgChangelogCoordinator(&fModel, package));
12478266f4d7SAugustin Cavalier 		HDINFO("pkg [%s] will have changelog updated from server.", packageNameStr);
12488266f4d7SAugustin Cavalier 	} else {
12498266f4d7SAugustin Cavalier 		HDDEBUG("pkg [%s] not have changelog updated from server.", packageNameStr);
1250a9edb9bfSAndrew Lindesay 	}
1251a9edb9bfSAndrew Lindesay 
12524b3c808eSAndrew Lindesay 	if (forcePopulate || RatingUtils::ShouldTryPopulateUserRatings(package->UserRatingInfo())) {
12538266f4d7SAugustin Cavalier 		_AddProcessCoordinator(
12548266f4d7SAugustin Cavalier 			ProcessCoordinatorFactory::PopulatePkgUserRatingsCoordinator(&fModel, package));
12558266f4d7SAugustin Cavalier 		HDINFO("pkg [%s] will have user ratings updated from server.", packageNameStr);
12568266f4d7SAugustin Cavalier 	} else {
12578266f4d7SAugustin Cavalier 		HDDEBUG("pkg [%s] not have user ratings updated from server.", packageNameStr);
125804c9d578SStephan Aßmus 	}
125904c9d578SStephan Aßmus }
126004c9d578SStephan Aßmus 
126104c9d578SStephan Aßmus 
126204c9d578SStephan Aßmus void
1263133ebab6SAndrew Lindesay MainWindow::_OpenSettingsWindow()
1264133ebab6SAndrew Lindesay {
1265133ebab6SAndrew Lindesay 	SettingsWindow* window = new SettingsWindow(this, &fModel);
1266133ebab6SAndrew Lindesay 	window->Show();
1267133ebab6SAndrew Lindesay }
1268133ebab6SAndrew Lindesay 
1269133ebab6SAndrew Lindesay 
1270133ebab6SAndrew Lindesay void
12711bbda92dSStephan Aßmus MainWindow::_OpenLoginWindow(const BMessage& onSuccessMessage)
127204c9d578SStephan Aßmus {
127304c9d578SStephan Aßmus 	UserLoginWindow* window = new UserLoginWindow(this,
127404c9d578SStephan Aßmus 		BRect(0, 0, 500, 400), fModel);
12751bbda92dSStephan Aßmus 
12761bbda92dSStephan Aßmus 	if (onSuccessMessage.what != 0)
12771bbda92dSStephan Aßmus 		window->SetOnSuccessMessage(BMessenger(this), onSuccessMessage);
12781bbda92dSStephan Aßmus 
127904c9d578SStephan Aßmus 	window->Show();
128004c9d578SStephan Aßmus }
128104c9d578SStephan Aßmus 
12828f03a0f9SStephan Aßmus 
12838f03a0f9SStephan Aßmus void
128410cd325cSAndrew Lindesay MainWindow::_StartUserVerify()
128510cd325cSAndrew Lindesay {
128610cd325cSAndrew Lindesay 	if (!fModel.Nickname().IsEmpty()) {
128710cd325cSAndrew Lindesay 		_AddProcessCoordinator(
128810cd325cSAndrew Lindesay 			ProcessCoordinatorFactory::CreateUserDetailVerifierCoordinator(
128910cd325cSAndrew Lindesay 				this,
129010cd325cSAndrew Lindesay 					// UserDetailVerifierListener
129110cd325cSAndrew Lindesay 				&fModel) );
129210cd325cSAndrew Lindesay 	}
129310cd325cSAndrew Lindesay }
129410cd325cSAndrew Lindesay 
129510cd325cSAndrew Lindesay 
129610cd325cSAndrew Lindesay void
12978f03a0f9SStephan Aßmus MainWindow::_UpdateAuthorization()
12988f03a0f9SStephan Aßmus {
1299d2d4866dSAndrew Lindesay 	BString nickname(fModel.Nickname());
1300d2d4866dSAndrew Lindesay 	bool hasUser = !nickname.IsEmpty();
1301e0a26dceSStephan Aßmus 
13026d519fd1SStephan Aßmus 	if (fLogOutItem != NULL)
1303e0a26dceSStephan Aßmus 		fLogOutItem->SetEnabled(hasUser);
1304d2d4866dSAndrew Lindesay 	if (fUsersUserUsageConditionsMenuItem != NULL)
1305d2d4866dSAndrew Lindesay 		fUsersUserUsageConditionsMenuItem->SetEnabled(hasUser);
1306e0a26dceSStephan Aßmus 	if (fLogInItem != NULL) {
1307e0a26dceSStephan Aßmus 		if (hasUser)
1308e0a26dceSStephan Aßmus 			fLogInItem->SetLabel(B_TRANSLATE("Switch account" B_UTF8_ELLIPSIS));
1309e0a26dceSStephan Aßmus 		else
1310e0a26dceSStephan Aßmus 			fLogInItem->SetLabel(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS));
1311e0a26dceSStephan Aßmus 	}
1312e0a26dceSStephan Aßmus 
1313e0a26dceSStephan Aßmus 	if (fUserMenu != NULL) {
1314e0a26dceSStephan Aßmus 		BString label;
1315d2d4866dSAndrew Lindesay 		if (hasUser) {
1316e0a26dceSStephan Aßmus 			label = B_TRANSLATE("Logged in as %User%");
1317d2d4866dSAndrew Lindesay 			label.ReplaceAll("%User%", nickname);
1318d2d4866dSAndrew Lindesay 		} else {
1319d2d4866dSAndrew Lindesay 			label = B_TRANSLATE("Not logged in");
1320e0a26dceSStephan Aßmus 		}
1321e0a26dceSStephan Aßmus 		fUserMenu->Superitem()->SetLabel(label);
1322e0a26dceSStephan Aßmus 	}
13238f03a0f9SStephan Aßmus }
13241bbda92dSStephan Aßmus 
13251bbda92dSStephan Aßmus 
13261bbda92dSStephan Aßmus void
1327b965ce70SHumdinger MainWindow::_UpdateAvailableRepositories()
1328b965ce70SHumdinger {
1329b965ce70SHumdinger 	fRepositoryMenu->RemoveItems(0, fRepositoryMenu->CountItems(), true);
1330b965ce70SHumdinger 
1331b965ce70SHumdinger 	fRepositoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All repositories"),
1332b965ce70SHumdinger 		new BMessage(MSG_DEPOT_SELECTED)));
1333b965ce70SHumdinger 
1334b965ce70SHumdinger 	fRepositoryMenu->AddItem(new BSeparatorItem());
1335b965ce70SHumdinger 
1336b965ce70SHumdinger 	bool foundSelectedDepot = false;
133705880d13SAndrew Lindesay 	std::vector<DepotInfoRef> depots = _CreateSnapshotOfDepots();
133805880d13SAndrew Lindesay 	std::vector<DepotInfoRef>::iterator it;
1339d13c3d89SAndrew Lindesay 
134005880d13SAndrew Lindesay 	for (it = depots.begin(); it != depots.end(); it++) {
134105880d13SAndrew Lindesay 		DepotInfoRef depot = *it;
134205880d13SAndrew Lindesay 
134305880d13SAndrew Lindesay 		if (depot->Name().Length() != 0) {
1344b965ce70SHumdinger 			BMessage* message = new BMessage(MSG_DEPOT_SELECTED);
134505880d13SAndrew Lindesay 			message->AddString("name", depot->Name());
134605880d13SAndrew Lindesay 			BMenuItem* item = new(std::nothrow) BMenuItem(depot->Name(), message);
134705880d13SAndrew Lindesay 
134805880d13SAndrew Lindesay 			if (item == NULL)
134905880d13SAndrew Lindesay 				HDFATAL("memory exhaustion");
135005880d13SAndrew Lindesay 
1351b965ce70SHumdinger 			fRepositoryMenu->AddItem(item);
1352b965ce70SHumdinger 
1353363fc60bSAndrew Lindesay 			if (depot->Name() == fModel.PackageFilter()->DepotName()) {
1354b965ce70SHumdinger 				item->SetMarked(true);
1355b965ce70SHumdinger 				foundSelectedDepot = true;
1356b965ce70SHumdinger 			}
1357b965ce70SHumdinger 		}
1358d13c3d89SAndrew Lindesay 	}
1359b965ce70SHumdinger 
1360b965ce70SHumdinger 	if (!foundSelectedDepot)
1361b965ce70SHumdinger 		fRepositoryMenu->ItemAt(0)->SetMarked(true);
1362b965ce70SHumdinger }
1363b965ce70SHumdinger 
1364b965ce70SHumdinger 
1365a9edb9bfSAndrew Lindesay bool
1366a9edb9bfSAndrew Lindesay MainWindow::_SelectedPackageHasWebAppRepositoryCode()
1367a9edb9bfSAndrew Lindesay {
1368a9edb9bfSAndrew Lindesay 	const PackageInfoRef& package = fPackageInfoView->Package();
13696ab878c0SAndrew Lindesay 	const BString depotName = package->DepotName();
1370a9edb9bfSAndrew Lindesay 
13716ab878c0SAndrew Lindesay 	if (depotName.IsEmpty()) {
1372fa5c8097SAndrew Lindesay 		HDDEBUG("the package [%s] has no depot name", package->Name().String());
13736ab878c0SAndrew Lindesay 	} else {
13746ab878c0SAndrew Lindesay 		const DepotInfo* depot = fModel.DepotForName(depotName);
1375a9edb9bfSAndrew Lindesay 
13766ab878c0SAndrew Lindesay 		if (depot == NULL) {
1377f96d1f4dSAndrew Lindesay 			HDINFO("the depot [%s] was not able to be found",
1378fa5c8097SAndrew Lindesay 				depotName.String());
13796ab878c0SAndrew Lindesay 		} else {
13806ab878c0SAndrew Lindesay 			BString repositoryCode = depot->WebAppRepositoryCode();
1381a9edb9bfSAndrew Lindesay 
13826ab878c0SAndrew Lindesay 			if (repositoryCode.IsEmpty()) {
1383f96d1f4dSAndrew Lindesay 				HDINFO("the depot [%s] has no web app repository code",
1384fa5c8097SAndrew Lindesay 					depotName.String());
1385fa5c8097SAndrew Lindesay 			} else
13866ab878c0SAndrew Lindesay 				return true;
13876ab878c0SAndrew Lindesay 		}
13886ab878c0SAndrew Lindesay 	}
13896ab878c0SAndrew Lindesay 
13906ab878c0SAndrew Lindesay 	return false;
1391a9edb9bfSAndrew Lindesay }
1392a9edb9bfSAndrew Lindesay 
1393a9edb9bfSAndrew Lindesay 
1394b965ce70SHumdinger void
13951bbda92dSStephan Aßmus MainWindow::_RatePackage()
13961bbda92dSStephan Aßmus {
1397a9edb9bfSAndrew Lindesay 	if (!_SelectedPackageHasWebAppRepositoryCode()) {
1398a9edb9bfSAndrew Lindesay 		BAlert* alert = new(std::nothrow) BAlert(
1399cbadcae1SHumdinger 			B_TRANSLATE("Rating not possible"),
1400cbadcae1SHumdinger 			B_TRANSLATE("This package doesn't seem to be on the HaikuDepot "
1401cbadcae1SHumdinger 				"Server, so it's not possible to create a new rating "
1402cbadcae1SHumdinger 				"or edit an existing rating."),
1403a9edb9bfSAndrew Lindesay 			B_TRANSLATE("OK"));
1404a9edb9bfSAndrew Lindesay 		alert->Go();
1405a9edb9bfSAndrew Lindesay     	return;
1406a9edb9bfSAndrew Lindesay 	}
1407a9edb9bfSAndrew Lindesay 
1408d2d4866dSAndrew Lindesay 	if (fModel.Nickname().IsEmpty()) {
14091bbda92dSStephan Aßmus 		BAlert* alert = new(std::nothrow) BAlert(
14101bbda92dSStephan Aßmus 			B_TRANSLATE("Not logged in"),
14111bbda92dSStephan Aßmus 			B_TRANSLATE("You need to be logged into an account before you "
14121bbda92dSStephan Aßmus 				"can rate packages."),
14131bbda92dSStephan Aßmus 			B_TRANSLATE("Cancel"),
14141bbda92dSStephan Aßmus 			B_TRANSLATE("Login or Create account"));
14151bbda92dSStephan Aßmus 
14161bbda92dSStephan Aßmus 		if (alert == NULL)
14171bbda92dSStephan Aßmus 			return;
14181bbda92dSStephan Aßmus 
14191bbda92dSStephan Aßmus 		int32 choice = alert->Go();
14201bbda92dSStephan Aßmus 		if (choice == 1)
14211bbda92dSStephan Aßmus 			_OpenLoginWindow(BMessage(MSG_RATE_PACKAGE));
14221bbda92dSStephan Aßmus 		return;
14231bbda92dSStephan Aßmus 	}
14241bbda92dSStephan Aßmus 
14251bbda92dSStephan Aßmus 	// TODO: Allow only one RatePackageWindow
14261bbda92dSStephan Aßmus 	// TODO: Mechanism for remembering the window frame
14271bbda92dSStephan Aßmus 	RatePackageWindow* window = new RatePackageWindow(this,
14281bbda92dSStephan Aßmus 		BRect(0, 0, 500, 400), fModel);
14291bbda92dSStephan Aßmus 	window->SetPackage(fPackageInfoView->Package());
14301bbda92dSStephan Aßmus 	window->Show();
14311bbda92dSStephan Aßmus }
1432d5ef985eSStephan Aßmus 
1433d5ef985eSStephan Aßmus 
1434d5ef985eSStephan Aßmus void
1435d5ef985eSStephan Aßmus MainWindow::_ShowScreenshot()
1436d5ef985eSStephan Aßmus {
1437d5ef985eSStephan Aßmus 	// TODO: Mechanism for remembering the window frame
1438d5ef985eSStephan Aßmus 	if (fScreenshotWindow == NULL)
143988af15cfSAndrew Lindesay 		fScreenshotWindow = new ScreenshotWindow(this, BRect(0, 0, 500, 400), &fModel);
1440d5ef985eSStephan Aßmus 
1441d5ef985eSStephan Aßmus 	if (fScreenshotWindow->LockWithTimeout(1000) != B_OK)
1442d5ef985eSStephan Aßmus 		return;
1443d5ef985eSStephan Aßmus 
1444d5ef985eSStephan Aßmus 	fScreenshotWindow->SetPackage(fPackageInfoView->Package());
1445d5ef985eSStephan Aßmus 
1446d5ef985eSStephan Aßmus 	if (fScreenshotWindow->IsHidden())
1447d5ef985eSStephan Aßmus 		fScreenshotWindow->Show();
1448d5ef985eSStephan Aßmus 	else
1449d5ef985eSStephan Aßmus 		fScreenshotWindow->Activate();
1450d5ef985eSStephan Aßmus 
1451d5ef985eSStephan Aßmus 	fScreenshotWindow->Unlock();
1452d5ef985eSStephan Aßmus }
145301339a54SAndrew Lindesay 
145401339a54SAndrew Lindesay 
145501339a54SAndrew Lindesay void
1456d2d4866dSAndrew Lindesay MainWindow::_ViewUserUsageConditions(
1457d2d4866dSAndrew Lindesay 	UserUsageConditionsSelectionMode mode)
145801339a54SAndrew Lindesay {
145901339a54SAndrew Lindesay 	UserUsageConditionsWindow* window = new UserUsageConditionsWindow(
1460d2d4866dSAndrew Lindesay 		fModel, mode);
146101339a54SAndrew Lindesay 	window->Show();
146201339a54SAndrew Lindesay }
146310cd325cSAndrew Lindesay 
146410cd325cSAndrew Lindesay 
146510cd325cSAndrew Lindesay void
146610cd325cSAndrew Lindesay MainWindow::UserCredentialsFailed()
146710cd325cSAndrew Lindesay {
146810cd325cSAndrew Lindesay 	BString message = B_TRANSLATE("The password previously "
146910cd325cSAndrew Lindesay 		"supplied for the user [%Nickname%] is not currently "
147010cd325cSAndrew Lindesay 		"valid. The user will be logged-out of this application "
147110cd325cSAndrew Lindesay 		"and you should login again with your updated password.");
147210cd325cSAndrew Lindesay 	message.ReplaceAll("%Nickname%", fModel.Nickname());
147310cd325cSAndrew Lindesay 
147410cd325cSAndrew Lindesay 	AppUtils::NotifySimpleError(B_TRANSLATE("Login issue"),
147510cd325cSAndrew Lindesay 		message);
147610cd325cSAndrew Lindesay 
147710cd325cSAndrew Lindesay 	{
147810cd325cSAndrew Lindesay 		AutoLocker<BLocker> locker(fModel.Lock());
147910cd325cSAndrew Lindesay 		fModel.SetNickname("");
148010cd325cSAndrew Lindesay 	}
148110cd325cSAndrew Lindesay }
148210cd325cSAndrew Lindesay 
148310cd325cSAndrew Lindesay 
148410cd325cSAndrew Lindesay /*! \brief This method is invoked from the UserDetailVerifierProcess on a
148510cd325cSAndrew Lindesay 		   background thread.  For this reason it lodges a message into itself
148610cd325cSAndrew Lindesay 		   which can then be handled on the main thread.
148710cd325cSAndrew Lindesay */
148810cd325cSAndrew Lindesay 
148910cd325cSAndrew Lindesay void
149010cd325cSAndrew Lindesay MainWindow::UserUsageConditionsNotLatest(const UserDetail& userDetail)
149110cd325cSAndrew Lindesay {
149210cd325cSAndrew Lindesay 	BMessage message(MSG_USER_USAGE_CONDITIONS_NOT_LATEST);
149310cd325cSAndrew Lindesay 	BMessage detailsMessage;
149410cd325cSAndrew Lindesay 	if (userDetail.Archive(&detailsMessage, true) != B_OK
149510cd325cSAndrew Lindesay 			|| message.AddMessage("userDetail", &detailsMessage) != B_OK) {
1496fa5c8097SAndrew Lindesay 		HDERROR("unable to archive the user detail into a message");
149710cd325cSAndrew Lindesay 	}
149810cd325cSAndrew Lindesay 	else
149910cd325cSAndrew Lindesay 		BMessenger(this).SendMessage(&message);
150010cd325cSAndrew Lindesay }
150110cd325cSAndrew Lindesay 
150210cd325cSAndrew Lindesay 
150310cd325cSAndrew Lindesay void
150410cd325cSAndrew Lindesay MainWindow::_HandleUserUsageConditionsNotLatest(
150510cd325cSAndrew Lindesay 	const UserDetail& userDetail)
150610cd325cSAndrew Lindesay {
150710cd325cSAndrew Lindesay 	ToLatestUserUsageConditionsWindow* window =
150810cd325cSAndrew Lindesay 		new ToLatestUserUsageConditionsWindow(this, fModel, userDetail);
150910cd325cSAndrew Lindesay 	window->Show();
151010cd325cSAndrew Lindesay }
151110cd325cSAndrew Lindesay 
151210cd325cSAndrew Lindesay 
151310cd325cSAndrew Lindesay void
151410cd325cSAndrew Lindesay MainWindow::_AddProcessCoordinator(ProcessCoordinator* item)
151510cd325cSAndrew Lindesay {
151610cd325cSAndrew Lindesay 	AutoLocker<BLocker> lock(&fCoordinatorLock);
151710cd325cSAndrew Lindesay 
151895c7b018SAndrew Lindesay 	if (fShouldCloseWhenNoProcessesToCoordinate) {
151995c7b018SAndrew Lindesay 		HDINFO("system shutting down --> new process coordinator [%s] rejected",
152095c7b018SAndrew Lindesay 			item->Name().String());
152195c7b018SAndrew Lindesay 		return;
152295c7b018SAndrew Lindesay 	}
152395c7b018SAndrew Lindesay 
1524a18f873fSAndrew Lindesay 	item->SetListener(this);
1525a18f873fSAndrew Lindesay 
1526409af934SAndrew Lindesay 	if (fCoordinator == NULL) {
152710cd325cSAndrew Lindesay 		if (acquire_sem(fCoordinatorRunningSem) != B_OK)
152810cd325cSAndrew Lindesay 			debugger("unable to acquire the process coordinator sem");
1529f96d1f4dSAndrew Lindesay 		HDINFO("adding and starting a process coordinator [%s]",
1530fa5c8097SAndrew Lindesay 			item->Name().String());
1531409af934SAndrew Lindesay 		delete fCoordinator;
1532409af934SAndrew Lindesay 		fCoordinator = item;
153310cd325cSAndrew Lindesay 		fCoordinator->Start();
15347d7de135SAugustin Cavalier 	} else {
1535f96d1f4dSAndrew Lindesay 		HDINFO("adding process coordinator [%s] to the queue",
153610cd325cSAndrew Lindesay 			item->Name().String());
153710cd325cSAndrew Lindesay 		fCoordinatorQueue.push(item);
153810cd325cSAndrew Lindesay 	}
153910cd325cSAndrew Lindesay }
154010cd325cSAndrew Lindesay 
154110cd325cSAndrew Lindesay 
154210cd325cSAndrew Lindesay void
154310cd325cSAndrew Lindesay MainWindow::_SpinUntilProcessCoordinatorComplete()
154410cd325cSAndrew Lindesay {
154510cd325cSAndrew Lindesay 	while (true) {
154610cd325cSAndrew Lindesay 		if (acquire_sem(fCoordinatorRunningSem) != B_OK)
154710cd325cSAndrew Lindesay 			debugger("unable to acquire the process coordinator sem");
154810cd325cSAndrew Lindesay 		if (release_sem(fCoordinatorRunningSem) != B_OK)
154910cd325cSAndrew Lindesay 			debugger("unable to release the process coordinator sem");
155010cd325cSAndrew Lindesay 		{
155110cd325cSAndrew Lindesay 			AutoLocker<BLocker> lock(&fCoordinatorLock);
1552409af934SAndrew Lindesay 			if (fCoordinator == NULL)
155310cd325cSAndrew Lindesay 				return;
155410cd325cSAndrew Lindesay 		}
155510cd325cSAndrew Lindesay 	}
155610cd325cSAndrew Lindesay }
155710cd325cSAndrew Lindesay 
155810cd325cSAndrew Lindesay 
155910cd325cSAndrew Lindesay void
156010cd325cSAndrew Lindesay MainWindow::_StopProcessCoordinators()
156110cd325cSAndrew Lindesay {
156295c7b018SAndrew Lindesay 	HDINFO("will stop all queued process coordinators");
156310cd325cSAndrew Lindesay 	AutoLocker<BLocker> lock(&fCoordinatorLock);
156410cd325cSAndrew Lindesay 
156510cd325cSAndrew Lindesay 	while (!fCoordinatorQueue.empty()) {
1566409af934SAndrew Lindesay 		ProcessCoordinator* processCoordinator
1567f96d1f4dSAndrew Lindesay 			= fCoordinatorQueue.front();
1568f96d1f4dSAndrew Lindesay 		HDINFO("will drop queued process coordinator [%s]",
1569fa5c8097SAndrew Lindesay 			processCoordinator->Name().String());
157010cd325cSAndrew Lindesay 		fCoordinatorQueue.pop();
1571409af934SAndrew Lindesay 		delete processCoordinator;
157210cd325cSAndrew Lindesay 	}
157310cd325cSAndrew Lindesay 
1574409af934SAndrew Lindesay 	if (fCoordinator != NULL)
157595c7b018SAndrew Lindesay 		fCoordinator->RequestStop();
157610cd325cSAndrew Lindesay }
157710cd325cSAndrew Lindesay 
157810cd325cSAndrew Lindesay 
157910cd325cSAndrew Lindesay /*! This method is called when there is some change in the bulk load process
158010cd325cSAndrew Lindesay 	or other process coordinator.
158110cd325cSAndrew Lindesay 	A change may mean that a new process has started / stopped etc... or it
158210cd325cSAndrew Lindesay 	may mean that the entire coordinator has finished.
158310cd325cSAndrew Lindesay */
158410cd325cSAndrew Lindesay 
158510cd325cSAndrew Lindesay void
158610cd325cSAndrew Lindesay MainWindow::CoordinatorChanged(ProcessCoordinatorState& coordinatorState)
158710cd325cSAndrew Lindesay {
1588409af934SAndrew Lindesay 	BMessage message(MSG_PROCESS_COORDINATOR_CHANGED);
1589409af934SAndrew Lindesay 	if (coordinatorState.Archive(&message, true) != B_OK) {
1590409af934SAndrew Lindesay 		HDFATAL("unable to archive message when the process coordinator"
1591409af934SAndrew Lindesay 			" has changed");
1592409af934SAndrew Lindesay 	}
1593409af934SAndrew Lindesay 	BMessenger(this).SendMessage(&message);
1594409af934SAndrew Lindesay }
1595409af934SAndrew Lindesay 
1596409af934SAndrew Lindesay 
1597409af934SAndrew Lindesay void
1598409af934SAndrew Lindesay MainWindow::_HandleProcessCoordinatorChanged(ProcessCoordinatorState& coordinatorState)
1599409af934SAndrew Lindesay {
160010cd325cSAndrew Lindesay 	AutoLocker<BLocker> lock(&fCoordinatorLock);
160110cd325cSAndrew Lindesay 
1602409af934SAndrew Lindesay 	if (fCoordinator->Identifier()
1603409af934SAndrew Lindesay 			== coordinatorState.ProcessCoordinatorIdentifier()) {
160410cd325cSAndrew Lindesay 		if (!coordinatorState.IsRunning()) {
160510cd325cSAndrew Lindesay 			if (release_sem(fCoordinatorRunningSem) != B_OK)
160610cd325cSAndrew Lindesay 				debugger("unable to release the process coordinator sem");
1607f96d1f4dSAndrew Lindesay 			HDINFO("process coordinator [%s] did complete",
1608fa5c8097SAndrew Lindesay 				fCoordinator->Name().String());
160910cd325cSAndrew Lindesay 			// complete the last one that just finished
161010cd325cSAndrew Lindesay 			BMessage* message = fCoordinator->Message();
161110cd325cSAndrew Lindesay 
161210cd325cSAndrew Lindesay 			if (message != NULL) {
161310cd325cSAndrew Lindesay 				BMessenger messenger(this);
161410cd325cSAndrew Lindesay 				message->AddInt64(KEY_ERROR_STATUS,
161510cd325cSAndrew Lindesay 					(int64) fCoordinator->ErrorStatus());
161610cd325cSAndrew Lindesay 				messenger.SendMessage(message);
161710cd325cSAndrew Lindesay 			}
161810cd325cSAndrew Lindesay 
16193538133fSAndrew Lindesay 			HDDEBUG("process coordinator report;\n---\n%s\n----",
16203538133fSAndrew Lindesay 				fCoordinator->LogReport().String());
16213538133fSAndrew Lindesay 
1622409af934SAndrew Lindesay 			delete fCoordinator;
1623409af934SAndrew Lindesay 			fCoordinator = NULL;
162410cd325cSAndrew Lindesay 
162510cd325cSAndrew Lindesay 			// now schedule the next one.
162610cd325cSAndrew Lindesay 			if (!fCoordinatorQueue.empty()) {
162710cd325cSAndrew Lindesay 				if (acquire_sem(fCoordinatorRunningSem) != B_OK)
162810cd325cSAndrew Lindesay 					debugger("unable to acquire the process coordinator sem");
162910cd325cSAndrew Lindesay 				fCoordinator = fCoordinatorQueue.front();
1630f96d1f4dSAndrew Lindesay 				HDINFO("starting next process coordinator [%s]",
163110cd325cSAndrew Lindesay 					fCoordinator->Name().String());
163210cd325cSAndrew Lindesay 				fCoordinatorQueue.pop();
163310cd325cSAndrew Lindesay 				fCoordinator->Start();
163410cd325cSAndrew Lindesay 			}
163510cd325cSAndrew Lindesay 			else {
163610cd325cSAndrew Lindesay 				_NotifyWorkStatusClear();
163795c7b018SAndrew Lindesay 				if (fShouldCloseWhenNoProcessesToCoordinate) {
163895c7b018SAndrew Lindesay 					HDINFO("no more processes to coord --> will quit");
163995c7b018SAndrew Lindesay 					BMessage message(B_QUIT_REQUESTED);
164095c7b018SAndrew Lindesay 					PostMessage(&message);
164195c7b018SAndrew Lindesay 				}
164210cd325cSAndrew Lindesay 			}
164310cd325cSAndrew Lindesay 		}
164410cd325cSAndrew Lindesay 		else {
164510cd325cSAndrew Lindesay 			_NotifyWorkStatusChange(coordinatorState.Message(),
164610cd325cSAndrew Lindesay 				coordinatorState.Progress());
164710cd325cSAndrew Lindesay 				// show the progress to the user.
164810cd325cSAndrew Lindesay 		}
164995c7b018SAndrew Lindesay 	} else {
165095c7b018SAndrew Lindesay 		_NotifyWorkStatusClear();
1651fa5c8097SAndrew Lindesay 		HDINFO("! unknown process coordinator changed");
165210cd325cSAndrew Lindesay 	}
165395c7b018SAndrew Lindesay }
1654ccf707d0SAndrew Lindesay 
1655ccf707d0SAndrew Lindesay 
1656ccf707d0SAndrew Lindesay static package_list_view_mode
1657ccf707d0SAndrew Lindesay main_window_tab_to_package_list_view_mode(int32 tab)
1658ccf707d0SAndrew Lindesay {
1659ccf707d0SAndrew Lindesay 	if (tab == TAB_PROMINENT_PACKAGES)
1660ccf707d0SAndrew Lindesay 		return PROMINENT;
1661ccf707d0SAndrew Lindesay 	return ALL;
1662ccf707d0SAndrew Lindesay }
1663ccf707d0SAndrew Lindesay 
1664ccf707d0SAndrew Lindesay 
1665ccf707d0SAndrew Lindesay void
1666ccf707d0SAndrew Lindesay MainWindow::_HandleChangePackageListViewMode()
1667ccf707d0SAndrew Lindesay {
1668ccf707d0SAndrew Lindesay 	package_list_view_mode tabMode = main_window_tab_to_package_list_view_mode(
1669ccf707d0SAndrew Lindesay 		fListTabs->Selection());
1670ccf707d0SAndrew Lindesay 	package_list_view_mode modelMode = fModel.PackageListViewMode();
1671ccf707d0SAndrew Lindesay 
1672ccf707d0SAndrew Lindesay 	if (tabMode != modelMode) {
1673ccf707d0SAndrew Lindesay 		BAutolock locker(fModel.Lock());
1674ccf707d0SAndrew Lindesay 		fModel.SetPackageListViewMode(tabMode);
1675ccf707d0SAndrew Lindesay 	}
1676ccf707d0SAndrew Lindesay }
167705880d13SAndrew Lindesay 
167805880d13SAndrew Lindesay 
167905880d13SAndrew Lindesay std::vector<DepotInfoRef>
168005880d13SAndrew Lindesay MainWindow::_CreateSnapshotOfDepots()
168105880d13SAndrew Lindesay {
168205880d13SAndrew Lindesay 	std::vector<DepotInfoRef> result;
168305880d13SAndrew Lindesay 	BAutolock locker(fModel.Lock());
168405880d13SAndrew Lindesay 	int32 countDepots = fModel.CountDepots();
168505880d13SAndrew Lindesay 	for(int32 i = 0; i < countDepots; i++)
168605880d13SAndrew Lindesay 		result.push_back(fModel.DepotAtIndex(i));
168705880d13SAndrew Lindesay 	return result;
168805880d13SAndrew Lindesay }
168988af15cfSAndrew Lindesay 
169088af15cfSAndrew Lindesay 
169188af15cfSAndrew Lindesay /*! This will get invoked in the case that a screenshot has been cached
169288af15cfSAndrew Lindesay     and so could now be loaded by some UI element. This method will then
169388af15cfSAndrew Lindesay     signal to other UI elements that they could load a screenshot should
169488af15cfSAndrew Lindesay     they have been waiting for it.
169588af15cfSAndrew Lindesay */
169688af15cfSAndrew Lindesay 
169788af15cfSAndrew Lindesay void
169888af15cfSAndrew Lindesay MainWindow::_HandleScreenshotCached(const BMessage* message)
169988af15cfSAndrew Lindesay {
170088af15cfSAndrew Lindesay 	ScreenshotCoordinate coordinate(message);
170188af15cfSAndrew Lindesay 	fPackageInfoView->HandleScreenshotCached(coordinate);
170288af15cfSAndrew Lindesay }
1703