xref: /haiku/src/apps/haikudepot/ui/MainWindow.cpp (revision 88af15cfbd158c0070214219a341bbbf21019887)
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.
6*88af15cfSAndrew 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"
40d13c3d89SAndrew Lindesay #include "Logger.h"
4104c9d578SStephan Aßmus #include "PackageInfoView.h"
4204c9d578SStephan Aßmus #include "PackageListView.h"
4304c9d578SStephan Aßmus #include "PackageManager.h"
443369e03dSAndrew Lindesay #include "ProcessCoordinator.h"
453369e03dSAndrew Lindesay #include "ProcessCoordinatorFactory.h"
4604c9d578SStephan Aßmus #include "RatePackageWindow.h"
47e0a26dceSStephan Aßmus #include "support.h"
48d5ef985eSStephan Aßmus #include "ScreenshotWindow.h"
49133ebab6SAndrew Lindesay #include "SettingsWindow.h"
5095c7b018SAndrew Lindesay #include "ShuttingDownWindow.h"
5110cd325cSAndrew Lindesay #include "ToLatestUserUsageConditionsWindow.h"
5204c9d578SStephan Aßmus #include "UserLoginWindow.h"
5301339a54SAndrew Lindesay #include "UserUsageConditionsWindow.h"
54125d42d9SJulian Harnath #include "WorkStatusView.h"
5504c9d578SStephan Aßmus 
5604c9d578SStephan Aßmus 
5704c9d578SStephan Aßmus #undef B_TRANSLATION_CONTEXT
5804c9d578SStephan Aßmus #define B_TRANSLATION_CONTEXT "MainWindow"
5904c9d578SStephan Aßmus 
6004c9d578SStephan Aßmus 
6104c9d578SStephan Aßmus enum {
625bf2b6ebSBrian Hill 	MSG_REFRESH_REPOS						= 'mrrp',
635bf2b6ebSBrian Hill 	MSG_MANAGE_REPOS						= 'mmrp',
64d144f952SAugustin Cavalier 	MSG_SOFTWARE_UPDATER					= 'mswu',
65133ebab6SAndrew Lindesay 	MSG_SETTINGS							= 'stgs',
6604c9d578SStephan Aßmus 	MSG_LOG_IN								= 'lgin',
678f03a0f9SStephan Aßmus 	MSG_AUTHORIZATION_CHANGED				= 'athc',
6889b16bb4SAndrew Lindesay 	MSG_CATEGORIES_LIST_CHANGED				= 'clic',
69da651104SStephan Aßmus 	MSG_PACKAGE_CHANGED						= 'pchd',
70409af934SAndrew Lindesay 	MSG_PROCESS_COORDINATOR_CHANGED			= 'pccd',
713369e03dSAndrew Lindesay 	MSG_WORK_STATUS_CHANGE					= 'wsch',
723369e03dSAndrew Lindesay 	MSG_WORK_STATUS_CLEAR					= 'wscl',
7384674570SAndrew Lindesay 	MSG_INCREMENT_VIEW_COUNTER				= 'icrv',
74*88af15cfSAndrew Lindesay 	MSG_SCREENSHOT_CACHED					= 'ssca',
75fdec4227SStephan Aßmus 
76ccf707d0SAndrew Lindesay 	MSG_CHANGE_PACKAGE_LIST_VIEW_MODE		= 'cplm',
77fdec4227SStephan Aßmus 	MSG_SHOW_AVAILABLE_PACKAGES				= 'savl',
78fdec4227SStephan Aßmus 	MSG_SHOW_INSTALLED_PACKAGES				= 'sins',
7904c9d578SStephan Aßmus 	MSG_SHOW_SOURCE_PACKAGES				= 'ssrc',
8004c9d578SStephan Aßmus 	MSG_SHOW_DEVELOP_PACKAGES				= 'sdvl'
8104c9d578SStephan Aßmus };
8204c9d578SStephan Aßmus 
8310cd325cSAndrew Lindesay #define KEY_ERROR_STATUS				"errorStatus"
84ccf707d0SAndrew Lindesay 
8584674570SAndrew Lindesay const bigtime_t kIncrementViewCounterDelayMicros = 3 * 1000 * 1000;
8684674570SAndrew Lindesay 
87ccf707d0SAndrew Lindesay #define TAB_PROMINENT_PACKAGES	0
88ccf707d0SAndrew Lindesay #define TAB_ALL_PACKAGES		1
8904c9d578SStephan Aßmus 
9004c9d578SStephan Aßmus using namespace BPackageKit;
9104c9d578SStephan Aßmus using namespace BPackageKit::BManager::BPrivate;
9204c9d578SStephan Aßmus 
9304c9d578SStephan Aßmus 
9404c9d578SStephan Aßmus typedef std::map<BString, PackageInfoRef> PackageInfoMap;
9504c9d578SStephan Aßmus 
9604c9d578SStephan Aßmus 
9704c9d578SStephan Aßmus struct RefreshWorkerParameters {
9804c9d578SStephan Aßmus 	MainWindow* window;
9904c9d578SStephan Aßmus 	bool forceRefresh;
10004c9d578SStephan Aßmus 
10104c9d578SStephan Aßmus 	RefreshWorkerParameters(MainWindow* window, bool forceRefresh)
10204c9d578SStephan Aßmus 		:
10304c9d578SStephan Aßmus 		window(window),
10404c9d578SStephan Aßmus 		forceRefresh(forceRefresh)
10504c9d578SStephan Aßmus 	{
10604c9d578SStephan Aßmus 	}
10704c9d578SStephan Aßmus };
10804c9d578SStephan Aßmus 
10904c9d578SStephan Aßmus 
11089b16bb4SAndrew Lindesay class MainWindowModelListener : public ModelListener {
1118f03a0f9SStephan Aßmus public:
11289b16bb4SAndrew Lindesay 	MainWindowModelListener(const BMessenger& messenger)
1138f03a0f9SStephan Aßmus 		:
1148f03a0f9SStephan Aßmus 		fMessenger(messenger)
1158f03a0f9SStephan Aßmus 	{
1168f03a0f9SStephan Aßmus 	}
1178f03a0f9SStephan Aßmus 
1188f03a0f9SStephan Aßmus 	virtual void AuthorizationChanged()
1198f03a0f9SStephan Aßmus 	{
1208f03a0f9SStephan Aßmus 		if (fMessenger.IsValid())
1218f03a0f9SStephan Aßmus 			fMessenger.SendMessage(MSG_AUTHORIZATION_CHANGED);
1228f03a0f9SStephan Aßmus 	}
1238f03a0f9SStephan Aßmus 
12489b16bb4SAndrew Lindesay 	virtual void CategoryListChanged()
12589b16bb4SAndrew Lindesay 	{
12689b16bb4SAndrew Lindesay 		if (fMessenger.IsValid())
12789b16bb4SAndrew Lindesay 			fMessenger.SendMessage(MSG_CATEGORIES_LIST_CHANGED);
12889b16bb4SAndrew Lindesay 	}
12989b16bb4SAndrew Lindesay 
130*88af15cfSAndrew Lindesay 	virtual void ScreenshotCached(const ScreenshotCoordinate& coordinate)
131*88af15cfSAndrew Lindesay 	{
132*88af15cfSAndrew Lindesay 		if (fMessenger.IsValid()) {
133*88af15cfSAndrew Lindesay 			BMessage message(MSG_SCREENSHOT_CACHED);
134*88af15cfSAndrew Lindesay 			if (coordinate.Archive(&message) != B_OK)
135*88af15cfSAndrew Lindesay 				debugger("unable to serialize a screenshot coordinate");
136*88af15cfSAndrew Lindesay 			fMessenger.SendMessage(&message);
137*88af15cfSAndrew Lindesay 		}
138*88af15cfSAndrew Lindesay 	}
139*88af15cfSAndrew Lindesay 
1408f03a0f9SStephan Aßmus private:
1418f03a0f9SStephan Aßmus 	BMessenger	fMessenger;
1428f03a0f9SStephan Aßmus };
1438f03a0f9SStephan Aßmus 
1448f03a0f9SStephan Aßmus 
145409af934SAndrew Lindesay class MainWindowPackageInfoListener : public PackageInfoListener {
146409af934SAndrew Lindesay public:
147409af934SAndrew Lindesay 	MainWindowPackageInfoListener(MainWindow* mainWindow)
148409af934SAndrew Lindesay 		:
149409af934SAndrew Lindesay 		fMainWindow(mainWindow)
150409af934SAndrew Lindesay 	{
151409af934SAndrew Lindesay 	}
152409af934SAndrew Lindesay 
153409af934SAndrew Lindesay 	~MainWindowPackageInfoListener()
154409af934SAndrew Lindesay 	{
155409af934SAndrew Lindesay 	}
156409af934SAndrew Lindesay 
157409af934SAndrew Lindesay private:
158409af934SAndrew Lindesay 	// PackageInfoListener
159409af934SAndrew Lindesay 	virtual	void PackageChanged(const PackageInfoEvent& event)
160409af934SAndrew Lindesay 	{
161409af934SAndrew Lindesay 		fMainWindow->PackageChanged(event);
162409af934SAndrew Lindesay 	}
163409af934SAndrew Lindesay 
164409af934SAndrew Lindesay private:
165409af934SAndrew Lindesay 	MainWindow*	fMainWindow;
166409af934SAndrew Lindesay };
167409af934SAndrew Lindesay 
168409af934SAndrew Lindesay 
169f7c2983eSAxel Dörfler MainWindow::MainWindow(const BMessage& settings)
17004c9d578SStephan Aßmus 	:
171f7c2983eSAxel Dörfler 	BWindow(BRect(50, 50, 650, 550), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"),
17204c9d578SStephan Aßmus 		B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
17304c9d578SStephan Aßmus 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
174d5ef985eSStephan Aßmus 	fScreenshotWindow(NULL),
17595c7b018SAndrew Lindesay 	fShuttingDownWindow(NULL),
176e0a26dceSStephan Aßmus 	fUserMenu(NULL),
177e0a26dceSStephan Aßmus 	fLogInItem(NULL),
178e0a26dceSStephan Aßmus 	fLogOutItem(NULL),
179976cadf1SAndrew Lindesay 	fUsersUserUsageConditionsMenuItem(NULL),
18089b16bb4SAndrew Lindesay 	fModelListener(new MainWindowModelListener(BMessenger(this)), true),
18110cd325cSAndrew Lindesay 	fCoordinator(NULL),
18295c7b018SAndrew Lindesay 	fShouldCloseWhenNoProcessesToCoordinate(false),
18384674570SAndrew Lindesay 	fSinglePackageMode(false),
18484674570SAndrew Lindesay 	fIncrementViewCounterDelayedRunner(NULL)
18504c9d578SStephan Aßmus {
18610cd325cSAndrew Lindesay 	if ((fCoordinatorRunningSem = create_sem(1, "ProcessCoordinatorSem")) < B_OK)
18710cd325cSAndrew Lindesay 		debugger("unable to create the process coordinator semaphore");
18810cd325cSAndrew Lindesay 
189409af934SAndrew Lindesay 	fPackageInfoListener = PackageInfoListenerRef(
190409af934SAndrew Lindesay 		new MainWindowPackageInfoListener(this), true);
191409af934SAndrew Lindesay 
192cbadcae1SHumdinger 	BMenuBar* menuBar = new BMenuBar("Main Menu");
19304c9d578SStephan Aßmus 	_BuildMenu(menuBar);
19404c9d578SStephan Aßmus 
195cbadcae1SHumdinger 	BMenuBar* userMenuBar = new BMenuBar("User Menu");
196e0a26dceSStephan Aßmus 	_BuildUserMenu(userMenuBar);
197e0a26dceSStephan Aßmus 	set_small_font(userMenuBar);
198e0a26dceSStephan Aßmus 	userMenuBar->SetExplicitMaxSize(BSize(B_SIZE_UNSET,
199e0a26dceSStephan Aßmus 		menuBar->MaxSize().height));
200e0a26dceSStephan Aßmus 
20104c9d578SStephan Aßmus 	fFilterView = new FilterView();
202f0e491d3SAndrew Lindesay 	fFeaturedPackagesView = new FeaturedPackagesView(fModel);
203f0e491d3SAndrew Lindesay 	fPackageListView = new PackageListView(&fModel);
204f0e491d3SAndrew Lindesay 	fPackageInfoView = new PackageInfoView(&fModel, this);
20504c9d578SStephan Aßmus 
20604c9d578SStephan Aßmus 	fSplitView = new BSplitView(B_VERTICAL, 5.0f);
20704c9d578SStephan Aßmus 
208125d42d9SJulian Harnath 	fWorkStatusView = new WorkStatusView("work status");
209125d42d9SJulian Harnath 	fPackageListView->AttachWorkStatusView(fWorkStatusView);
210125d42d9SJulian Harnath 
211e00a489bSAugustin Cavalier 	fListTabs = new TabView(BMessenger(this),
212ccf707d0SAndrew Lindesay 		BMessage(MSG_CHANGE_PACKAGE_LIST_VIEW_MODE), "list tabs");
213e00a489bSAugustin Cavalier 	fListTabs->AddTab(fFeaturedPackagesView);
214e00a489bSAugustin Cavalier 	fListTabs->AddTab(fPackageListView);
2154b930ccaSStephan Aßmus 
21604c9d578SStephan Aßmus 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f)
217e0a26dceSStephan Aßmus 		.AddGroup(B_HORIZONTAL, 0.0f)
218e0a26dceSStephan Aßmus 			.Add(menuBar, 1.0f)
219e0a26dceSStephan Aßmus 			.Add(userMenuBar, 0.0f)
220e0a26dceSStephan Aßmus 		.End()
22104c9d578SStephan Aßmus 		.Add(fFilterView)
22204c9d578SStephan Aßmus 		.AddSplit(fSplitView)
22304c9d578SStephan Aßmus 			.AddGroup(B_VERTICAL)
224e00a489bSAugustin Cavalier 				.Add(fListTabs)
22504c9d578SStephan Aßmus 				.SetInsets(
22604c9d578SStephan Aßmus 					B_USE_DEFAULT_SPACING, 0.0f,
22704c9d578SStephan Aßmus 					B_USE_DEFAULT_SPACING, 0.0f)
22804c9d578SStephan Aßmus 			.End()
22904c9d578SStephan Aßmus 			.Add(fPackageInfoView)
23004c9d578SStephan Aßmus 		.End()
231125d42d9SJulian Harnath 		.Add(fWorkStatusView)
23204c9d578SStephan Aßmus 	;
23304c9d578SStephan Aßmus 
23404c9d578SStephan Aßmus 	fSplitView->SetCollapsible(0, false);
23504c9d578SStephan Aßmus 	fSplitView->SetCollapsible(1, false);
23604c9d578SStephan Aßmus 
2378f03a0f9SStephan Aßmus 	fModel.AddListener(fModelListener);
2388f03a0f9SStephan Aßmus 
23904c9d578SStephan Aßmus 	BMessage columnSettings;
24004c9d578SStephan Aßmus 	if (settings.FindMessage("column settings", &columnSettings) == B_OK)
24104c9d578SStephan Aßmus 		fPackageListView->LoadState(&columnSettings);
24204c9d578SStephan Aßmus 
243ccf707d0SAndrew Lindesay 	_RestoreModelSettings(settings);
244133ebab6SAndrew Lindesay 	_MaybePromptCanShareAnonymousUserData(settings);
24504c9d578SStephan Aßmus 
246ccf707d0SAndrew Lindesay 	if (fModel.PackageListViewMode() == PROMINENT)
247ccf707d0SAndrew Lindesay 		fListTabs->Select(TAB_PROMINENT_PACKAGES);
2482997e05bSStephan Aßmus 	else
249ccf707d0SAndrew Lindesay 		fListTabs->Select(TAB_ALL_PACKAGES);
2502997e05bSStephan Aßmus 
251d2d4866dSAndrew Lindesay 	_RestoreNickname(settings);
25210cd325cSAndrew Lindesay 	_UpdateAuthorization();
253f7c2983eSAxel Dörfler 	_RestoreWindowFrame(settings);
254f7c2983eSAxel Dörfler 
2558f03a0f9SStephan Aßmus 	// start worker threads
25604c9d578SStephan Aßmus 	BPackageRoster().StartWatching(this,
25704c9d578SStephan Aßmus 		B_WATCH_PACKAGE_INSTALLATION_LOCATIONS);
25804c9d578SStephan Aßmus 
25963975654SStephan Aßmus 	_InitWorkerThreads();
2609883929bSAndrew Lindesay 	_AdoptModel();
2619883929bSAndrew Lindesay 	_StartBulkLoad();
26204c9d578SStephan Aßmus }
26304c9d578SStephan Aßmus 
26404c9d578SStephan Aßmus 
265afe7affbSAndrew Lindesay MainWindow::MainWindow(const BMessage& settings, PackageInfoRef& package)
2666d519fd1SStephan Aßmus 	:
267f7c2983eSAxel Dörfler 	BWindow(BRect(50, 50, 650, 350), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"),
2686d519fd1SStephan Aßmus 		B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
2696d519fd1SStephan Aßmus 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
2709883929bSAndrew Lindesay 	fFeaturedPackagesView(NULL),
2719883929bSAndrew Lindesay 	fPackageListView(NULL),
272d78bfd8dSJulian Harnath 	fWorkStatusView(NULL),
273d5ef985eSStephan Aßmus 	fScreenshotWindow(NULL),
27495c7b018SAndrew Lindesay 	fShuttingDownWindow(NULL),
275e0a26dceSStephan Aßmus 	fUserMenu(NULL),
276e0a26dceSStephan Aßmus 	fLogInItem(NULL),
2776d519fd1SStephan Aßmus 	fLogOutItem(NULL),
278976cadf1SAndrew Lindesay 	fUsersUserUsageConditionsMenuItem(NULL),
27989b16bb4SAndrew Lindesay 	fModelListener(new MainWindowModelListener(BMessenger(this)), true),
28010cd325cSAndrew Lindesay 	fCoordinator(NULL),
28195c7b018SAndrew Lindesay 	fShouldCloseWhenNoProcessesToCoordinate(false),
28284674570SAndrew Lindesay 	fSinglePackageMode(true),
28384674570SAndrew Lindesay 	fIncrementViewCounterDelayedRunner(NULL)
2846d519fd1SStephan Aßmus {
28510cd325cSAndrew Lindesay 	if ((fCoordinatorRunningSem = create_sem(1, "ProcessCoordinatorSem")) < B_OK)
28610cd325cSAndrew Lindesay 		debugger("unable to create the process coordinator semaphore");
28710cd325cSAndrew Lindesay 
288409af934SAndrew Lindesay 	fPackageInfoListener = PackageInfoListenerRef(
289409af934SAndrew Lindesay 		new MainWindowPackageInfoListener(this), true);
290409af934SAndrew Lindesay 
2916d519fd1SStephan Aßmus 	fFilterView = new FilterView();
292f0e491d3SAndrew Lindesay 	fPackageInfoView = new PackageInfoView(&fModel, this);
29387016f8fSAndrew Lindesay 	fWorkStatusView = new WorkStatusView("work status");
2946d519fd1SStephan Aßmus 
2956d519fd1SStephan Aßmus 	BLayoutBuilder::Group<>(this, B_VERTICAL)
2966d519fd1SStephan Aßmus 		.Add(fPackageInfoView)
29787016f8fSAndrew Lindesay 		.Add(fWorkStatusView)
2986d519fd1SStephan Aßmus 		.SetInsets(0, B_USE_WINDOW_INSETS, 0, 0)
2996d519fd1SStephan Aßmus 	;
3006d519fd1SStephan Aßmus 
3016d519fd1SStephan Aßmus 	fModel.AddListener(fModelListener);
3026d519fd1SStephan Aßmus 
303afe7affbSAndrew Lindesay 	// add the single package into the model so that any internal
304afe7affbSAndrew Lindesay 	// business logic is able to find the package.
305afe7affbSAndrew Lindesay 	DepotInfoRef depot(new DepotInfo("single-pkg-depot"), true);
306afe7affbSAndrew Lindesay 	depot->AddPackage(package);
307afe7affbSAndrew Lindesay 	fModel.MergeOrAddDepot(depot);
308afe7affbSAndrew Lindesay 
3096d519fd1SStephan Aßmus 	// Restore settings
310d2d4866dSAndrew Lindesay 	_RestoreNickname(settings);
311ccf707d0SAndrew Lindesay 	_UpdateAuthorization();
312f7c2983eSAxel Dörfler 	_RestoreWindowFrame(settings);
3136d519fd1SStephan Aßmus 
3146d519fd1SStephan Aßmus 	fPackageInfoView->SetPackage(package);
31563975654SStephan Aßmus 
316afe7affbSAndrew Lindesay 	// start worker threads
317afe7affbSAndrew Lindesay 	BPackageRoster().StartWatching(this,
318afe7affbSAndrew Lindesay 		B_WATCH_PACKAGE_INSTALLATION_LOCATIONS);
319afe7affbSAndrew Lindesay 
32063975654SStephan Aßmus 	_InitWorkerThreads();
3216d519fd1SStephan Aßmus }
3226d519fd1SStephan Aßmus 
3236d519fd1SStephan Aßmus 
32404c9d578SStephan Aßmus MainWindow::~MainWindow()
32504c9d578SStephan Aßmus {
32610cd325cSAndrew Lindesay 	_SpinUntilProcessCoordinatorComplete();
32710cd325cSAndrew Lindesay 	delete_sem(fCoordinatorRunningSem);
32810cd325cSAndrew Lindesay 	fCoordinatorRunningSem = 0;
32910cd325cSAndrew Lindesay 
33004c9d578SStephan Aßmus 	BPackageRoster().StopWatching(this);
33104c9d578SStephan Aßmus 
33295c7b018SAndrew Lindesay 	if (fScreenshotWindow != NULL) {
33395c7b018SAndrew Lindesay 		if (fScreenshotWindow->Lock())
334d5ef985eSStephan Aßmus 			fScreenshotWindow->Quit();
33504c9d578SStephan Aßmus 	}
33604c9d578SStephan Aßmus 
33795c7b018SAndrew Lindesay 	if (fShuttingDownWindow != NULL) {
33895c7b018SAndrew Lindesay 		if (fShuttingDownWindow->Lock())
33995c7b018SAndrew Lindesay 			fShuttingDownWindow->Quit();
34095c7b018SAndrew Lindesay 	}
341d5562247SAugustin Cavalier 
342a3866854SAugustin Cavalier 	delete_sem(fPackageToPopulateSem);
343a3866854SAugustin Cavalier 	wait_for_thread(fPopulatePackageWorker, NULL);
344a3866854SAugustin Cavalier 
3454329a83fSAugustin Cavalier 	// We must clear the model early to release references.
346d5562247SAugustin Cavalier 	fModel.Clear();
34795c7b018SAndrew Lindesay }
34895c7b018SAndrew Lindesay 
34904c9d578SStephan Aßmus 
35004c9d578SStephan Aßmus bool
35104c9d578SStephan Aßmus MainWindow::QuitRequested()
35204c9d578SStephan Aßmus {
35304c9d578SStephan Aßmus 
35410cd325cSAndrew Lindesay 	_StopProcessCoordinators();
3553369e03dSAndrew Lindesay 
35695c7b018SAndrew Lindesay 	// If there are any processes in flight we need to be careful to make
35795c7b018SAndrew Lindesay 	// sure that they are cleanly completed before actually quitting.  By
35895c7b018SAndrew Lindesay 	// turning on the `fShouldCloseWhenNoProcessesToCoordinate` flag, when
35995c7b018SAndrew Lindesay 	// the process coordination has completed then it will detect this and
36095c7b018SAndrew Lindesay 	// quit again.
36195c7b018SAndrew Lindesay 
36295c7b018SAndrew Lindesay 	{
36395c7b018SAndrew Lindesay 		AutoLocker<BLocker> lock(&fCoordinatorLock);
36495c7b018SAndrew Lindesay 		fShouldCloseWhenNoProcessesToCoordinate = true;
36595c7b018SAndrew Lindesay 
366409af934SAndrew Lindesay 		if (fCoordinator != NULL) {
36795c7b018SAndrew Lindesay 			HDINFO("a coordinator is running --> will wait before quitting...");
36895c7b018SAndrew Lindesay 
36995c7b018SAndrew Lindesay 			if (fShuttingDownWindow == NULL)
37095c7b018SAndrew Lindesay 				fShuttingDownWindow = new ShuttingDownWindow(this);
37195c7b018SAndrew Lindesay 			fShuttingDownWindow->Show();
37295c7b018SAndrew Lindesay 
37395c7b018SAndrew Lindesay 			return false;
37495c7b018SAndrew Lindesay 		}
37595c7b018SAndrew Lindesay 	}
37695c7b018SAndrew Lindesay 
37795c7b018SAndrew Lindesay 	BMessage settings;
37895c7b018SAndrew Lindesay 	StoreSettings(settings);
37995c7b018SAndrew Lindesay 	BMessage message(MSG_MAIN_WINDOW_CLOSED);
38095c7b018SAndrew Lindesay 	message.AddMessage(KEY_WINDOW_SETTINGS, &settings);
38195c7b018SAndrew Lindesay 	be_app->PostMessage(&message);
38295c7b018SAndrew Lindesay 
38395c7b018SAndrew Lindesay 	if (fShuttingDownWindow != NULL) {
38495c7b018SAndrew Lindesay 		if (fShuttingDownWindow->Lock())
38595c7b018SAndrew Lindesay 			fShuttingDownWindow->Quit();
38695c7b018SAndrew Lindesay 		fShuttingDownWindow = NULL;
38795c7b018SAndrew Lindesay 	}
38895c7b018SAndrew Lindesay 
38904c9d578SStephan Aßmus 	return true;
39004c9d578SStephan Aßmus }
39104c9d578SStephan Aßmus 
39204c9d578SStephan Aßmus 
39304c9d578SStephan Aßmus void
39404c9d578SStephan Aßmus MainWindow::MessageReceived(BMessage* message)
39504c9d578SStephan Aßmus {
39604c9d578SStephan Aßmus 	switch (message->what) {
3973369e03dSAndrew Lindesay 		case MSG_BULK_LOAD_DONE:
39810cd325cSAndrew Lindesay 		{
39910cd325cSAndrew Lindesay 			int64 errorStatus64;
40010cd325cSAndrew Lindesay 			if (message->FindInt64(KEY_ERROR_STATUS, &errorStatus64) == B_OK)
40110cd325cSAndrew Lindesay 				_BulkLoadCompleteReceived((status_t) errorStatus64);
40210cd325cSAndrew Lindesay 			else
403fa5c8097SAndrew Lindesay 				HDERROR("expected [%s] value in message", KEY_ERROR_STATUS);
40404c9d578SStephan Aßmus 			break;
40510cd325cSAndrew Lindesay 		}
40604c9d578SStephan Aßmus 		case B_SIMPLE_DATA:
40704c9d578SStephan Aßmus 		case B_REFS_RECEIVED:
40804c9d578SStephan Aßmus 			// TODO: ?
40904c9d578SStephan Aßmus 			break;
41004c9d578SStephan Aßmus 
41104c9d578SStephan Aßmus 		case B_PACKAGE_UPDATE:
412f32d5c5cSAndrew Lindesay 			_HandleExternalPackageUpdateMessageReceived(message);
41304c9d578SStephan Aßmus 			break;
41404c9d578SStephan Aßmus 
4155bf2b6ebSBrian Hill 		case MSG_REFRESH_REPOS:
4163369e03dSAndrew Lindesay 			_StartBulkLoad(true);
4173369e03dSAndrew Lindesay 			break;
4183369e03dSAndrew Lindesay 
41910cd325cSAndrew Lindesay 		case MSG_WORK_STATUS_CLEAR:
42010cd325cSAndrew Lindesay 			_HandleWorkStatusClear();
42110cd325cSAndrew Lindesay 			break;
42210cd325cSAndrew Lindesay 
4233369e03dSAndrew Lindesay 		case MSG_WORK_STATUS_CHANGE:
4243369e03dSAndrew Lindesay 			_HandleWorkStatusChangeMessageReceived(message);
42504c9d578SStephan Aßmus 			break;
42604c9d578SStephan Aßmus 
4275bf2b6ebSBrian Hill 		case MSG_MANAGE_REPOS:
4285bf2b6ebSBrian Hill 			be_roster->Launch("application/x-vnd.Haiku-Repositories");
4295bf2b6ebSBrian Hill 			break;
4305bf2b6ebSBrian Hill 
431d144f952SAugustin Cavalier 		case MSG_SOFTWARE_UPDATER:
432d144f952SAugustin Cavalier 			be_roster->Launch("application/x-vnd.haiku-softwareupdater");
433d144f952SAugustin Cavalier 			break;
434d144f952SAugustin Cavalier 
43504c9d578SStephan Aßmus 		case MSG_LOG_IN:
4361bbda92dSStephan Aßmus 			_OpenLoginWindow(BMessage());
43704c9d578SStephan Aßmus 			break;
43804c9d578SStephan Aßmus 
439133ebab6SAndrew Lindesay 		case MSG_SETTINGS:
440133ebab6SAndrew Lindesay 			_OpenSettingsWindow();
441133ebab6SAndrew Lindesay 			break;
442133ebab6SAndrew Lindesay 
4438f03a0f9SStephan Aßmus 		case MSG_LOG_OUT:
444d2d4866dSAndrew Lindesay 			fModel.SetNickname("");
4458f03a0f9SStephan Aßmus 			break;
4468f03a0f9SStephan Aßmus 
44701339a54SAndrew Lindesay 		case MSG_VIEW_LATEST_USER_USAGE_CONDITIONS:
448d2d4866dSAndrew Lindesay 			_ViewUserUsageConditions(LATEST);
449d2d4866dSAndrew Lindesay 			break;
450d2d4866dSAndrew Lindesay 
451d2d4866dSAndrew Lindesay 		case MSG_VIEW_USERS_USER_USAGE_CONDITIONS:
452d2d4866dSAndrew Lindesay 			_ViewUserUsageConditions(USER);
45301339a54SAndrew Lindesay 			break;
45401339a54SAndrew Lindesay 
4558f03a0f9SStephan Aßmus 		case MSG_AUTHORIZATION_CHANGED:
45610cd325cSAndrew Lindesay 			_StartUserVerify();
4578f03a0f9SStephan Aßmus 			_UpdateAuthorization();
4588f03a0f9SStephan Aßmus 			break;
4598f03a0f9SStephan Aßmus 
460*88af15cfSAndrew Lindesay 		case MSG_SCREENSHOT_CACHED:
461*88af15cfSAndrew Lindesay 			_HandleScreenshotCached(message);
462*88af15cfSAndrew Lindesay 			break;
463*88af15cfSAndrew Lindesay 
46489b16bb4SAndrew Lindesay 		case MSG_CATEGORIES_LIST_CHANGED:
46589b16bb4SAndrew Lindesay 			fFilterView->AdoptModel(fModel);
46689b16bb4SAndrew Lindesay 			break;
46789b16bb4SAndrew Lindesay 
468ccf707d0SAndrew Lindesay 		case MSG_CHANGE_PACKAGE_LIST_VIEW_MODE:
469ccf707d0SAndrew Lindesay 			_HandleChangePackageListViewMode();
4704fade61fSStephan Aßmus 			break;
4714fade61fSStephan Aßmus 
472fdec4227SStephan Aßmus 		case MSG_SHOW_AVAILABLE_PACKAGES:
473fdec4227SStephan Aßmus 			{
474fdec4227SStephan Aßmus 				BAutolock locker(fModel.Lock());
475fdec4227SStephan Aßmus 				fModel.SetShowAvailablePackages(
476fdec4227SStephan Aßmus 					!fModel.ShowAvailablePackages());
477fdec4227SStephan Aßmus 			}
478fdec4227SStephan Aßmus 			_AdoptModel();
479fdec4227SStephan Aßmus 			break;
480fdec4227SStephan Aßmus 
481fdec4227SStephan Aßmus 		case MSG_SHOW_INSTALLED_PACKAGES:
482fdec4227SStephan Aßmus 			{
483fdec4227SStephan Aßmus 				BAutolock locker(fModel.Lock());
484fdec4227SStephan Aßmus 				fModel.SetShowInstalledPackages(
485fdec4227SStephan Aßmus 					!fModel.ShowInstalledPackages());
486fdec4227SStephan Aßmus 			}
487fdec4227SStephan Aßmus 			_AdoptModel();
488fdec4227SStephan Aßmus 			break;
489fdec4227SStephan Aßmus 
49004c9d578SStephan Aßmus 		case MSG_SHOW_SOURCE_PACKAGES:
49104c9d578SStephan Aßmus 			{
49204c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
49304c9d578SStephan Aßmus 				fModel.SetShowSourcePackages(!fModel.ShowSourcePackages());
49404c9d578SStephan Aßmus 			}
49504c9d578SStephan Aßmus 			_AdoptModel();
49604c9d578SStephan Aßmus 			break;
49704c9d578SStephan Aßmus 
49804c9d578SStephan Aßmus 		case MSG_SHOW_DEVELOP_PACKAGES:
49904c9d578SStephan Aßmus 			{
50004c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
50104c9d578SStephan Aßmus 				fModel.SetShowDevelopPackages(!fModel.ShowDevelopPackages());
50204c9d578SStephan Aßmus 			}
50304c9d578SStephan Aßmus 			_AdoptModel();
50404c9d578SStephan Aßmus 			break;
50504c9d578SStephan Aßmus 
506a9edb9bfSAndrew Lindesay 			// this may be triggered by, for example, a user rating being added
507a9edb9bfSAndrew Lindesay 			// or having been altered.
508a9edb9bfSAndrew Lindesay 		case MSG_SERVER_DATA_CHANGED:
509a9edb9bfSAndrew Lindesay 		{
510a9edb9bfSAndrew Lindesay 			BString name;
511a9edb9bfSAndrew Lindesay 			if (message->FindString("name", &name) == B_OK) {
512a9edb9bfSAndrew Lindesay 				BAutolock locker(fModel.Lock());
513a9edb9bfSAndrew Lindesay 				if (fPackageInfoView->Package()->Name() == name) {
514a9edb9bfSAndrew Lindesay 					_PopulatePackageAsync(true);
515a9edb9bfSAndrew Lindesay 				} else {
516f96d1f4dSAndrew Lindesay 					HDDEBUG("pkg [%s] is updated on the server, but is "
517f96d1f4dSAndrew Lindesay 						"not selected so will not be updated.",
518fa5c8097SAndrew Lindesay 						name.String());
519a9edb9bfSAndrew Lindesay 				}
520a9edb9bfSAndrew Lindesay 			}
521a9edb9bfSAndrew Lindesay 			break;
522a9edb9bfSAndrew Lindesay 		}
523a9edb9bfSAndrew Lindesay 
52484674570SAndrew Lindesay 		case MSG_INCREMENT_VIEW_COUNTER:
52584674570SAndrew Lindesay 			_HandleIncrementViewCounter(message);
52684674570SAndrew Lindesay 			break;
52784674570SAndrew Lindesay 
52804c9d578SStephan Aßmus 		case MSG_PACKAGE_SELECTED:
52904c9d578SStephan Aßmus 		{
53072992391SStephan Aßmus 			BString name;
53172992391SStephan Aßmus 			if (message->FindString("name", &name) == B_OK) {
532c4199192SAndrew Lindesay 				PackageInfoRef package;
533c4199192SAndrew Lindesay 				{
53475ba9dbfSStephan Aßmus 					BAutolock locker(fModel.Lock());
535c4199192SAndrew Lindesay 					package = fModel.PackageForName(name);
536c4199192SAndrew Lindesay 				}
5376f07feadSAndrew Lindesay 				if (!package.IsSet() || name != package->Name())
538c4199192SAndrew Lindesay 					debugger("unable to find the named package");
539133ebab6SAndrew Lindesay 				else {
54004c9d578SStephan Aßmus 					_AdoptPackage(package);
54184674570SAndrew Lindesay 					_SetupDelayedIncrementViewCounter(package);
542133ebab6SAndrew Lindesay 				}
54304c9d578SStephan Aßmus 			} else {
54404c9d578SStephan Aßmus 				_ClearPackage();
54504c9d578SStephan Aßmus 			}
54604c9d578SStephan Aßmus 			break;
54704c9d578SStephan Aßmus 		}
54804c9d578SStephan Aßmus 
54904c9d578SStephan Aßmus 		case MSG_CATEGORY_SELECTED:
55004c9d578SStephan Aßmus 		{
55189b16bb4SAndrew Lindesay 			BString code;
55289b16bb4SAndrew Lindesay 			if (message->FindString("code", &code) != B_OK)
55389b16bb4SAndrew Lindesay 				code = "";
55404c9d578SStephan Aßmus 			{
55504c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
55689b16bb4SAndrew Lindesay 				fModel.SetCategory(code);
55704c9d578SStephan Aßmus 			}
55804c9d578SStephan Aßmus 			_AdoptModel();
55904c9d578SStephan Aßmus 			break;
56004c9d578SStephan Aßmus 		}
56104c9d578SStephan Aßmus 
56204c9d578SStephan Aßmus 		case MSG_DEPOT_SELECTED:
56304c9d578SStephan Aßmus 		{
56404c9d578SStephan Aßmus 			BString name;
56504c9d578SStephan Aßmus 			if (message->FindString("name", &name) != B_OK)
56604c9d578SStephan Aßmus 				name = "";
56704c9d578SStephan Aßmus 			{
56804c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
56904c9d578SStephan Aßmus 				fModel.SetDepot(name);
57004c9d578SStephan Aßmus 			}
57104c9d578SStephan Aßmus 			_AdoptModel();
572b965ce70SHumdinger 			_UpdateAvailableRepositories();
57304c9d578SStephan Aßmus 			break;
57404c9d578SStephan Aßmus 		}
57504c9d578SStephan Aßmus 
57604c9d578SStephan Aßmus 		case MSG_SEARCH_TERMS_MODIFIED:
57704c9d578SStephan Aßmus 		{
57804c9d578SStephan Aßmus 			// TODO: Do this with a delay!
57904c9d578SStephan Aßmus 			BString searchTerms;
58004c9d578SStephan Aßmus 			if (message->FindString("search terms", &searchTerms) != B_OK)
58104c9d578SStephan Aßmus 				searchTerms = "";
58204c9d578SStephan Aßmus 			{
58304c9d578SStephan Aßmus 				BAutolock locker(fModel.Lock());
58404c9d578SStephan Aßmus 				fModel.SetSearchTerms(searchTerms);
58504c9d578SStephan Aßmus 			}
58604c9d578SStephan Aßmus 			_AdoptModel();
58704c9d578SStephan Aßmus 			break;
58804c9d578SStephan Aßmus 		}
58904c9d578SStephan Aßmus 
590da651104SStephan Aßmus 		case MSG_PACKAGE_CHANGED:
59104c9d578SStephan Aßmus 		{
59204c9d578SStephan Aßmus 			PackageInfo* info;
59304c9d578SStephan Aßmus 			if (message->FindPointer("package", (void**)&info) == B_OK) {
59404c9d578SStephan Aßmus 				PackageInfoRef ref(info, true);
5950b69420bSAndrew Lindesay 				fFeaturedPackagesView->BeginAddRemove();
596c4199192SAndrew Lindesay 				_AddRemovePackageFromLists(ref);
5970b69420bSAndrew Lindesay 				fFeaturedPackagesView->EndAddRemove();
59810cd325cSAndrew Lindesay 			}
59904c9d578SStephan Aßmus 			break;
60004c9d578SStephan Aßmus 		}
60104c9d578SStephan Aßmus 
602409af934SAndrew Lindesay 		case MSG_PROCESS_COORDINATOR_CHANGED:
603409af934SAndrew Lindesay 		{
604409af934SAndrew Lindesay 			ProcessCoordinatorState state(message);
605409af934SAndrew Lindesay 			_HandleProcessCoordinatorChanged(state);
606409af934SAndrew Lindesay 			break;
607409af934SAndrew Lindesay 		}
608409af934SAndrew Lindesay 
60904c9d578SStephan Aßmus 		case MSG_RATE_PACKAGE:
6101bbda92dSStephan Aßmus 			_RatePackage();
61104c9d578SStephan Aßmus 			break;
61204c9d578SStephan Aßmus 
613d5ef985eSStephan Aßmus 		case MSG_SHOW_SCREENSHOT:
614d5ef985eSStephan Aßmus 			_ShowScreenshot();
615d5ef985eSStephan Aßmus 			break;
616d5ef985eSStephan Aßmus 
617125d42d9SJulian Harnath 		case MSG_PACKAGE_WORKER_BUSY:
618125d42d9SJulian Harnath 		{
619125d42d9SJulian Harnath 			BString reason;
620125d42d9SJulian Harnath 			status_t status = message->FindString("reason", &reason);
621125d42d9SJulian Harnath 			if (status != B_OK)
622125d42d9SJulian Harnath 				break;
623125d42d9SJulian Harnath 			fWorkStatusView->SetBusy(reason);
624125d42d9SJulian Harnath 			break;
625125d42d9SJulian Harnath 		}
626125d42d9SJulian Harnath 
627125d42d9SJulian Harnath 		case MSG_PACKAGE_WORKER_IDLE:
628125d42d9SJulian Harnath 			fWorkStatusView->SetIdle();
629125d42d9SJulian Harnath 			break;
630125d42d9SJulian Harnath 
63110cd325cSAndrew Lindesay 		case MSG_USER_USAGE_CONDITIONS_NOT_LATEST:
63210cd325cSAndrew Lindesay 		{
63310cd325cSAndrew Lindesay 			BMessage userDetailMsg;
63410cd325cSAndrew Lindesay 			if (message->FindMessage("userDetail", &userDetailMsg) != B_OK) {
63510cd325cSAndrew Lindesay 				debugger("expected the [userDetail] data to be carried in the "
63610cd325cSAndrew Lindesay 					"message.");
63710cd325cSAndrew Lindesay 			}
63810cd325cSAndrew Lindesay 			UserDetail userDetail(&userDetailMsg);
63910cd325cSAndrew Lindesay 			_HandleUserUsageConditionsNotLatest(userDetail);
64010cd325cSAndrew Lindesay 			break;
64110cd325cSAndrew Lindesay 		}
64210cd325cSAndrew Lindesay 
64304c9d578SStephan Aßmus 		default:
64404c9d578SStephan Aßmus 			BWindow::MessageReceived(message);
64504c9d578SStephan Aßmus 			break;
64604c9d578SStephan Aßmus 	}
64704c9d578SStephan Aßmus }
64804c9d578SStephan Aßmus 
64904c9d578SStephan Aßmus 
650ccf707d0SAndrew Lindesay static const char*
651ccf707d0SAndrew Lindesay main_window_package_list_view_mode_str(package_list_view_mode mode)
652ccf707d0SAndrew Lindesay {
653ccf707d0SAndrew Lindesay 	if (mode == PROMINENT)
654ccf707d0SAndrew Lindesay 		return "PROMINENT";
655ccf707d0SAndrew Lindesay 	return "ALL";
656ccf707d0SAndrew Lindesay }
657ccf707d0SAndrew Lindesay 
658ccf707d0SAndrew Lindesay 
659ccf707d0SAndrew Lindesay static package_list_view_mode
660ccf707d0SAndrew Lindesay main_window_str_to_package_list_view_mode(const BString& str)
661ccf707d0SAndrew Lindesay {
662ccf707d0SAndrew Lindesay 	if (str == "PROMINENT")
663ccf707d0SAndrew Lindesay 		return PROMINENT;
664ccf707d0SAndrew Lindesay 	return ALL;
665ccf707d0SAndrew Lindesay }
666ccf707d0SAndrew Lindesay 
667ccf707d0SAndrew Lindesay 
66804c9d578SStephan Aßmus void
6694b347fccSAndrew Lindesay MainWindow::StoreSettings(BMessage& settings)
67004c9d578SStephan Aßmus {
671f7c2983eSAxel Dörfler 	settings.AddRect(_WindowFrameName(), Frame());
672f7c2983eSAxel Dörfler 	if (!fSinglePackageMode) {
67304c9d578SStephan Aßmus 		settings.AddRect("window frame", Frame());
67404c9d578SStephan Aßmus 
67504c9d578SStephan Aßmus 		BMessage columnSettings;
6769883929bSAndrew Lindesay 		if (fPackageListView != NULL)
67704c9d578SStephan Aßmus 			fPackageListView->SaveState(&columnSettings);
67804c9d578SStephan Aßmus 
67904c9d578SStephan Aßmus 		settings.AddMessage("column settings", &columnSettings);
68004c9d578SStephan Aßmus 
681133ebab6SAndrew Lindesay 		settings.AddString(SETTING_PACKAGE_LIST_VIEW_MODE,
682ccf707d0SAndrew Lindesay 			main_window_package_list_view_mode_str(
683ccf707d0SAndrew Lindesay 				fModel.PackageListViewMode()));
684133ebab6SAndrew Lindesay 		settings.AddBool(SETTING_SHOW_AVAILABLE_PACKAGES,
6852997e05bSStephan Aßmus 			fModel.ShowAvailablePackages());
686133ebab6SAndrew Lindesay 		settings.AddBool(SETTING_SHOW_INSTALLED_PACKAGES,
6872997e05bSStephan Aßmus 			fModel.ShowInstalledPackages());
688133ebab6SAndrew Lindesay 		settings.AddBool(SETTING_SHOW_DEVELOP_PACKAGES,
689133ebab6SAndrew Lindesay 			fModel.ShowDevelopPackages());
690133ebab6SAndrew Lindesay 		settings.AddBool(SETTING_SHOW_SOURCE_PACKAGES,
691133ebab6SAndrew Lindesay 			fModel.ShowSourcePackages());
692133ebab6SAndrew Lindesay 		settings.AddBool(SETTING_CAN_SHARE_ANONYMOUS_USER_DATA,
693133ebab6SAndrew Lindesay 			fModel.CanShareAnonymousUsageData());
6946d519fd1SStephan Aßmus 	}
6958f03a0f9SStephan Aßmus 
696d2d4866dSAndrew Lindesay 	settings.AddString("username", fModel.Nickname());
69704c9d578SStephan Aßmus }
69804c9d578SStephan Aßmus 
69904c9d578SStephan Aßmus 
70004c9d578SStephan Aßmus void
701a18f873fSAndrew Lindesay MainWindow::Consume(ProcessCoordinator *item)
702a18f873fSAndrew Lindesay {
703a18f873fSAndrew Lindesay 	_AddProcessCoordinator(item);
704a18f873fSAndrew Lindesay }
705a18f873fSAndrew Lindesay 
706a18f873fSAndrew Lindesay 
707a18f873fSAndrew Lindesay void
70804c9d578SStephan Aßmus MainWindow::PackageChanged(const PackageInfoEvent& event)
70904c9d578SStephan Aßmus {
710a9edb9bfSAndrew Lindesay 	uint32 watchedChanges = PKG_CHANGED_STATE | PKG_CHANGED_PROMINENCE;
711a9edb9bfSAndrew Lindesay 	if ((event.Changes() & watchedChanges) != 0) {
71204c9d578SStephan Aßmus 		PackageInfoRef ref(event.Package());
713da651104SStephan Aßmus 		BMessage message(MSG_PACKAGE_CHANGED);
71404c9d578SStephan Aßmus 		message.AddPointer("package", ref.Get());
71504c9d578SStephan Aßmus 		ref.Detach();
71604c9d578SStephan Aßmus 			// reference needs to be released by MessageReceived();
71704c9d578SStephan Aßmus 		PostMessage(&message);
71804c9d578SStephan Aßmus 	}
71904c9d578SStephan Aßmus }
72004c9d578SStephan Aßmus 
72104c9d578SStephan Aßmus 
72204c9d578SStephan Aßmus void
72304c9d578SStephan Aßmus MainWindow::_BuildMenu(BMenuBar* menuBar)
72404c9d578SStephan Aßmus {
7250b6928f1SHumdinger 	BMenu* menu = new BMenu(B_TRANSLATE_SYSTEM_NAME("HaikuDepot"));
7263369e03dSAndrew Lindesay 	fRefreshRepositoriesItem = new BMenuItem(
7273369e03dSAndrew Lindesay 		B_TRANSLATE("Refresh repositories"), new BMessage(MSG_REFRESH_REPOS));
7283369e03dSAndrew Lindesay 	menu->AddItem(fRefreshRepositoriesItem);
729d7f78130SHumdinger 	menu->AddItem(new BMenuItem(B_TRANSLATE("Manage repositories"
730d7f78130SHumdinger 		B_UTF8_ELLIPSIS), new BMessage(MSG_MANAGE_REPOS)));
731d144f952SAugustin Cavalier 	menu->AddItem(new BMenuItem(B_TRANSLATE("Check for updates"
732d144f952SAugustin Cavalier 		B_UTF8_ELLIPSIS), new BMessage(MSG_SOFTWARE_UPDATER)));
7330b6928f1SHumdinger 	menu->AddSeparatorItem();
7340b6928f1SHumdinger 	menu->AddItem(new BMenuItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS),
735e1ae57abSJoachim Mairböck 		new BMessage(MSG_SETTINGS), ','));
7360b6928f1SHumdinger 	menu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
7370b6928f1SHumdinger 		new BMessage(B_QUIT_REQUESTED), 'Q'));
73804c9d578SStephan Aßmus 	menuBar->AddItem(menu);
73904c9d578SStephan Aßmus 
740b965ce70SHumdinger 	fRepositoryMenu = new BMenu(B_TRANSLATE("Repositories"));
741b965ce70SHumdinger 	menuBar->AddItem(fRepositoryMenu);
742b965ce70SHumdinger 
7434fade61fSStephan Aßmus 	menu = new BMenu(B_TRANSLATE("Show"));
7444fade61fSStephan Aßmus 
745fdec4227SStephan Aßmus 	fShowAvailablePackagesItem = new BMenuItem(
7464fade61fSStephan Aßmus 		B_TRANSLATE("Available packages"),
747fdec4227SStephan Aßmus 		new BMessage(MSG_SHOW_AVAILABLE_PACKAGES));
748fdec4227SStephan Aßmus 	menu->AddItem(fShowAvailablePackagesItem);
749fdec4227SStephan Aßmus 
750fdec4227SStephan Aßmus 	fShowInstalledPackagesItem = new BMenuItem(
7514fade61fSStephan Aßmus 		B_TRANSLATE("Installed packages"),
752fdec4227SStephan Aßmus 		new BMessage(MSG_SHOW_INSTALLED_PACKAGES));
753fdec4227SStephan Aßmus 	menu->AddItem(fShowInstalledPackagesItem);
754fdec4227SStephan Aßmus 
755fdec4227SStephan Aßmus 	menu->AddSeparatorItem();
756fdec4227SStephan Aßmus 
757fdec4227SStephan Aßmus 	fShowDevelopPackagesItem = new BMenuItem(
7584fade61fSStephan Aßmus 		B_TRANSLATE("Develop packages"),
759fdec4227SStephan Aßmus 		new BMessage(MSG_SHOW_DEVELOP_PACKAGES));
760fdec4227SStephan Aßmus 	menu->AddItem(fShowDevelopPackagesItem);
761fdec4227SStephan Aßmus 
762fdec4227SStephan Aßmus 	fShowSourcePackagesItem = new BMenuItem(
7634fade61fSStephan Aßmus 		B_TRANSLATE("Source packages"),
764fdec4227SStephan Aßmus 		new BMessage(MSG_SHOW_SOURCE_PACKAGES));
765fdec4227SStephan Aßmus 	menu->AddItem(fShowSourcePackagesItem);
766fdec4227SStephan Aßmus 
767fdec4227SStephan Aßmus 	menuBar->AddItem(menu);
76804c9d578SStephan Aßmus }
76904c9d578SStephan Aßmus 
77004c9d578SStephan Aßmus 
77104c9d578SStephan Aßmus void
772e0a26dceSStephan Aßmus MainWindow::_BuildUserMenu(BMenuBar* menuBar)
773e0a26dceSStephan Aßmus {
774e0a26dceSStephan Aßmus 	fUserMenu = new BMenu(B_TRANSLATE("Not logged in"));
775e0a26dceSStephan Aßmus 
776e0a26dceSStephan Aßmus 	fLogInItem = new BMenuItem(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS),
777e0a26dceSStephan Aßmus 		new BMessage(MSG_LOG_IN));
778e0a26dceSStephan Aßmus 	fUserMenu->AddItem(fLogInItem);
779e0a26dceSStephan Aßmus 
780e0a26dceSStephan Aßmus 	fLogOutItem = new BMenuItem(B_TRANSLATE("Log out"),
781e0a26dceSStephan Aßmus 		new BMessage(MSG_LOG_OUT));
782e0a26dceSStephan Aßmus 	fUserMenu->AddItem(fLogOutItem);
783e0a26dceSStephan Aßmus 
7840c82f64bSAndrew Lindesay 	BMenuItem *latestUserUsageConditionsMenuItem =
7851448ced0SHumdinger 		new BMenuItem(B_TRANSLATE("View latest usage conditions"
78601339a54SAndrew Lindesay 			B_UTF8_ELLIPSIS),
78701339a54SAndrew Lindesay 			new BMessage(MSG_VIEW_LATEST_USER_USAGE_CONDITIONS));
7880c82f64bSAndrew Lindesay 	fUserMenu->AddItem(latestUserUsageConditionsMenuItem);
78901339a54SAndrew Lindesay 
790d2d4866dSAndrew Lindesay 	fUsersUserUsageConditionsMenuItem =
791d2d4866dSAndrew Lindesay 		new BMenuItem(B_TRANSLATE("View agreed usage conditions"
792d2d4866dSAndrew Lindesay 			B_UTF8_ELLIPSIS),
793d2d4866dSAndrew Lindesay 			new BMessage(MSG_VIEW_USERS_USER_USAGE_CONDITIONS));
794d2d4866dSAndrew Lindesay 	fUserMenu->AddItem(fUsersUserUsageConditionsMenuItem);
795d2d4866dSAndrew Lindesay 
796e0a26dceSStephan Aßmus 	menuBar->AddItem(fUserMenu);
797e0a26dceSStephan Aßmus }
798e0a26dceSStephan Aßmus 
799e0a26dceSStephan Aßmus 
800e0a26dceSStephan Aßmus void
801d2d4866dSAndrew Lindesay MainWindow::_RestoreNickname(const BMessage& settings)
802f7c2983eSAxel Dörfler {
803d2d4866dSAndrew Lindesay 	BString nickname;
804d2d4866dSAndrew Lindesay 	if (settings.FindString("username", &nickname) == B_OK
805d2d4866dSAndrew Lindesay 		&& nickname.Length() > 0) {
806d2d4866dSAndrew Lindesay 		fModel.SetNickname(nickname);
807f7c2983eSAxel Dörfler 	}
808f7c2983eSAxel Dörfler }
809f7c2983eSAxel Dörfler 
810f7c2983eSAxel Dörfler 
811f7c2983eSAxel Dörfler const char*
812f7c2983eSAxel Dörfler MainWindow::_WindowFrameName() const
813f7c2983eSAxel Dörfler {
814f7c2983eSAxel Dörfler 	if (fSinglePackageMode)
815f7c2983eSAxel Dörfler 		return "small window frame";
816f7c2983eSAxel Dörfler 
817f7c2983eSAxel Dörfler 	return "window frame";
818f7c2983eSAxel Dörfler }
819f7c2983eSAxel Dörfler 
820f7c2983eSAxel Dörfler 
821f7c2983eSAxel Dörfler void
822f7c2983eSAxel Dörfler MainWindow::_RestoreWindowFrame(const BMessage& settings)
823f7c2983eSAxel Dörfler {
824f7c2983eSAxel Dörfler 	BRect frame = Frame();
825f7c2983eSAxel Dörfler 
826f7c2983eSAxel Dörfler 	BRect windowFrame;
827f7c2983eSAxel Dörfler 	bool fromSettings = false;
828f7c2983eSAxel Dörfler 	if (settings.FindRect(_WindowFrameName(), &windowFrame) == B_OK) {
829f7c2983eSAxel Dörfler 		frame = windowFrame;
830f7c2983eSAxel Dörfler 		fromSettings = true;
831f7c2983eSAxel Dörfler 	} else if (!fSinglePackageMode) {
832f7c2983eSAxel Dörfler 		// Resize to occupy a certain screen size
833f7c2983eSAxel Dörfler 		BRect screenFrame = BScreen(this).Frame();
834f7c2983eSAxel Dörfler 		float width = frame.Width();
835f7c2983eSAxel Dörfler 		float height = frame.Height();
836f7c2983eSAxel Dörfler 		if (width < screenFrame.Width() * .666f
837f7c2983eSAxel Dörfler 			&& height < screenFrame.Height() * .666f) {
838f7c2983eSAxel Dörfler 			frame.bottom = frame.top + screenFrame.Height() * .666f;
839f7c2983eSAxel Dörfler 			frame.right = frame.left
840f7c2983eSAxel Dörfler 				+ std::min(screenFrame.Width() * .666f, height * 7 / 5);
841f7c2983eSAxel Dörfler 		}
842f7c2983eSAxel Dörfler 	}
843f7c2983eSAxel Dörfler 
844f7c2983eSAxel Dörfler 	MoveTo(frame.LeftTop());
845f7c2983eSAxel Dörfler 	ResizeTo(frame.Width(), frame.Height());
846f7c2983eSAxel Dörfler 
847f7c2983eSAxel Dörfler 	if (fromSettings)
8488e96ec34SAxel Dörfler 		MoveOnScreen();
849f7c2983eSAxel Dörfler 	else
850f7c2983eSAxel Dörfler 		CenterOnScreen();
851f7c2983eSAxel Dörfler }
852f7c2983eSAxel Dörfler 
853f7c2983eSAxel Dörfler 
854f7c2983eSAxel Dörfler void
855ccf707d0SAndrew Lindesay MainWindow::_RestoreModelSettings(const BMessage& settings)
856ccf707d0SAndrew Lindesay {
857ccf707d0SAndrew Lindesay 	BString packageListViewMode;
858133ebab6SAndrew Lindesay 	if (settings.FindString(SETTING_PACKAGE_LIST_VIEW_MODE,
859ccf707d0SAndrew Lindesay 			&packageListViewMode) == B_OK) {
860ccf707d0SAndrew Lindesay 		fModel.SetPackageListViewMode(
861ccf707d0SAndrew Lindesay 			main_window_str_to_package_list_view_mode(packageListViewMode));
862ccf707d0SAndrew Lindesay 	}
863ccf707d0SAndrew Lindesay 
864ccf707d0SAndrew Lindesay 	bool showOption;
865133ebab6SAndrew Lindesay 	if (settings.FindBool(SETTING_SHOW_AVAILABLE_PACKAGES, &showOption) == B_OK)
866ccf707d0SAndrew Lindesay 		fModel.SetShowAvailablePackages(showOption);
867133ebab6SAndrew Lindesay 	if (settings.FindBool(SETTING_SHOW_INSTALLED_PACKAGES, &showOption) == B_OK)
868ccf707d0SAndrew Lindesay 		fModel.SetShowInstalledPackages(showOption);
869133ebab6SAndrew Lindesay 	if (settings.FindBool(SETTING_SHOW_DEVELOP_PACKAGES, &showOption) == B_OK)
870ccf707d0SAndrew Lindesay 		fModel.SetShowDevelopPackages(showOption);
871133ebab6SAndrew Lindesay 	if (settings.FindBool(SETTING_SHOW_SOURCE_PACKAGES, &showOption) == B_OK)
872ccf707d0SAndrew Lindesay 		fModel.SetShowSourcePackages(showOption);
873133ebab6SAndrew Lindesay 	if (settings.FindBool(SETTING_CAN_SHARE_ANONYMOUS_USER_DATA,
874133ebab6SAndrew Lindesay 			&showOption) == B_OK) {
875133ebab6SAndrew Lindesay 		fModel.SetCanShareAnonymousUsageData(showOption);
876133ebab6SAndrew Lindesay 	}
877133ebab6SAndrew Lindesay }
878133ebab6SAndrew Lindesay 
879133ebab6SAndrew Lindesay 
880133ebab6SAndrew Lindesay void
881133ebab6SAndrew Lindesay MainWindow::_MaybePromptCanShareAnonymousUserData(const BMessage& settings)
882133ebab6SAndrew Lindesay {
883133ebab6SAndrew Lindesay 	bool showOption;
884133ebab6SAndrew Lindesay 	if (settings.FindBool(SETTING_CAN_SHARE_ANONYMOUS_USER_DATA,
885133ebab6SAndrew Lindesay 			&showOption) == B_NAME_NOT_FOUND) {
886133ebab6SAndrew Lindesay 		_PromptCanShareAnonymousUserData();
887133ebab6SAndrew Lindesay 	}
888133ebab6SAndrew Lindesay }
889133ebab6SAndrew Lindesay 
890133ebab6SAndrew Lindesay 
891133ebab6SAndrew Lindesay void
892133ebab6SAndrew Lindesay MainWindow::_PromptCanShareAnonymousUserData()
893133ebab6SAndrew Lindesay {
894133ebab6SAndrew Lindesay 	BAlert* alert = new(std::nothrow) BAlert(
895133ebab6SAndrew Lindesay 		B_TRANSLATE("Sending anonymous usage data"),
896133ebab6SAndrew Lindesay 		B_TRANSLATE("Would it be acceptable to send anonymous usage data to the"
897133ebab6SAndrew Lindesay 			" HaikuDepotServer system from this computer? You can change your"
898133ebab6SAndrew Lindesay 			" preference in the \"Settings\" window later."),
899133ebab6SAndrew Lindesay 		B_TRANSLATE("No"),
900133ebab6SAndrew Lindesay 		B_TRANSLATE("Yes"));
901133ebab6SAndrew Lindesay 
902133ebab6SAndrew Lindesay 	int32 result = alert->Go();
903133ebab6SAndrew Lindesay 	fModel.SetCanShareAnonymousUsageData(1 == result);
904ccf707d0SAndrew Lindesay }
905ccf707d0SAndrew Lindesay 
906ccf707d0SAndrew Lindesay 
907ccf707d0SAndrew Lindesay void
90863975654SStephan Aßmus MainWindow::_InitWorkerThreads()
90963975654SStephan Aßmus {
91063975654SStephan Aßmus 	fPackageToPopulateSem = create_sem(0, "PopulatePackage");
91163975654SStephan Aßmus 	if (fPackageToPopulateSem >= 0) {
91263975654SStephan Aßmus 		fPopulatePackageWorker = spawn_thread(&_PopulatePackageWorker,
91363975654SStephan Aßmus 			"Package Populator", B_NORMAL_PRIORITY, this);
91463975654SStephan Aßmus 		if (fPopulatePackageWorker >= 0)
91563975654SStephan Aßmus 			resume_thread(fPopulatePackageWorker);
91609f82905SStephan Aßmus 	} else
91709f82905SStephan Aßmus 		fPopulatePackageWorker = -1;
91863975654SStephan Aßmus }
91963975654SStephan Aßmus 
92063975654SStephan Aßmus 
92163975654SStephan Aßmus void
922c4199192SAndrew Lindesay MainWindow::_AdoptModelControls()
92304c9d578SStephan Aßmus {
9249883929bSAndrew Lindesay 	if (fSinglePackageMode)
9259883929bSAndrew Lindesay 		return;
9269883929bSAndrew Lindesay 
92704c9d578SStephan Aßmus 	BAutolock locker(fModel.Lock());
928fdec4227SStephan Aßmus 	fShowAvailablePackagesItem->SetMarked(fModel.ShowAvailablePackages());
929fdec4227SStephan Aßmus 	fShowInstalledPackagesItem->SetMarked(fModel.ShowInstalledPackages());
930fdec4227SStephan Aßmus 	fShowSourcePackagesItem->SetMarked(fModel.ShowSourcePackages());
931fdec4227SStephan Aßmus 	fShowDevelopPackagesItem->SetMarked(fModel.ShowDevelopPackages());
932da651104SStephan Aßmus 
933ccf707d0SAndrew Lindesay 	if (fModel.PackageListViewMode() == PROMINENT)
934ccf707d0SAndrew Lindesay 		fListTabs->Select(TAB_PROMINENT_PACKAGES);
9354fade61fSStephan Aßmus 	else
936ccf707d0SAndrew Lindesay 		fListTabs->Select(TAB_ALL_PACKAGES);
937b965ce70SHumdinger 
938b965ce70SHumdinger 	fFilterView->AdoptModel(fModel);
93904c9d578SStephan Aßmus }
94004c9d578SStephan Aßmus 
94104c9d578SStephan Aßmus 
94204c9d578SStephan Aßmus void
943c4199192SAndrew Lindesay MainWindow::_AdoptModel()
944c4199192SAndrew Lindesay {
945fa5c8097SAndrew Lindesay 	HDTRACE("adopting model to main window ui");
946c4199192SAndrew Lindesay 
947c4199192SAndrew Lindesay 	if (fSinglePackageMode)
948c4199192SAndrew Lindesay 		return;
949c4199192SAndrew Lindesay 
95005880d13SAndrew Lindesay 	std::vector<DepotInfoRef> depots = _CreateSnapshotOfDepots();
95105880d13SAndrew Lindesay 	std::vector<DepotInfoRef>::iterator it;
9520b69420bSAndrew Lindesay 
9530b69420bSAndrew Lindesay 	fFeaturedPackagesView->BeginAddRemove();
9540b69420bSAndrew Lindesay 
95505880d13SAndrew Lindesay 	for (it = depots.begin(); it != depots.end(); it++) {
95605880d13SAndrew Lindesay 		DepotInfoRef depotInfoRef = *it;
957d75b4d61SAndrew Lindesay 		for (int i = 0; i < depotInfoRef->CountPackages(); i++) {
958d75b4d61SAndrew Lindesay 			PackageInfoRef package = depotInfoRef->PackageAtIndex(i);
959d75b4d61SAndrew Lindesay 			_AddRemovePackageFromLists(package);
960d75b4d61SAndrew Lindesay 		}
961c4199192SAndrew Lindesay 	}
962c4199192SAndrew Lindesay 
9630b69420bSAndrew Lindesay 	fFeaturedPackagesView->EndAddRemove();
9640b69420bSAndrew Lindesay 
965c4199192SAndrew Lindesay 	_AdoptModelControls();
966c4199192SAndrew Lindesay }
967c4199192SAndrew Lindesay 
968c4199192SAndrew Lindesay 
969c4199192SAndrew Lindesay void
970c4199192SAndrew Lindesay MainWindow::_AddRemovePackageFromLists(const PackageInfoRef& package)
971c4199192SAndrew Lindesay {
972c4199192SAndrew Lindesay 	bool matches;
973c4199192SAndrew Lindesay 
974c4199192SAndrew Lindesay 	{
975c4199192SAndrew Lindesay 		AutoLocker<BLocker> modelLocker(fModel.Lock());
976c4199192SAndrew Lindesay 		matches = fModel.MatchesFilter(package);
977c4199192SAndrew Lindesay 	}
978c4199192SAndrew Lindesay 
979c4199192SAndrew Lindesay 	if (matches) {
980c4199192SAndrew Lindesay 		if (package->IsProminent())
981c4199192SAndrew Lindesay 			fFeaturedPackagesView->AddPackage(package);
982c4199192SAndrew Lindesay 		fPackageListView->AddPackage(package);
983c4199192SAndrew Lindesay 	} else {
984c4199192SAndrew Lindesay 		fFeaturedPackagesView->RemovePackage(package);
985c4199192SAndrew Lindesay 		fPackageListView->RemovePackage(package);
986c4199192SAndrew Lindesay 	}
987c4199192SAndrew Lindesay }
988c4199192SAndrew Lindesay 
989c4199192SAndrew Lindesay 
990c4199192SAndrew Lindesay void
99184674570SAndrew Lindesay MainWindow::_SetupDelayedIncrementViewCounter(const PackageInfoRef package) {
99284674570SAndrew Lindesay 	if (fIncrementViewCounterDelayedRunner != NULL) {
99384674570SAndrew Lindesay 		fIncrementViewCounterDelayedRunner->SetCount(0);
99484674570SAndrew Lindesay 		delete fIncrementViewCounterDelayedRunner;
99584674570SAndrew Lindesay 	}
99684674570SAndrew Lindesay 	BMessage message(MSG_INCREMENT_VIEW_COUNTER);
99784674570SAndrew Lindesay 	message.SetString("name", package->Name());
99884674570SAndrew Lindesay 	fIncrementViewCounterDelayedRunner =
99984674570SAndrew Lindesay 		new BMessageRunner(BMessenger(this), &message,
100084674570SAndrew Lindesay 			kIncrementViewCounterDelayMicros, 1);
100184674570SAndrew Lindesay 	if (fIncrementViewCounterDelayedRunner->InitCheck()
100284674570SAndrew Lindesay 			!= B_OK) {
100384674570SAndrew Lindesay 		HDERROR("unable to init the increment view counter");
100484674570SAndrew Lindesay 	}
100584674570SAndrew Lindesay }
100684674570SAndrew Lindesay 
100784674570SAndrew Lindesay 
100884674570SAndrew Lindesay void
100984674570SAndrew Lindesay MainWindow::_HandleIncrementViewCounter(const BMessage* message)
101084674570SAndrew Lindesay {
101184674570SAndrew Lindesay 	BString name;
101284674570SAndrew Lindesay 	if (message->FindString("name", &name) == B_OK) {
101384674570SAndrew Lindesay 		const PackageInfoRef& viewedPackage =
101484674570SAndrew Lindesay 			fPackageInfoView->Package();
101584674570SAndrew Lindesay 		if (viewedPackage.IsSet()) {
101684674570SAndrew Lindesay 			if (viewedPackage->Name() == name)
101784674570SAndrew Lindesay 				_IncrementViewCounter(viewedPackage);
101884674570SAndrew Lindesay 			else
101984674570SAndrew Lindesay 				HDINFO("incr. view counter; name mismatch");
102084674570SAndrew Lindesay 		} else
102184674570SAndrew Lindesay 			HDINFO("incr. view counter; no viewed pkg");
102284674570SAndrew Lindesay 	} else
102384674570SAndrew Lindesay 		HDERROR("incr. view counter; no name");
102484674570SAndrew Lindesay 	fIncrementViewCounterDelayedRunner->SetCount(0);
102584674570SAndrew Lindesay 	delete fIncrementViewCounterDelayedRunner;
102684674570SAndrew Lindesay 	fIncrementViewCounterDelayedRunner = NULL;
102784674570SAndrew Lindesay }
102884674570SAndrew Lindesay 
102984674570SAndrew Lindesay 
103084674570SAndrew Lindesay void
1031409af934SAndrew Lindesay MainWindow::_IncrementViewCounter(const PackageInfoRef package)
1032133ebab6SAndrew Lindesay {
1033133ebab6SAndrew Lindesay 	bool shouldIncrementViewCounter = false;
1034133ebab6SAndrew Lindesay 
1035133ebab6SAndrew Lindesay 	{
1036133ebab6SAndrew Lindesay 		AutoLocker<BLocker> modelLocker(fModel.Lock());
1037133ebab6SAndrew Lindesay 		bool canShareAnonymousUsageData = fModel.CanShareAnonymousUsageData();
1038133ebab6SAndrew Lindesay 		if (canShareAnonymousUsageData && !package->Viewed()) {
1039133ebab6SAndrew Lindesay 			package->SetViewed();
1040133ebab6SAndrew Lindesay 			shouldIncrementViewCounter = true;
1041133ebab6SAndrew Lindesay 		}
1042133ebab6SAndrew Lindesay 	}
1043133ebab6SAndrew Lindesay 
1044133ebab6SAndrew Lindesay 	if (shouldIncrementViewCounter) {
1045467ffecdSAugustin Cavalier 		ProcessCoordinator* incrementViewCoordinator =
1046133ebab6SAndrew Lindesay 			ProcessCoordinatorFactory::CreateIncrementViewCounter(
1047133ebab6SAndrew Lindesay 				&fModel, package);
1048467ffecdSAugustin Cavalier 		_AddProcessCoordinator(incrementViewCoordinator);
1049133ebab6SAndrew Lindesay 	}
1050133ebab6SAndrew Lindesay }
1051133ebab6SAndrew Lindesay 
1052133ebab6SAndrew Lindesay 
1053133ebab6SAndrew Lindesay void
105404c9d578SStephan Aßmus MainWindow::_AdoptPackage(const PackageInfoRef& package)
105504c9d578SStephan Aßmus {
105675ba9dbfSStephan Aßmus 	{
105775ba9dbfSStephan Aßmus 		BAutolock locker(fModel.Lock());
105804c9d578SStephan Aßmus 		fPackageInfoView->SetPackage(package);
10591986ab9fSStephan Aßmus 
1060664372abSStephan Aßmus 		if (fFeaturedPackagesView != NULL)
1061664372abSStephan Aßmus 			fFeaturedPackagesView->SelectPackage(package);
10621986ab9fSStephan Aßmus 		if (fPackageListView != NULL)
10631986ab9fSStephan Aßmus 			fPackageListView->SelectPackage(package);
106475ba9dbfSStephan Aßmus 	}
106504c9d578SStephan Aßmus 
1066a9edb9bfSAndrew Lindesay 	_PopulatePackageAsync(false);
106704c9d578SStephan Aßmus }
106804c9d578SStephan Aßmus 
106904c9d578SStephan Aßmus 
107004c9d578SStephan Aßmus void
107104c9d578SStephan Aßmus MainWindow::_ClearPackage()
107204c9d578SStephan Aßmus {
107304c9d578SStephan Aßmus 	fPackageInfoView->Clear();
107404c9d578SStephan Aßmus }
107504c9d578SStephan Aßmus 
107604c9d578SStephan Aßmus 
107704c9d578SStephan Aßmus void
10783369e03dSAndrew Lindesay MainWindow::_StartBulkLoad(bool force)
107904c9d578SStephan Aßmus {
1080c4199192SAndrew Lindesay 	if (fFeaturedPackagesView != NULL)
1081c4199192SAndrew Lindesay 		fFeaturedPackagesView->Clear();
1082c4199192SAndrew Lindesay 	if (fPackageListView != NULL)
1083c4199192SAndrew Lindesay 		fPackageListView->Clear();
1084c4199192SAndrew Lindesay 	fPackageInfoView->Clear();
1085c4199192SAndrew Lindesay 
108610cd325cSAndrew Lindesay 	fRefreshRepositoriesItem->SetEnabled(false);
108710cd325cSAndrew Lindesay 	ProcessCoordinator* bulkLoadCoordinator =
108810cd325cSAndrew Lindesay 		ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
1089409af934SAndrew Lindesay 			fPackageInfoListener, &fModel, force);
109010cd325cSAndrew Lindesay 	_AddProcessCoordinator(bulkLoadCoordinator);
109104c9d578SStephan Aßmus }
109204c9d578SStephan Aßmus 
109304c9d578SStephan Aßmus 
109404c9d578SStephan Aßmus void
109510cd325cSAndrew Lindesay MainWindow::_BulkLoadCompleteReceived(status_t errorStatus)
109604c9d578SStephan Aßmus {
109710cd325cSAndrew Lindesay 	if (errorStatus != B_OK) {
10983369e03dSAndrew Lindesay 		AppUtils::NotifySimpleError(
10991448ced0SHumdinger 			B_TRANSLATE("Package update error"),
11003369e03dSAndrew Lindesay 			B_TRANSLATE("While updating package data, a problem has arisen "
11013369e03dSAndrew Lindesay 				"that may cause data to be outdated or missing from the "
11023369e03dSAndrew Lindesay 				"application's display. Additional details regarding this "
11033369e03dSAndrew Lindesay 				"problem may be able to be obtained from the application "
1104b21c9447SAndrew Lindesay 				"logs."
1105b21c9447SAndrew Lindesay 				ALERT_MSG_LOGS_USER_GUIDE));
110604c9d578SStephan Aßmus 	}
110710cd325cSAndrew Lindesay 
11083369e03dSAndrew Lindesay 	fRefreshRepositoriesItem->SetEnabled(true);
110910cd325cSAndrew Lindesay 	_AdoptModel();
111010cd325cSAndrew Lindesay 	_UpdateAvailableRepositories();
1111ccf707d0SAndrew Lindesay 
1112ccf707d0SAndrew Lindesay 	// if after loading everything in, it transpires that there are no
1113ccf707d0SAndrew Lindesay 	// featured packages then the featured packages should be disabled
1114ccf707d0SAndrew Lindesay 	// and the user should be switched to the "all packages" view so
1115ccf707d0SAndrew Lindesay 	// that they are not presented with a blank window!
1116ccf707d0SAndrew Lindesay 
1117ccf707d0SAndrew Lindesay 	bool hasProminentPackages = fModel.HasAnyProminentPackages();
1118ccf707d0SAndrew Lindesay 	fListTabs->TabAt(TAB_PROMINENT_PACKAGES)->SetEnabled(hasProminentPackages);
1119ccf707d0SAndrew Lindesay 	if (!hasProminentPackages
1120ccf707d0SAndrew Lindesay 			&& fListTabs->Selection() == TAB_PROMINENT_PACKAGES) {
1121ccf707d0SAndrew Lindesay 		fModel.SetPackageListViewMode(ALL);
1122ccf707d0SAndrew Lindesay 		fListTabs->Select(TAB_ALL_PACKAGES);
1123ccf707d0SAndrew Lindesay 	}
112404c9d578SStephan Aßmus }
112504c9d578SStephan Aßmus 
112604c9d578SStephan Aßmus 
11273369e03dSAndrew Lindesay void
112810cd325cSAndrew Lindesay MainWindow::_NotifyWorkStatusClear()
112904c9d578SStephan Aßmus {
113010cd325cSAndrew Lindesay 	BMessage message(MSG_WORK_STATUS_CLEAR);
113110cd325cSAndrew Lindesay 	this->PostMessage(&message, this);
113210cd325cSAndrew Lindesay }
113310cd325cSAndrew Lindesay 
113410cd325cSAndrew Lindesay 
113510cd325cSAndrew Lindesay void
113610cd325cSAndrew Lindesay MainWindow::_HandleWorkStatusClear()
113710cd325cSAndrew Lindesay {
113810cd325cSAndrew Lindesay 	fWorkStatusView->SetText("");
11393369e03dSAndrew Lindesay 	fWorkStatusView->SetIdle();
11403369e03dSAndrew Lindesay }
114104c9d578SStephan Aßmus 
114204c9d578SStephan Aßmus 
11433369e03dSAndrew Lindesay /*! Sends off a message to the Window so that it can change the status view
11443369e03dSAndrew Lindesay     on the front-end in the UI thread.
11453369e03dSAndrew Lindesay */
114604c9d578SStephan Aßmus 
11473369e03dSAndrew Lindesay void
11483369e03dSAndrew Lindesay MainWindow::_NotifyWorkStatusChange(const BString& text, float progress)
11493369e03dSAndrew Lindesay {
11503369e03dSAndrew Lindesay 	BMessage message(MSG_WORK_STATUS_CHANGE);
115104c9d578SStephan Aßmus 
11523369e03dSAndrew Lindesay 	if (!text.IsEmpty())
11533369e03dSAndrew Lindesay 		message.AddString(KEY_WORK_STATUS_TEXT, text);
11543369e03dSAndrew Lindesay 	message.AddFloat(KEY_WORK_STATUS_PROGRESS, progress);
115504c9d578SStephan Aßmus 
11563369e03dSAndrew Lindesay 	this->PostMessage(&message, this);
11573369e03dSAndrew Lindesay }
115804c9d578SStephan Aßmus 
11593369e03dSAndrew Lindesay 
1160f32d5c5cSAndrew Lindesay void
1161f32d5c5cSAndrew Lindesay MainWindow::_HandleExternalPackageUpdateMessageReceived(const BMessage* message)
1162f32d5c5cSAndrew Lindesay {
1163f32d5c5cSAndrew Lindesay 	BStringList addedPackageNames;
1164f32d5c5cSAndrew Lindesay 	BStringList removedPackageNames;
1165f32d5c5cSAndrew Lindesay 
1166f32d5c5cSAndrew Lindesay 	if (message->FindStrings("added package names",
1167f32d5c5cSAndrew Lindesay 			&addedPackageNames) == B_OK) {
1168f32d5c5cSAndrew Lindesay 		addedPackageNames.Sort();
11690ebb9177SAndrew Lindesay 		AutoLocker<BLocker> locker(fModel.Lock());
11700ebb9177SAndrew Lindesay 		fModel.SetStateForPackagesByName(addedPackageNames, ACTIVATED);
1171f32d5c5cSAndrew Lindesay 	}
1172f32d5c5cSAndrew Lindesay 	else
1173f32d5c5cSAndrew Lindesay 		HDINFO("no [added package names] key in inbound message");
1174f32d5c5cSAndrew Lindesay 
1175f32d5c5cSAndrew Lindesay 	if (message->FindStrings("removed package names",
1176f32d5c5cSAndrew Lindesay 			&removedPackageNames) == B_OK) {
1177f32d5c5cSAndrew Lindesay 		removedPackageNames.Sort();
11780ebb9177SAndrew Lindesay 		AutoLocker<BLocker> locker(fModel.Lock());
11790ebb9177SAndrew Lindesay 		fModel.SetStateForPackagesByName(addedPackageNames, UNINSTALLED);
1180f32d5c5cSAndrew Lindesay 	} else
1181f32d5c5cSAndrew Lindesay 		HDINFO("no [removed package names] key in inbound message");
1182f32d5c5cSAndrew Lindesay }
1183f32d5c5cSAndrew Lindesay 
1184f32d5c5cSAndrew Lindesay 
11853369e03dSAndrew Lindesay void
11863369e03dSAndrew Lindesay MainWindow::_HandleWorkStatusChangeMessageReceived(const BMessage* message)
11873369e03dSAndrew Lindesay {
11889883929bSAndrew Lindesay 	if (fWorkStatusView == NULL)
11899883929bSAndrew Lindesay 		return;
11909883929bSAndrew Lindesay 
11913369e03dSAndrew Lindesay 	BString text;
11923369e03dSAndrew Lindesay 	float progress;
11933369e03dSAndrew Lindesay 
11943369e03dSAndrew Lindesay 	if (message->FindString(KEY_WORK_STATUS_TEXT, &text) == B_OK)
11953369e03dSAndrew Lindesay 		fWorkStatusView->SetText(text);
11963369e03dSAndrew Lindesay 
1197a18f873fSAndrew Lindesay 	if (message->FindFloat(KEY_WORK_STATUS_PROGRESS, &progress) == B_OK) {
1198a18f873fSAndrew Lindesay 		if (progress < 0.0f)
1199a18f873fSAndrew Lindesay 			fWorkStatusView->SetBusy();
1200a18f873fSAndrew Lindesay 		else
12013369e03dSAndrew Lindesay 			fWorkStatusView->SetProgress(progress);
1202a18f873fSAndrew Lindesay 	} else {
1203a18f873fSAndrew Lindesay 		HDERROR("work status change missing progress on update message");
1204a18f873fSAndrew Lindesay 		fWorkStatusView->SetProgress(0.0f);
120504c9d578SStephan Aßmus 	}
120604c9d578SStephan Aßmus }
120704c9d578SStephan Aßmus 
120804c9d578SStephan Aßmus 
1209a9edb9bfSAndrew Lindesay /*! This method will cause the package to have its data refreshed from
1210a9edb9bfSAndrew Lindesay     the server application.  The refresh happens in the background; this method
1211a9edb9bfSAndrew Lindesay     is asynchronous.
1212a9edb9bfSAndrew Lindesay */
1213a9edb9bfSAndrew Lindesay 
1214a9edb9bfSAndrew Lindesay void
1215a9edb9bfSAndrew Lindesay MainWindow::_PopulatePackageAsync(bool forcePopulate)
1216a9edb9bfSAndrew Lindesay {
1217a9edb9bfSAndrew Lindesay 		// Trigger asynchronous package population from the web-app
1218a9edb9bfSAndrew Lindesay 	{
1219a9edb9bfSAndrew Lindesay 		AutoLocker<BLocker> lock(&fPackageToPopulateLock);
1220a9edb9bfSAndrew Lindesay 		fPackageToPopulate = fPackageInfoView->Package();
1221a9edb9bfSAndrew Lindesay 		fForcePopulatePackage = forcePopulate;
1222a9edb9bfSAndrew Lindesay 	}
1223a9edb9bfSAndrew Lindesay 	release_sem_etc(fPackageToPopulateSem, 1, 0);
1224a9edb9bfSAndrew Lindesay 
1225f96d1f4dSAndrew Lindesay 	HDDEBUG("pkg [%s] will be updated from the server.",
1226fa5c8097SAndrew Lindesay 		fPackageToPopulate->Name().String());
1227a9edb9bfSAndrew Lindesay }
1228a9edb9bfSAndrew Lindesay 
1229a9edb9bfSAndrew Lindesay 
1230a9edb9bfSAndrew Lindesay /*! This method will run in the background.  The thread will block until there
1231a9edb9bfSAndrew Lindesay     is a package to be updated.  When the thread unblocks, it will update the
1232a9edb9bfSAndrew Lindesay     package with information from the server.
1233a9edb9bfSAndrew Lindesay */
1234a9edb9bfSAndrew Lindesay 
123504c9d578SStephan Aßmus status_t
123604c9d578SStephan Aßmus MainWindow::_PopulatePackageWorker(void* arg)
123704c9d578SStephan Aßmus {
123804c9d578SStephan Aßmus 	MainWindow* window = reinterpret_cast<MainWindow*>(arg);
123904c9d578SStephan Aßmus 
124004c9d578SStephan Aßmus 	while (acquire_sem(window->fPackageToPopulateSem) == B_OK) {
124104c9d578SStephan Aßmus 		PackageInfoRef package;
1242a9edb9bfSAndrew Lindesay 		bool force;
124304c9d578SStephan Aßmus 		{
124404c9d578SStephan Aßmus 			AutoLocker<BLocker> lock(&window->fPackageToPopulateLock);
124504c9d578SStephan Aßmus 			package = window->fPackageToPopulate;
1246a9edb9bfSAndrew Lindesay 			force = window->fForcePopulatePackage;
124704c9d578SStephan Aßmus 		}
124804c9d578SStephan Aßmus 
1249779ab335SX512 		if (package.IsSet()) {
1250a9edb9bfSAndrew Lindesay 			uint32 populateFlags = Model::POPULATE_USER_RATINGS
1251a9edb9bfSAndrew Lindesay 				| Model::POPULATE_CHANGELOG;
1252a9edb9bfSAndrew Lindesay 
1253a9edb9bfSAndrew Lindesay 			if (force)
1254a9edb9bfSAndrew Lindesay 				populateFlags |= Model::POPULATE_FORCE;
1255a9edb9bfSAndrew Lindesay 
1256a9edb9bfSAndrew Lindesay 			window->fModel.PopulatePackage(package, populateFlags);
1257a9edb9bfSAndrew Lindesay 
1258fa5c8097SAndrew Lindesay 			HDDEBUG("populating package [%s]", package->Name().String());
125904c9d578SStephan Aßmus 		}
126004c9d578SStephan Aßmus 	}
126104c9d578SStephan Aßmus 
126204c9d578SStephan Aßmus 	return 0;
126304c9d578SStephan Aßmus }
126404c9d578SStephan Aßmus 
126504c9d578SStephan Aßmus 
126604c9d578SStephan Aßmus void
1267133ebab6SAndrew Lindesay MainWindow::_OpenSettingsWindow()
1268133ebab6SAndrew Lindesay {
1269133ebab6SAndrew Lindesay 	SettingsWindow* window = new SettingsWindow(this, &fModel);
1270133ebab6SAndrew Lindesay 	window->Show();
1271133ebab6SAndrew Lindesay }
1272133ebab6SAndrew Lindesay 
1273133ebab6SAndrew Lindesay 
1274133ebab6SAndrew Lindesay void
12751bbda92dSStephan Aßmus MainWindow::_OpenLoginWindow(const BMessage& onSuccessMessage)
127604c9d578SStephan Aßmus {
127704c9d578SStephan Aßmus 	UserLoginWindow* window = new UserLoginWindow(this,
127804c9d578SStephan Aßmus 		BRect(0, 0, 500, 400), fModel);
12791bbda92dSStephan Aßmus 
12801bbda92dSStephan Aßmus 	if (onSuccessMessage.what != 0)
12811bbda92dSStephan Aßmus 		window->SetOnSuccessMessage(BMessenger(this), onSuccessMessage);
12821bbda92dSStephan Aßmus 
128304c9d578SStephan Aßmus 	window->Show();
128404c9d578SStephan Aßmus }
128504c9d578SStephan Aßmus 
12868f03a0f9SStephan Aßmus 
12878f03a0f9SStephan Aßmus void
128810cd325cSAndrew Lindesay MainWindow::_StartUserVerify()
128910cd325cSAndrew Lindesay {
129010cd325cSAndrew Lindesay 	if (!fModel.Nickname().IsEmpty()) {
129110cd325cSAndrew Lindesay 		_AddProcessCoordinator(
129210cd325cSAndrew Lindesay 			ProcessCoordinatorFactory::CreateUserDetailVerifierCoordinator(
129310cd325cSAndrew Lindesay 				this,
129410cd325cSAndrew Lindesay 					// UserDetailVerifierListener
129510cd325cSAndrew Lindesay 				&fModel) );
129610cd325cSAndrew Lindesay 	}
129710cd325cSAndrew Lindesay }
129810cd325cSAndrew Lindesay 
129910cd325cSAndrew Lindesay 
130010cd325cSAndrew Lindesay void
13018f03a0f9SStephan Aßmus MainWindow::_UpdateAuthorization()
13028f03a0f9SStephan Aßmus {
1303d2d4866dSAndrew Lindesay 	BString nickname(fModel.Nickname());
1304d2d4866dSAndrew Lindesay 	bool hasUser = !nickname.IsEmpty();
1305e0a26dceSStephan Aßmus 
13066d519fd1SStephan Aßmus 	if (fLogOutItem != NULL)
1307e0a26dceSStephan Aßmus 		fLogOutItem->SetEnabled(hasUser);
1308d2d4866dSAndrew Lindesay 	if (fUsersUserUsageConditionsMenuItem != NULL)
1309d2d4866dSAndrew Lindesay 		fUsersUserUsageConditionsMenuItem->SetEnabled(hasUser);
1310e0a26dceSStephan Aßmus 	if (fLogInItem != NULL) {
1311e0a26dceSStephan Aßmus 		if (hasUser)
1312e0a26dceSStephan Aßmus 			fLogInItem->SetLabel(B_TRANSLATE("Switch account" B_UTF8_ELLIPSIS));
1313e0a26dceSStephan Aßmus 		else
1314e0a26dceSStephan Aßmus 			fLogInItem->SetLabel(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS));
1315e0a26dceSStephan Aßmus 	}
1316e0a26dceSStephan Aßmus 
1317e0a26dceSStephan Aßmus 	if (fUserMenu != NULL) {
1318e0a26dceSStephan Aßmus 		BString label;
1319d2d4866dSAndrew Lindesay 		if (hasUser) {
1320e0a26dceSStephan Aßmus 			label = B_TRANSLATE("Logged in as %User%");
1321d2d4866dSAndrew Lindesay 			label.ReplaceAll("%User%", nickname);
1322d2d4866dSAndrew Lindesay 		} else {
1323d2d4866dSAndrew Lindesay 			label = B_TRANSLATE("Not logged in");
1324e0a26dceSStephan Aßmus 		}
1325e0a26dceSStephan Aßmus 		fUserMenu->Superitem()->SetLabel(label);
1326e0a26dceSStephan Aßmus 	}
13278f03a0f9SStephan Aßmus }
13281bbda92dSStephan Aßmus 
13291bbda92dSStephan Aßmus 
13301bbda92dSStephan Aßmus void
1331b965ce70SHumdinger MainWindow::_UpdateAvailableRepositories()
1332b965ce70SHumdinger {
1333b965ce70SHumdinger 	fRepositoryMenu->RemoveItems(0, fRepositoryMenu->CountItems(), true);
1334b965ce70SHumdinger 
1335b965ce70SHumdinger 	fRepositoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All repositories"),
1336b965ce70SHumdinger 		new BMessage(MSG_DEPOT_SELECTED)));
1337b965ce70SHumdinger 
1338b965ce70SHumdinger 	fRepositoryMenu->AddItem(new BSeparatorItem());
1339b965ce70SHumdinger 
1340b965ce70SHumdinger 	bool foundSelectedDepot = false;
134105880d13SAndrew Lindesay 	std::vector<DepotInfoRef> depots = _CreateSnapshotOfDepots();
134205880d13SAndrew Lindesay 	std::vector<DepotInfoRef>::iterator it;
1343d13c3d89SAndrew Lindesay 
134405880d13SAndrew Lindesay 	for (it = depots.begin(); it != depots.end(); it++) {
134505880d13SAndrew Lindesay 		DepotInfoRef depot = *it;
134605880d13SAndrew Lindesay 
134705880d13SAndrew Lindesay 		if (depot->Name().Length() != 0) {
1348b965ce70SHumdinger 			BMessage* message = new BMessage(MSG_DEPOT_SELECTED);
134905880d13SAndrew Lindesay 			message->AddString("name", depot->Name());
135005880d13SAndrew Lindesay 			BMenuItem* item = new(std::nothrow) BMenuItem(depot->Name(), message);
135105880d13SAndrew Lindesay 
135205880d13SAndrew Lindesay 			if (item == NULL)
135305880d13SAndrew Lindesay 				HDFATAL("memory exhaustion");
135405880d13SAndrew Lindesay 
1355b965ce70SHumdinger 			fRepositoryMenu->AddItem(item);
1356b965ce70SHumdinger 
135705880d13SAndrew Lindesay 			if (depot->Name() == fModel.Depot()) {
1358b965ce70SHumdinger 				item->SetMarked(true);
1359b965ce70SHumdinger 				foundSelectedDepot = true;
1360b965ce70SHumdinger 			}
1361b965ce70SHumdinger 		}
1362d13c3d89SAndrew Lindesay 	}
1363b965ce70SHumdinger 
1364b965ce70SHumdinger 	if (!foundSelectedDepot)
1365b965ce70SHumdinger 		fRepositoryMenu->ItemAt(0)->SetMarked(true);
1366b965ce70SHumdinger }
1367b965ce70SHumdinger 
1368b965ce70SHumdinger 
1369a9edb9bfSAndrew Lindesay bool
1370a9edb9bfSAndrew Lindesay MainWindow::_SelectedPackageHasWebAppRepositoryCode()
1371a9edb9bfSAndrew Lindesay {
1372a9edb9bfSAndrew Lindesay 	const PackageInfoRef& package = fPackageInfoView->Package();
13736ab878c0SAndrew Lindesay 	const BString depotName = package->DepotName();
1374a9edb9bfSAndrew Lindesay 
13756ab878c0SAndrew Lindesay 	if (depotName.IsEmpty()) {
1376fa5c8097SAndrew Lindesay 		HDDEBUG("the package [%s] has no depot name", package->Name().String());
13776ab878c0SAndrew Lindesay 	} else {
13786ab878c0SAndrew Lindesay 		const DepotInfo* depot = fModel.DepotForName(depotName);
1379a9edb9bfSAndrew Lindesay 
13806ab878c0SAndrew Lindesay 		if (depot == NULL) {
1381f96d1f4dSAndrew Lindesay 			HDINFO("the depot [%s] was not able to be found",
1382fa5c8097SAndrew Lindesay 				depotName.String());
13836ab878c0SAndrew Lindesay 		} else {
13846ab878c0SAndrew Lindesay 			BString repositoryCode = depot->WebAppRepositoryCode();
1385a9edb9bfSAndrew Lindesay 
13866ab878c0SAndrew Lindesay 			if (repositoryCode.IsEmpty()) {
1387f96d1f4dSAndrew Lindesay 				HDINFO("the depot [%s] has no web app repository code",
1388fa5c8097SAndrew Lindesay 					depotName.String());
1389fa5c8097SAndrew Lindesay 			} else
13906ab878c0SAndrew Lindesay 				return true;
13916ab878c0SAndrew Lindesay 		}
13926ab878c0SAndrew Lindesay 	}
13936ab878c0SAndrew Lindesay 
13946ab878c0SAndrew Lindesay 	return false;
1395a9edb9bfSAndrew Lindesay }
1396a9edb9bfSAndrew Lindesay 
1397a9edb9bfSAndrew Lindesay 
1398b965ce70SHumdinger void
13991bbda92dSStephan Aßmus MainWindow::_RatePackage()
14001bbda92dSStephan Aßmus {
1401a9edb9bfSAndrew Lindesay 	if (!_SelectedPackageHasWebAppRepositoryCode()) {
1402a9edb9bfSAndrew Lindesay 		BAlert* alert = new(std::nothrow) BAlert(
1403cbadcae1SHumdinger 			B_TRANSLATE("Rating not possible"),
1404cbadcae1SHumdinger 			B_TRANSLATE("This package doesn't seem to be on the HaikuDepot "
1405cbadcae1SHumdinger 				"Server, so it's not possible to create a new rating "
1406cbadcae1SHumdinger 				"or edit an existing rating."),
1407a9edb9bfSAndrew Lindesay 			B_TRANSLATE("OK"));
1408a9edb9bfSAndrew Lindesay 		alert->Go();
1409a9edb9bfSAndrew Lindesay     	return;
1410a9edb9bfSAndrew Lindesay 	}
1411a9edb9bfSAndrew Lindesay 
1412d2d4866dSAndrew Lindesay 	if (fModel.Nickname().IsEmpty()) {
14131bbda92dSStephan Aßmus 		BAlert* alert = new(std::nothrow) BAlert(
14141bbda92dSStephan Aßmus 			B_TRANSLATE("Not logged in"),
14151bbda92dSStephan Aßmus 			B_TRANSLATE("You need to be logged into an account before you "
14161bbda92dSStephan Aßmus 				"can rate packages."),
14171bbda92dSStephan Aßmus 			B_TRANSLATE("Cancel"),
14181bbda92dSStephan Aßmus 			B_TRANSLATE("Login or Create account"));
14191bbda92dSStephan Aßmus 
14201bbda92dSStephan Aßmus 		if (alert == NULL)
14211bbda92dSStephan Aßmus 			return;
14221bbda92dSStephan Aßmus 
14231bbda92dSStephan Aßmus 		int32 choice = alert->Go();
14241bbda92dSStephan Aßmus 		if (choice == 1)
14251bbda92dSStephan Aßmus 			_OpenLoginWindow(BMessage(MSG_RATE_PACKAGE));
14261bbda92dSStephan Aßmus 		return;
14271bbda92dSStephan Aßmus 	}
14281bbda92dSStephan Aßmus 
14291bbda92dSStephan Aßmus 	// TODO: Allow only one RatePackageWindow
14301bbda92dSStephan Aßmus 	// TODO: Mechanism for remembering the window frame
14311bbda92dSStephan Aßmus 	RatePackageWindow* window = new RatePackageWindow(this,
14321bbda92dSStephan Aßmus 		BRect(0, 0, 500, 400), fModel);
14331bbda92dSStephan Aßmus 	window->SetPackage(fPackageInfoView->Package());
14341bbda92dSStephan Aßmus 	window->Show();
14351bbda92dSStephan Aßmus }
1436d5ef985eSStephan Aßmus 
1437d5ef985eSStephan Aßmus 
1438d5ef985eSStephan Aßmus void
1439d5ef985eSStephan Aßmus MainWindow::_ShowScreenshot()
1440d5ef985eSStephan Aßmus {
1441d5ef985eSStephan Aßmus 	// TODO: Mechanism for remembering the window frame
1442d5ef985eSStephan Aßmus 	if (fScreenshotWindow == NULL)
1443*88af15cfSAndrew Lindesay 		fScreenshotWindow = new ScreenshotWindow(this, BRect(0, 0, 500, 400), &fModel);
1444d5ef985eSStephan Aßmus 
1445d5ef985eSStephan Aßmus 	if (fScreenshotWindow->LockWithTimeout(1000) != B_OK)
1446d5ef985eSStephan Aßmus 		return;
1447d5ef985eSStephan Aßmus 
1448d5ef985eSStephan Aßmus 	fScreenshotWindow->SetPackage(fPackageInfoView->Package());
1449d5ef985eSStephan Aßmus 
1450d5ef985eSStephan Aßmus 	if (fScreenshotWindow->IsHidden())
1451d5ef985eSStephan Aßmus 		fScreenshotWindow->Show();
1452d5ef985eSStephan Aßmus 	else
1453d5ef985eSStephan Aßmus 		fScreenshotWindow->Activate();
1454d5ef985eSStephan Aßmus 
1455d5ef985eSStephan Aßmus 	fScreenshotWindow->Unlock();
1456d5ef985eSStephan Aßmus }
145701339a54SAndrew Lindesay 
145801339a54SAndrew Lindesay 
145901339a54SAndrew Lindesay void
1460d2d4866dSAndrew Lindesay MainWindow::_ViewUserUsageConditions(
1461d2d4866dSAndrew Lindesay 	UserUsageConditionsSelectionMode mode)
146201339a54SAndrew Lindesay {
146301339a54SAndrew Lindesay 	UserUsageConditionsWindow* window = new UserUsageConditionsWindow(
1464d2d4866dSAndrew Lindesay 		fModel, mode);
146501339a54SAndrew Lindesay 	window->Show();
146601339a54SAndrew Lindesay }
146710cd325cSAndrew Lindesay 
146810cd325cSAndrew Lindesay 
146910cd325cSAndrew Lindesay void
147010cd325cSAndrew Lindesay MainWindow::UserCredentialsFailed()
147110cd325cSAndrew Lindesay {
147210cd325cSAndrew Lindesay 	BString message = B_TRANSLATE("The password previously "
147310cd325cSAndrew Lindesay 		"supplied for the user [%Nickname%] is not currently "
147410cd325cSAndrew Lindesay 		"valid. The user will be logged-out of this application "
147510cd325cSAndrew Lindesay 		"and you should login again with your updated password.");
147610cd325cSAndrew Lindesay 	message.ReplaceAll("%Nickname%", fModel.Nickname());
147710cd325cSAndrew Lindesay 
147810cd325cSAndrew Lindesay 	AppUtils::NotifySimpleError(B_TRANSLATE("Login issue"),
147910cd325cSAndrew Lindesay 		message);
148010cd325cSAndrew Lindesay 
148110cd325cSAndrew Lindesay 	{
148210cd325cSAndrew Lindesay 		AutoLocker<BLocker> locker(fModel.Lock());
148310cd325cSAndrew Lindesay 		fModel.SetNickname("");
148410cd325cSAndrew Lindesay 	}
148510cd325cSAndrew Lindesay }
148610cd325cSAndrew Lindesay 
148710cd325cSAndrew Lindesay 
148810cd325cSAndrew Lindesay /*! \brief This method is invoked from the UserDetailVerifierProcess on a
148910cd325cSAndrew Lindesay 		   background thread.  For this reason it lodges a message into itself
149010cd325cSAndrew Lindesay 		   which can then be handled on the main thread.
149110cd325cSAndrew Lindesay */
149210cd325cSAndrew Lindesay 
149310cd325cSAndrew Lindesay void
149410cd325cSAndrew Lindesay MainWindow::UserUsageConditionsNotLatest(const UserDetail& userDetail)
149510cd325cSAndrew Lindesay {
149610cd325cSAndrew Lindesay 	BMessage message(MSG_USER_USAGE_CONDITIONS_NOT_LATEST);
149710cd325cSAndrew Lindesay 	BMessage detailsMessage;
149810cd325cSAndrew Lindesay 	if (userDetail.Archive(&detailsMessage, true) != B_OK
149910cd325cSAndrew Lindesay 			|| message.AddMessage("userDetail", &detailsMessage) != B_OK) {
1500fa5c8097SAndrew Lindesay 		HDERROR("unable to archive the user detail into a message");
150110cd325cSAndrew Lindesay 	}
150210cd325cSAndrew Lindesay 	else
150310cd325cSAndrew Lindesay 		BMessenger(this).SendMessage(&message);
150410cd325cSAndrew Lindesay }
150510cd325cSAndrew Lindesay 
150610cd325cSAndrew Lindesay 
150710cd325cSAndrew Lindesay void
150810cd325cSAndrew Lindesay MainWindow::_HandleUserUsageConditionsNotLatest(
150910cd325cSAndrew Lindesay 	const UserDetail& userDetail)
151010cd325cSAndrew Lindesay {
151110cd325cSAndrew Lindesay 	ToLatestUserUsageConditionsWindow* window =
151210cd325cSAndrew Lindesay 		new ToLatestUserUsageConditionsWindow(this, fModel, userDetail);
151310cd325cSAndrew Lindesay 	window->Show();
151410cd325cSAndrew Lindesay }
151510cd325cSAndrew Lindesay 
151610cd325cSAndrew Lindesay 
151710cd325cSAndrew Lindesay void
151810cd325cSAndrew Lindesay MainWindow::_AddProcessCoordinator(ProcessCoordinator* item)
151910cd325cSAndrew Lindesay {
152010cd325cSAndrew Lindesay 	AutoLocker<BLocker> lock(&fCoordinatorLock);
152110cd325cSAndrew Lindesay 
152295c7b018SAndrew Lindesay 	if (fShouldCloseWhenNoProcessesToCoordinate) {
152395c7b018SAndrew Lindesay 		HDINFO("system shutting down --> new process coordinator [%s] rejected",
152495c7b018SAndrew Lindesay 			item->Name().String());
152595c7b018SAndrew Lindesay 		return;
152695c7b018SAndrew Lindesay 	}
152795c7b018SAndrew Lindesay 
1528a18f873fSAndrew Lindesay 	item->SetListener(this);
1529a18f873fSAndrew Lindesay 
1530409af934SAndrew Lindesay 	if (fCoordinator == NULL) {
153110cd325cSAndrew Lindesay 		if (acquire_sem(fCoordinatorRunningSem) != B_OK)
153210cd325cSAndrew Lindesay 			debugger("unable to acquire the process coordinator sem");
1533f96d1f4dSAndrew Lindesay 		HDINFO("adding and starting a process coordinator [%s]",
1534fa5c8097SAndrew Lindesay 			item->Name().String());
1535409af934SAndrew Lindesay 		delete fCoordinator;
1536409af934SAndrew Lindesay 		fCoordinator = item;
153710cd325cSAndrew Lindesay 		fCoordinator->Start();
15387d7de135SAugustin Cavalier 	} else {
1539f96d1f4dSAndrew Lindesay 		HDINFO("adding process coordinator [%s] to the queue",
154010cd325cSAndrew Lindesay 			item->Name().String());
154110cd325cSAndrew Lindesay 		fCoordinatorQueue.push(item);
154210cd325cSAndrew Lindesay 	}
154310cd325cSAndrew Lindesay }
154410cd325cSAndrew Lindesay 
154510cd325cSAndrew Lindesay 
154610cd325cSAndrew Lindesay void
154710cd325cSAndrew Lindesay MainWindow::_SpinUntilProcessCoordinatorComplete()
154810cd325cSAndrew Lindesay {
154910cd325cSAndrew Lindesay 	while (true) {
155010cd325cSAndrew Lindesay 		if (acquire_sem(fCoordinatorRunningSem) != B_OK)
155110cd325cSAndrew Lindesay 			debugger("unable to acquire the process coordinator sem");
155210cd325cSAndrew Lindesay 		if (release_sem(fCoordinatorRunningSem) != B_OK)
155310cd325cSAndrew Lindesay 			debugger("unable to release the process coordinator sem");
155410cd325cSAndrew Lindesay 		{
155510cd325cSAndrew Lindesay 			AutoLocker<BLocker> lock(&fCoordinatorLock);
1556409af934SAndrew Lindesay 			if (fCoordinator == NULL)
155710cd325cSAndrew Lindesay 				return;
155810cd325cSAndrew Lindesay 		}
155910cd325cSAndrew Lindesay 	}
156010cd325cSAndrew Lindesay }
156110cd325cSAndrew Lindesay 
156210cd325cSAndrew Lindesay 
156310cd325cSAndrew Lindesay void
156410cd325cSAndrew Lindesay MainWindow::_StopProcessCoordinators()
156510cd325cSAndrew Lindesay {
156695c7b018SAndrew Lindesay 	HDINFO("will stop all queued process coordinators");
156710cd325cSAndrew Lindesay 	AutoLocker<BLocker> lock(&fCoordinatorLock);
156810cd325cSAndrew Lindesay 
156910cd325cSAndrew Lindesay 	while (!fCoordinatorQueue.empty()) {
1570409af934SAndrew Lindesay 		ProcessCoordinator* processCoordinator
1571f96d1f4dSAndrew Lindesay 			= fCoordinatorQueue.front();
1572f96d1f4dSAndrew Lindesay 		HDINFO("will drop queued process coordinator [%s]",
1573fa5c8097SAndrew Lindesay 			processCoordinator->Name().String());
157410cd325cSAndrew Lindesay 		fCoordinatorQueue.pop();
1575409af934SAndrew Lindesay 		delete processCoordinator;
157610cd325cSAndrew Lindesay 	}
157710cd325cSAndrew Lindesay 
1578409af934SAndrew Lindesay 	if (fCoordinator != NULL)
157995c7b018SAndrew Lindesay 		fCoordinator->RequestStop();
158010cd325cSAndrew Lindesay }
158110cd325cSAndrew Lindesay 
158210cd325cSAndrew Lindesay 
158310cd325cSAndrew Lindesay /*! This method is called when there is some change in the bulk load process
158410cd325cSAndrew Lindesay 	or other process coordinator.
158510cd325cSAndrew Lindesay 	A change may mean that a new process has started / stopped etc... or it
158610cd325cSAndrew Lindesay 	may mean that the entire coordinator has finished.
158710cd325cSAndrew Lindesay */
158810cd325cSAndrew Lindesay 
158910cd325cSAndrew Lindesay void
159010cd325cSAndrew Lindesay MainWindow::CoordinatorChanged(ProcessCoordinatorState& coordinatorState)
159110cd325cSAndrew Lindesay {
1592409af934SAndrew Lindesay 	BMessage message(MSG_PROCESS_COORDINATOR_CHANGED);
1593409af934SAndrew Lindesay 	if (coordinatorState.Archive(&message, true) != B_OK) {
1594409af934SAndrew Lindesay 		HDFATAL("unable to archive message when the process coordinator"
1595409af934SAndrew Lindesay 			" has changed");
1596409af934SAndrew Lindesay 	}
1597409af934SAndrew Lindesay 	BMessenger(this).SendMessage(&message);
1598409af934SAndrew Lindesay }
1599409af934SAndrew Lindesay 
1600409af934SAndrew Lindesay 
1601409af934SAndrew Lindesay void
1602409af934SAndrew Lindesay MainWindow::_HandleProcessCoordinatorChanged(ProcessCoordinatorState& coordinatorState)
1603409af934SAndrew Lindesay {
160410cd325cSAndrew Lindesay 	AutoLocker<BLocker> lock(&fCoordinatorLock);
160510cd325cSAndrew Lindesay 
1606409af934SAndrew Lindesay 	if (fCoordinator->Identifier()
1607409af934SAndrew Lindesay 			== coordinatorState.ProcessCoordinatorIdentifier()) {
160810cd325cSAndrew Lindesay 		if (!coordinatorState.IsRunning()) {
160910cd325cSAndrew Lindesay 			if (release_sem(fCoordinatorRunningSem) != B_OK)
161010cd325cSAndrew Lindesay 				debugger("unable to release the process coordinator sem");
1611f96d1f4dSAndrew Lindesay 			HDINFO("process coordinator [%s] did complete",
1612fa5c8097SAndrew Lindesay 				fCoordinator->Name().String());
161310cd325cSAndrew Lindesay 			// complete the last one that just finished
161410cd325cSAndrew Lindesay 			BMessage* message = fCoordinator->Message();
161510cd325cSAndrew Lindesay 
161610cd325cSAndrew Lindesay 			if (message != NULL) {
161710cd325cSAndrew Lindesay 				BMessenger messenger(this);
161810cd325cSAndrew Lindesay 				message->AddInt64(KEY_ERROR_STATUS,
161910cd325cSAndrew Lindesay 					(int64) fCoordinator->ErrorStatus());
162010cd325cSAndrew Lindesay 				messenger.SendMessage(message);
162110cd325cSAndrew Lindesay 			}
162210cd325cSAndrew Lindesay 
16233538133fSAndrew Lindesay 			HDDEBUG("process coordinator report;\n---\n%s\n----",
16243538133fSAndrew Lindesay 				fCoordinator->LogReport().String());
16253538133fSAndrew Lindesay 
1626409af934SAndrew Lindesay 			delete fCoordinator;
1627409af934SAndrew Lindesay 			fCoordinator = NULL;
162810cd325cSAndrew Lindesay 
162910cd325cSAndrew Lindesay 			// now schedule the next one.
163010cd325cSAndrew Lindesay 			if (!fCoordinatorQueue.empty()) {
163110cd325cSAndrew Lindesay 				if (acquire_sem(fCoordinatorRunningSem) != B_OK)
163210cd325cSAndrew Lindesay 					debugger("unable to acquire the process coordinator sem");
163310cd325cSAndrew Lindesay 				fCoordinator = fCoordinatorQueue.front();
1634f96d1f4dSAndrew Lindesay 				HDINFO("starting next process coordinator [%s]",
163510cd325cSAndrew Lindesay 					fCoordinator->Name().String());
163610cd325cSAndrew Lindesay 				fCoordinatorQueue.pop();
163710cd325cSAndrew Lindesay 				fCoordinator->Start();
163810cd325cSAndrew Lindesay 			}
163910cd325cSAndrew Lindesay 			else {
164010cd325cSAndrew Lindesay 				_NotifyWorkStatusClear();
164195c7b018SAndrew Lindesay 				if (fShouldCloseWhenNoProcessesToCoordinate) {
164295c7b018SAndrew Lindesay 					HDINFO("no more processes to coord --> will quit");
164395c7b018SAndrew Lindesay 					BMessage message(B_QUIT_REQUESTED);
164495c7b018SAndrew Lindesay 					PostMessage(&message);
164595c7b018SAndrew Lindesay 				}
164610cd325cSAndrew Lindesay 			}
164710cd325cSAndrew Lindesay 		}
164810cd325cSAndrew Lindesay 		else {
164910cd325cSAndrew Lindesay 			_NotifyWorkStatusChange(coordinatorState.Message(),
165010cd325cSAndrew Lindesay 				coordinatorState.Progress());
165110cd325cSAndrew Lindesay 				// show the progress to the user.
165210cd325cSAndrew Lindesay 		}
165395c7b018SAndrew Lindesay 	} else {
165495c7b018SAndrew Lindesay 		_NotifyWorkStatusClear();
1655fa5c8097SAndrew Lindesay 		HDINFO("! unknown process coordinator changed");
165610cd325cSAndrew Lindesay 	}
165795c7b018SAndrew Lindesay }
1658ccf707d0SAndrew Lindesay 
1659ccf707d0SAndrew Lindesay 
1660ccf707d0SAndrew Lindesay static package_list_view_mode
1661ccf707d0SAndrew Lindesay main_window_tab_to_package_list_view_mode(int32 tab)
1662ccf707d0SAndrew Lindesay {
1663ccf707d0SAndrew Lindesay 	if (tab == TAB_PROMINENT_PACKAGES)
1664ccf707d0SAndrew Lindesay 		return PROMINENT;
1665ccf707d0SAndrew Lindesay 	return ALL;
1666ccf707d0SAndrew Lindesay }
1667ccf707d0SAndrew Lindesay 
1668ccf707d0SAndrew Lindesay 
1669ccf707d0SAndrew Lindesay void
1670ccf707d0SAndrew Lindesay MainWindow::_HandleChangePackageListViewMode()
1671ccf707d0SAndrew Lindesay {
1672ccf707d0SAndrew Lindesay 	package_list_view_mode tabMode = main_window_tab_to_package_list_view_mode(
1673ccf707d0SAndrew Lindesay 		fListTabs->Selection());
1674ccf707d0SAndrew Lindesay 	package_list_view_mode modelMode = fModel.PackageListViewMode();
1675ccf707d0SAndrew Lindesay 
1676ccf707d0SAndrew Lindesay 	if (tabMode != modelMode) {
1677ccf707d0SAndrew Lindesay 		BAutolock locker(fModel.Lock());
1678ccf707d0SAndrew Lindesay 		fModel.SetPackageListViewMode(tabMode);
1679ccf707d0SAndrew Lindesay 	}
1680ccf707d0SAndrew Lindesay }
168105880d13SAndrew Lindesay 
168205880d13SAndrew Lindesay 
168305880d13SAndrew Lindesay std::vector<DepotInfoRef>
168405880d13SAndrew Lindesay MainWindow::_CreateSnapshotOfDepots()
168505880d13SAndrew Lindesay {
168605880d13SAndrew Lindesay 	std::vector<DepotInfoRef> result;
168705880d13SAndrew Lindesay 	BAutolock locker(fModel.Lock());
168805880d13SAndrew Lindesay 	int32 countDepots = fModel.CountDepots();
168905880d13SAndrew Lindesay 	for(int32 i = 0; i < countDepots; i++)
169005880d13SAndrew Lindesay 		result.push_back(fModel.DepotAtIndex(i));
169105880d13SAndrew Lindesay 	return result;
169205880d13SAndrew Lindesay }
1693*88af15cfSAndrew Lindesay 
1694*88af15cfSAndrew Lindesay 
1695*88af15cfSAndrew Lindesay /*! This will get invoked in the case that a screenshot has been cached
1696*88af15cfSAndrew Lindesay     and so could now be loaded by some UI element. This method will then
1697*88af15cfSAndrew Lindesay     signal to other UI elements that they could load a screenshot should
1698*88af15cfSAndrew Lindesay     they have been waiting for it.
1699*88af15cfSAndrew Lindesay */
1700*88af15cfSAndrew Lindesay 
1701*88af15cfSAndrew Lindesay void
1702*88af15cfSAndrew Lindesay MainWindow::_HandleScreenshotCached(const BMessage* message)
1703*88af15cfSAndrew Lindesay {
1704*88af15cfSAndrew Lindesay 	ScreenshotCoordinate coordinate(message);
1705*88af15cfSAndrew Lindesay 	fPackageInfoView->HandleScreenshotCached(coordinate);
1706*88af15cfSAndrew Lindesay }
1707