1d9512848SStephan Aßmus/*
2f7c2983eSAxel Dörfler * Copyright 2015, Axel D��rfler, <axeld@pinc-software.de>.
3dc8a0aecSStephan Aßmus * Copyright 2013-2014, Stephan A��mus <superstippi@gmx.de>.
42f89f68eSRene Gollent * Copyright 2013, Rene Gollent, rene@gollent.com.
5f2cf36dfSRene Gollent * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
689b16bb4SAndrew Lindesay * Copyright 2016-2019, Andrew Lindesay <apl@lindesay.co.nz>.
7125d42d9SJulian Harnath * Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>.
8d9512848SStephan Aßmus * All rights reserved. Distributed under the terms of the MIT License.
9d9512848SStephan Aßmus */
10d9512848SStephan Aßmus
11f7c2983eSAxel Dörfler
12d9512848SStephan Aßmus#include "MainWindow.h"
13d9512848SStephan Aßmus
142f89f68eSRene Gollent#include <map>
153b17d8ddSAndrew Lindesay#include <vector>
162f89f68eSRene Gollent
17f2cf36dfSRene Gollent#include <stdio.h>
18d9512848SStephan Aßmus#include <Alert.h>
19f7628f83SStephan Aßmus#include <Autolock.h>
20d9512848SStephan Aßmus#include <Application.h>
21d9512848SStephan Aßmus#include <Button.h>
22d9512848SStephan Aßmus#include <Catalog.h>
234b930ccaSStephan Aßmus#include <CardLayout.h>
24d9512848SStephan Aßmus#include <LayoutBuilder.h>
25ac7d911bSStephan Aßmus#include <MenuBar.h>
26d9512848SStephan Aßmus#include <MenuItem.h>
27d9512848SStephan Aßmus#include <Messenger.h>
285bf2b6ebSBrian Hill#include <Roster.h>
29f7c2983eSAxel Dörfler#include <Screen.h>
30d9512848SStephan Aßmus#include <ScrollView.h>
312f89f68eSRene Gollent#include <StringList.h>
320a9c9029SStephan Aßmus#include <StringView.h>
33d9512848SStephan Aßmus#include <TabView.h>
34d9512848SStephan Aßmus
353369e03dSAndrew Lindesay#include "AppUtils.h"
367cf0e764SRene Gollent#include "AutoDeleter.h"
379e8ffcbbSRene Gollent#include "AutoLocker.h"
382f89f68eSRene Gollent#include "DecisionProvider.h"
394b930ccaSStephan Aßmus#include "FeaturedPackagesView.h"
40ac7d911bSStephan Aßmus#include "FilterView.h"
41d13c3d89SAndrew Lindesay#include "Logger.h"
42fade0fd5SStephan Aßmus#include "PackageInfoView.h"
43ac7d911bSStephan Aßmus#include "PackageListView.h"
449e8ffcbbSRene Gollent#include "PackageManager.h"
453369e03dSAndrew Lindesay#include "ProcessCoordinator.h"
463369e03dSAndrew Lindesay#include "ProcessCoordinatorFactory.h"
47a6c0fea7SStephan Aßmus#include "RatePackageWindow.h"
48e0a26dceSStephan Aßmus#include "support.h"
49d5ef985eSStephan Aßmus#include "ScreenshotWindow.h"
5081c000ddSStephan Aßmus#include "UserLoginWindow.h"
5101339a54SAndrew Lindesay#include "UserUsageConditionsWindow.h"
52125d42d9SJulian Harnath#include "WorkStatusView.h"
53ac7d911bSStephan Aßmus
542f89f68eSRene Gollent
55d9512848SStephan Aßmus#undef B_TRANSLATION_CONTEXT
56d9512848SStephan Aßmus#define B_TRANSLATION_CONTEXT "MainWindow"
57d9512848SStephan Aßmus
58ac7d911bSStephan Aßmus
59d882cc28SRene Gollentenum {
6001339a54SAndrew Lindesay	MSG_BULK_LOAD_DONE						= 'mmwd',
6101339a54SAndrew Lindesay	MSG_REFRESH_REPOS						= 'mrrp',
6201339a54SAndrew Lindesay	MSG_MANAGE_REPOS						= 'mmrp',
6301339a54SAndrew Lindesay	MSG_SOFTWARE_UPDATER					= 'mswu',
6401339a54SAndrew Lindesay	MSG_LOG_IN								= 'lgin',
6501339a54SAndrew Lindesay	MSG_LOG_OUT								= 'lgot',
6601339a54SAndrew Lindesay	MSG_AUTHORIZATION_CHANGED				= 'athc',
6701339a54SAndrew Lindesay	MSG_CATEGORIES_LIST_CHANGED				= 'clic',
6801339a54SAndrew Lindesay	MSG_PACKAGE_CHANGED						= 'pchd',
6901339a54SAndrew Lindesay	MSG_WORK_STATUS_CHANGE					= 'wsch',
7001339a54SAndrew Lindesay	MSG_WORK_STATUS_CLEAR					= 'wscl',
7101339a54SAndrew Lindesay
7201339a54SAndrew Lindesay	MSG_SHOW_FEATURED_PACKAGES				= 'sofp',
7301339a54SAndrew Lindesay	MSG_SHOW_AVAILABLE_PACKAGES				= 'savl',
7401339a54SAndrew Lindesay	MSG_SHOW_INSTALLED_PACKAGES				= 'sins',
7501339a54SAndrew Lindesay	MSG_SHOW_SOURCE_PACKAGES				= 'ssrc',
7601339a54SAndrew Lindesay	MSG_SHOW_DEVELOP_PACKAGES				= 'sdvl'
77d882cc28SRene Gollent};
78d882cc28SRene Gollent
79d882cc28SRene Gollent
802f89f68eSRene Gollentusing namespace BPackageKit;
81f2cf36dfSRene Gollentusing namespace BPackageKit::BManager::BPrivate;
822f89f68eSRene Gollent
832f89f68eSRene Gollent
842f89f68eSRene Gollenttypedef std::map<BString, PackageInfoRef> PackageInfoMap;
852f89f68eSRene Gollent
862f89f68eSRene Gollent
877cf0e764SRene Gollentstruct RefreshWorkerParameters {
887cf0e764SRene Gollent	MainWindow* window;
897cf0e764SRene Gollent	bool forceRefresh;
907cf0e764SRene Gollent
917cf0e764SRene Gollent	RefreshWorkerParameters(MainWindow* window, bool forceRefresh)
927cf0e764SRene Gollent		:
937cf0e764SRene Gollent		window(window),
947cf0e764SRene Gollent		forceRefresh(forceRefresh)
955f448959SAxel Dörfler	{
965f448959SAxel Dörfler	}
977cf0e764SRene Gollent};
987cf0e764SRene Gollent
997cf0e764SRene Gollent
10089b16bb4SAndrew Lindesayclass MainWindowModelListener : public ModelListener {
1018f03a0f9SStephan Aßmuspublic:
10289b16bb4SAndrew Lindesay	MainWindowModelListener(const BMessenger& messenger)
1038f03a0f9SStephan Aßmus		:
1048f03a0f9SStephan Aßmus		fMessenger(messenger)
1058f03a0f9SStephan Aßmus	{
1068f03a0f9SStephan Aßmus	}
10787084745SMichael Lotz
1088f03a0f9SStephan Aßmus	virtual void AuthorizationChanged()
1098f03a0f9SStephan Aßmus	{
1108f03a0f9SStephan Aßmus		if (fMessenger.IsValid())
1118f03a0f9SStephan Aßmus			fMessenger.SendMessage(MSG_AUTHORIZATION_CHANGED);
1128f03a0f9SStephan Aßmus	}
1138f03a0f9SStephan Aßmus
11489b16bb4SAndrew Lindesay	virtual void CategoryListChanged()
11589b16bb4SAndrew Lindesay	{
11689b16bb4SAndrew Lindesay		if (fMessenger.IsValid())
11789b16bb4SAndrew Lindesay			fMessenger.SendMessage(MSG_CATEGORIES_LIST_CHANGED);
11889b16bb4SAndrew Lindesay	}
11989b16bb4SAndrew Lindesay
1208f03a0f9SStephan Aßmusprivate:
1218f03a0f9SStephan Aßmus	BMessenger	fMessenger;
1228f03a0f9SStephan Aßmus};
1238f03a0f9SStephan Aßmus
1248f03a0f9SStephan Aßmus
125f7c2983eSAxel DörflerMainWindow::MainWindow(const BMessage& settings)
126d9512848SStephan Aßmus	:
127f7c2983eSAxel Dörfler	BWindow(BRect(50, 50, 650, 550), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"),
128127061e7SStephan Aßmus		B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
1292f89f68eSRene Gollent		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
130d5ef985eSStephan Aßmus	fScreenshotWindow(NULL),
131e0a26dceSStephan Aßmus	fUserMenu(NULL),
132e0a26dceSStephan Aßmus	fLogInItem(NULL),
133e0a26dceSStephan Aßmus	fLogOutItem(NULL),
134976cadf1SAndrew Lindesay	fUsersUserUsageConditionsMenuItem(NULL),
13589b16bb4SAndrew Lindesay	fModelListener(new MainWindowModelListener(BMessenger(this)), true),
1363369e03dSAndrew Lindesay	fBulkLoadProcessCoordinator(NULL),
1373369e03dSAndrew Lindesay	fSinglePackageMode(false)
138d9512848SStephan Aßmus{
139cbadcae1SHumdinger	BMenuBar* menuBar = new BMenuBar("Main Menu");
140686357a3SStephan Aßmus	_BuildMenu(menuBar);
1411f67148fSRene Gollent
142cbadcae1SHumdinger	BMenuBar* userMenuBar = new BMenuBar("User Menu");
143e0a26dceSStephan Aßmus	_BuildUserMenu(userMenuBar);
144e0a26dceSStephan Aßmus	set_small_font(userMenuBar);
145e0a26dceSStephan Aßmus	userMenuBar->SetExplicitMaxSize(BSize(B_SIZE_UNSET,
146e0a26dceSStephan Aßmus		menuBar->MaxSize().height));
147d2d4866dSAndrew Lindesay	_UpdateAuthorization();
148e0a26dceSStephan Aßmus
149f302cc52SRene Gollent	fFilterView = new FilterView();
1504b930ccaSStephan Aßmus	fFeaturedPackagesView = new FeaturedPackagesView();
151b748950bSStephan Aßmus	fPackageListView = new PackageListView(fModel.Lock());
1529e8ffcbbSRene Gollent	fPackageInfoView = new PackageInfoView(fModel.Lock(), this);
1531f67148fSRene Gollent
154127061e7SStephan Aßmus	fSplitView = new BSplitView(B_VERTICAL, 5.0f);
1551f67148fSRene Gollent
156125d42d9SJulian Harnath	fWorkStatusView = new WorkStatusView("work status");
157125d42d9SJulian Harnath	fPackageListView->AttachWorkStatusView(fWorkStatusView);
158125d42d9SJulian Harnath
159e00a489bSAugustin Cavalier	fListTabs = new TabView(BMessenger(this),
160e00a489bSAugustin Cavalier		BMessage(MSG_SHOW_FEATURED_PACKAGES), "list tabs");
161e00a489bSAugustin Cavalier	fListTabs->AddTab(fFeaturedPackagesView);
162e00a489bSAugustin Cavalier	fListTabs->AddTab(fPackageListView);
1634b930ccaSStephan Aßmus
164ac7d911bSStephan Aßmus	BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f)
165e0a26dceSStephan Aßmus		.AddGroup(B_HORIZONTAL, 0.0f)
166e0a26dceSStephan Aßmus			.Add(menuBar, 1.0f)
167e0a26dceSStephan Aßmus			.Add(userMenuBar, 0.0f)
168e0a26dceSStephan Aßmus		.End()
169686357a3SStephan Aßmus		.Add(fFilterView)
170601d751fSStephan Aßmus		.AddSplit(fSplitView)
171601d751fSStephan Aßmus			.AddGroup(B_VERTICAL)
172e00a489bSAugustin Cavalier				.Add(fListTabs)
173601d751fSStephan Aßmus				.SetInsets(
174601d751fSStephan Aßmus					B_USE_DEFAULT_SPACING, 0.0f,
175601d751fSStephan Aßmus					B_USE_DEFAULT_SPACING, 0.0f)
176ac7d911bSStephan Aßmus			.End()
177601d751fSStephan Aßmus			.Add(fPackageInfoView)
178ac7d911bSStephan Aßmus		.End()
179125d42d9SJulian Harnath		.Add(fWorkStatusView)
180ac7d911bSStephan Aßmus	;
181ac7d911bSStephan Aßmus
182686357a3SStephan Aßmus	fSplitView->SetCollapsible(0, false);
1833aac7049SStephan Aßmus	fSplitView->SetCollapsible(1, false);
1843883c020SStephan Aßmus
1858f03a0f9SStephan Aßmus	fModel.AddListener(fModelListener);
1868f03a0f9SStephan Aßmus
187572c7292SStephan Aßmus	// Restore settings
188572c7292SStephan Aßmus	BMessage columnSettings;
189572c7292SStephan Aßmus	if (settings.FindMessage("column settings", &columnSettings) == B_OK)
190572c7292SStephan Aßmus		fPackageListView->LoadState(&columnSettings);
191572c7292SStephan Aßmus
192870554acSStephan Aßmus	bool showOption;
1932997e05bSStephan Aßmus	if (settings.FindBool("show featured packages", &showOption) == B_OK)
1942997e05bSStephan Aßmus		fModel.SetShowFeaturedPackages(showOption);
1952997e05bSStephan Aßmus	if (settings.FindBool("show available packages", &showOption) == B_OK)
1962997e05bSStephan Aßmus		fModel.SetShowAvailablePackages(showOption);
1972997e05bSStephan Aßmus	if (settings.FindBool("show installed packages", &showOption) == B_OK)
1982997e05bSStephan Aßmus		fModel.SetShowInstalledPackages(showOption);
199870554acSStephan Aßmus	if (settings.FindBool("show develop packages", &showOption) == B_OK)
200870554acSStephan Aßmus		fModel.SetShowDevelopPackages(showOption);
201870554acSStephan Aßmus	if (settings.FindBool("show source packages", &showOption) == B_OK)
202870554acSStephan Aßmus		fModel.SetShowSourcePackages(showOption);
203870554acSStephan Aßmus
2042997e05bSStephan Aßmus	if (fModel.ShowFeaturedPackages())
205e00a489bSAugustin Cavalier		fListTabs->Select(0);
2062997e05bSStephan Aßmus	else
207e00a489bSAugustin Cavalier		fListTabs->Select(1);
2082997e05bSStephan Aßmus
209d2d4866dSAndrew Lindesay	_RestoreNickname(settings);
210f7c2983eSAxel Dörfler	_RestoreWindowFrame(settings);
211f7c2983eSAxel Dörfler
21272fff6d3SJulian Harnath	atomic_set(&fPackagesToShowListID, 0);
21372fff6d3SJulian Harnath
2148f03a0f9SStephan Aßmus	// start worker threads
215a852846fSIngo Weinhold	BPackageRoster().StartWatching(this,
216a852846fSIngo Weinhold		B_WATCH_PACKAGE_INSTALLATION_LOCATIONS);
217a852846fSIngo Weinhold
2183369e03dSAndrew Lindesay	_StartBulkLoad();
2199e8ffcbbSRene Gollent
22063975654SStephan Aßmus	_InitWorkerThreads();
221d9512848SStephan Aßmus}
222d9512848SStephan Aßmus
223d9512848SStephan Aßmus
224f7c2983eSAxel DörflerMainWindow::MainWindow(const BMessage& settings, const PackageInfoRef& package)
2256d519fd1SStephan Aßmus	:
226f7c2983eSAxel Dörfler	BWindow(BRect(50, 50, 650, 350), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"),
2276d519fd1SStephan Aßmus		B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
2286d519fd1SStephan Aßmus		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
229d78bfd8dSJulian Harnath	fWorkStatusView(NULL),
230d5ef985eSStephan Aßmus	fScreenshotWindow(NULL),
231e0a26dceSStephan Aßmus	fUserMenu(NULL),
232e0a26dceSStephan Aßmus	fLogInItem(NULL),
2336d519fd1SStephan Aßmus	fLogOutItem(NULL),
234976cadf1SAndrew Lindesay	fUsersUserUsageConditionsMenuItem(NULL),
23589b16bb4SAndrew Lindesay	fModelListener(new MainWindowModelListener(BMessenger(this)), true),
2363369e03dSAndrew Lindesay	fBulkLoadProcessCoordinator(NULL),
2373369e03dSAndrew Lindesay	fSinglePackageMode(true)
2386d519fd1SStephan Aßmus{
2396d519fd1SStephan Aßmus	fFilterView = new FilterView();
2406d519fd1SStephan Aßmus	fPackageListView = new PackageListView(fModel.Lock());
2416d519fd1SStephan Aßmus	fPackageInfoView = new PackageInfoView(fModel.Lock(), this);
2426d519fd1SStephan Aßmus
2436d519fd1SStephan Aßmus	BLayoutBuilder::Group<>(this, B_VERTICAL)
2446d519fd1SStephan Aßmus		.Add(fPackageInfoView)
2456d519fd1SStephan Aßmus		.SetInsets(0, B_USE_WINDOW_INSETS, 0, 0)
2466d519fd1SStephan Aßmus	;
2476d519fd1SStephan Aßmus
2486d519fd1SStephan Aßmus	fModel.AddListener(fModelListener);
2496d519fd1SStephan Aßmus
2506d519fd1SStephan Aßmus	// Restore settings
251d2d4866dSAndrew Lindesay	_RestoreNickname(settings);
252f7c2983eSAxel Dörfler	_RestoreWindowFrame(settings);
2536d519fd1SStephan Aßmus
2546d519fd1SStephan Aßmus	fPackageInfoView->SetPackage(package);
25563975654SStephan Aßmus
25663975654SStephan Aßmus	_InitWorkerThreads();
2576d519fd1SStephan Aßmus}
2586d519fd1SStephan Aßmus
2596d519fd1SStephan Aßmus
260d9512848SStephan AßmusMainWindow::~MainWindow()
261d9512848SStephan Aßmus{
262a852846fSIngo Weinhold	BPackageRoster().StopWatching(this);
263a852846fSIngo Weinhold
2649e8ffcbbSRene Gollent	delete_sem(fPendingActionsSem);
26505bffa62SStephan Aßmus	if (fPendingActionsWorker >= 0)
26605bffa62SStephan Aßmus		wait_for_thread(fPendingActionsWorker, NULL);
2670d50f6afSStephan Aßmus
2680d50f6afSStephan Aßmus	delete_sem(fPackageToPopulateSem);
26905bffa62SStephan Aßmus	if (fPopulatePackageWorker >= 0)
27005bffa62SStephan Aßmus		wait_for_thread(fPopulatePackageWorker, NULL);
271d5ef985eSStephan Aßmus
27272fff6d3SJulian Harnath	delete_sem(fNewPackagesToShowSem);
27372fff6d3SJulian Harnath	delete_sem(fShowPackagesAcknowledgeSem);
27472fff6d3SJulian Harnath	if (fShowPackagesWorker >= 0)
27572fff6d3SJulian Harnath		wait_for_thread(fShowPackagesWorker, NULL);
27672fff6d3SJulian Harnath
277d5ef985eSStephan Aßmus	if (fScreenshotWindow != NULL && fScreenshotWindow->Lock())
278d5ef985eSStephan Aßmus		fScreenshotWindow->Quit();
279d9512848SStephan Aßmus}
280d9512848SStephan Aßmus
281d9512848SStephan Aßmus
282d9512848SStephan Aßmusbool
283d9512848SStephan AßmusMainWindow::QuitRequested()
284d9512848SStephan Aßmus{
285572c7292SStephan Aßmus	BMessage settings;
286572c7292SStephan Aßmus	StoreSettings(settings);
287572c7292SStephan Aßmus
288d9512848SStephan Aßmus	BMessage message(MSG_MAIN_WINDOW_CLOSED);
2893369e03dSAndrew Lindesay	message.AddMessage(KEY_WINDOW_SETTINGS, &settings);
290572c7292SStephan Aßmus
291d9512848SStephan Aßmus	be_app->PostMessage(&message);
2921f67148fSRene Gollent
2933369e03dSAndrew Lindesay	_StopBulkLoad();
2943369e03dSAndrew Lindesay
295d9512848SStephan Aßmus	return true;
296d9512848SStephan Aßmus}
297d9512848SStephan Aßmus
298d9512848SStephan Aßmus
299d9512848SStephan Aßmusvoid
300d9512848SStephan AßmusMainWindow::MessageReceived(BMessage* message)
301d9512848SStephan Aßmus{
302d9512848SStephan Aßmus	switch (message->what) {
3033369e03dSAndrew Lindesay		case MSG_BULK_LOAD_DONE:
3043369e03dSAndrew Lindesay			_BulkLoadCompleteReceived();
305d882cc28SRene Gollent			break;
306d9512848SStephan Aßmus		case B_SIMPLE_DATA:
307d9512848SStephan Aßmus		case B_REFS_RECEIVED:
308f7628f83SStephan Aßmus			// TODO: ?
309d9512848SStephan Aßmus			break;
3100aea9219SStephan Aßmus
311a852846fSIngo Weinhold		case B_PACKAGE_UPDATE:
312a852846fSIngo Weinhold			// TODO: We should do a more selective update depending on the
31387084745SMichael Lotz			// "event", "location", and "change count" fields!
3143369e03dSAndrew Lindesay			_StartBulkLoad(false);
315a852846fSIngo Weinhold			break;
316a852846fSIngo Weinhold
3175bf2b6ebSBrian Hill		case MSG_REFRESH_REPOS:
3183369e03dSAndrew Lindesay			_StartBulkLoad(true);
3193369e03dSAndrew Lindesay			break;
3203369e03dSAndrew Lindesay
3213369e03dSAndrew Lindesay		case MSG_WORK_STATUS_CHANGE:
3223369e03dSAndrew Lindesay			_HandleWorkStatusChangeMessageReceived(message);
3234bee7f07SRene Gollent			break;
324870554acSStephan Aßmus
3255bf2b6ebSBrian Hill		case MSG_MANAGE_REPOS:
3265bf2b6ebSBrian Hill			be_roster->Launch("application/x-vnd.Haiku-Repositories");
3275bf2b6ebSBrian Hill			break;
3285bf2b6ebSBrian Hill
329d144f952SAugustin Cavalier		case MSG_SOFTWARE_UPDATER:
330d144f952SAugustin Cavalier			be_roster->Launch("application/x-vnd.haiku-softwareupdater");
331d144f952SAugustin Cavalier			break;
332d144f952SAugustin Cavalier
33381c000ddSStephan Aßmus		case MSG_LOG_IN:
3341bbda92dSStephan Aßmus			_OpenLoginWindow(BMessage());
33581c000ddSStephan Aßmus			break;
33681c000ddSStephan Aßmus
3378f03a0f9SStephan Aßmus		case MSG_LOG_OUT:
338d2d4866dSAndrew Lindesay			fModel.SetNickname("");
3398f03a0f9SStephan Aßmus			break;
3408f03a0f9SStephan Aßmus
34101339a54SAndrew Lindesay		case MSG_VIEW_LATEST_USER_USAGE_CONDITIONS:
342d2d4866dSAndrew Lindesay			_ViewUserUsageConditions(LATEST);
343d2d4866dSAndrew Lindesay			break;
344d2d4866dSAndrew Lindesay
345d2d4866dSAndrew Lindesay		case MSG_VIEW_USERS_USER_USAGE_CONDITIONS:
346d2d4866dSAndrew Lindesay			_ViewUserUsageConditions(USER);
34701339a54SAndrew Lindesay			break;
34801339a54SAndrew Lindesay
3498f03a0f9SStephan Aßmus		case MSG_AUTHORIZATION_CHANGED:
3508f03a0f9SStephan Aßmus			_UpdateAuthorization();
3518f03a0f9SStephan Aßmus			break;
3528f03a0f9SStephan Aßmus
35389b16bb4SAndrew Lindesay		case MSG_CATEGORIES_LIST_CHANGED:
35489b16bb4SAndrew Lindesay			fFilterView->AdoptModel(fModel);
35589b16bb4SAndrew Lindesay			break;
35689b16bb4SAndrew Lindesay
3574fade61fSStephan Aßmus		case MSG_SHOW_FEATURED_PACKAGES:
358e00a489bSAugustin Cavalier			// check to see if we aren't already on the current tab
359e00a489bSAugustin Cavalier			if (fListTabs->Selection() ==
360e00a489bSAugustin Cavalier					(fModel.ShowFeaturedPackages() ? 0 : 1))
361e00a489bSAugustin Cavalier				break;
3624fade61fSStephan Aßmus			{
3634fade61fSStephan Aßmus				BAutolock locker(fModel.Lock());
3644fade61fSStephan Aßmus				fModel.SetShowFeaturedPackages(
365e00a489bSAugustin Cavalier					fListTabs->Selection() == 0);
3664fade61fSStephan Aßmus			}
3674fade61fSStephan Aßmus			_AdoptModel();
3684fade61fSStephan Aßmus			break;
3694fade61fSStephan Aßmus
370fdec4227SStephan Aßmus		case MSG_SHOW_AVAILABLE_PACKAGES:
371fdec4227SStephan Aßmus			{
372fdec4227SStephan Aßmus				BAutolock locker(fModel.Lock());
373fdec4227SStephan Aßmus				fModel.SetShowAvailablePackages(
374fdec4227SStephan Aßmus					!fModel.ShowAvailablePackages());
375fdec4227SStephan Aßmus			}
376fdec4227SStephan Aßmus			_AdoptModel();
377fdec4227SStephan Aßmus			break;
378fdec4227SStephan Aßmus
379fdec4227SStephan Aßmus		case MSG_SHOW_INSTALLED_PACKAGES:
380fdec4227SStephan Aßmus			{
381fdec4227SStephan Aßmus				BAutolock locker(fModel.Lock());
382fdec4227SStephan Aßmus				fModel.SetShowInstalledPackages(
383fdec4227SStephan Aßmus					!fModel.ShowInstalledPackages());
384fdec4227SStephan Aßmus			}
385fdec4227SStephan Aßmus			_AdoptModel();
386fdec4227SStephan Aßmus			break;
387fdec4227SStephan Aßmus
388870554acSStephan Aßmus		case MSG_SHOW_SOURCE_PACKAGES:
389870554acSStephan Aßmus			{
3905f448959SAxel Dörfler				BAutolock locker(fModel.Lock());
391870554acSStephan Aßmus				fModel.SetShowSourcePackages(!fModel.ShowSourcePackages());
392870554acSStephan Aßmus			}
393870554acSStephan Aßmus			_AdoptModel();
394870554acSStephan Aßmus			break;
395870554acSStephan Aßmus
396870554acSStephan Aßmus		case MSG_SHOW_DEVELOP_PACKAGES:
397870554acSStephan Aßmus			{
3985f448959SAxel Dörfler				BAutolock locker(fModel.Lock());
399870554acSStephan Aßmus				fModel.SetShowDevelopPackages(!fModel.ShowDevelopPackages());
400870554acSStephan Aßmus			}
401870554acSStephan Aßmus			_AdoptModel();
402870554acSStephan Aßmus			break;
403870554acSStephan Aßmus
404a9edb9bfSAndrew Lindesay			// this may be triggered by, for example, a user rating being added
405a9edb9bfSAndrew Lindesay			// or having been altered.
406a9edb9bfSAndrew Lindesay		case MSG_SERVER_DATA_CHANGED:
407a9edb9bfSAndrew Lindesay		{
408a9edb9bfSAndrew Lindesay			BString name;
409a9edb9bfSAndrew Lindesay			if (message->FindString("name", &name) == B_OK) {
410a9edb9bfSAndrew Lindesay				BAutolock locker(fModel.Lock());
411a9edb9bfSAndrew Lindesay				if (fPackageInfoView->Package()->Name() == name) {
412a9edb9bfSAndrew Lindesay					_PopulatePackageAsync(true);
413a9edb9bfSAndrew Lindesay				} else {
414a9edb9bfSAndrew Lindesay					if (Logger::IsDebugEnabled()) {
415a9edb9bfSAndrew Lindesay						printf("pkg [%s] is updated on the server, but is "
416a9edb9bfSAndrew Lindesay							"not selected so will not be updated.\n",
417a9edb9bfSAndrew Lindesay							name.String());
418a9edb9bfSAndrew Lindesay					}
419a9edb9bfSAndrew Lindesay				}
420a9edb9bfSAndrew Lindesay			}
421a9edb9bfSAndrew Lindesay        	break;
422a9edb9bfSAndrew Lindesay        }
423a9edb9bfSAndrew Lindesay
4240aea9219SStephan Aßmus		case MSG_PACKAGE_SELECTED:
4250aea9219SStephan Aßmus		{
42672992391SStephan Aßmus			BString name;
42772992391SStephan Aßmus			if (message->FindString("name", &name) == B_OK) {
42875ba9dbfSStephan Aßmus				BAutolock locker(fModel.Lock());
429f7628f83SStephan Aßmus				int count = fVisiblePackages.CountItems();
430f7628f83SStephan Aßmus				for (int i = 0; i < count; i++) {
431f7628f83SStephan Aßmus					const PackageInfoRef& package
432f7628f83SStephan Aßmus						= fVisiblePackages.ItemAtFast(i);
43372992391SStephan Aßmus					if (package.Get() != NULL && package->Name() == name) {
43475ba9dbfSStephan Aßmus						locker.Unlock();
435f7628f83SStephan Aßmus						_AdoptPackage(package);
436f7628f83SStephan Aßmus						break;
437f7628f83SStephan Aßmus					}
438f7628f83SStephan Aßmus				}
4390aea9219SStephan Aßmus			} else {
4400aea9219SStephan Aßmus				_ClearPackage();
4410aea9219SStephan Aßmus			}
4420aea9219SStephan Aßmus			break;
4430aea9219SStephan Aßmus		}
4441f67148fSRene Gollent
44542479955SStephan Aßmus		case MSG_CATEGORY_SELECTED:
44642479955SStephan Aßmus		{
44789b16bb4SAndrew Lindesay			BString code;
44889b16bb4SAndrew Lindesay			if (message->FindString("code", &code) != B_OK)
44989b16bb4SAndrew Lindesay				code = "";
450ab172803SStephan Aßmus			{
451ab172803SStephan Aßmus				BAutolock locker(fModel.Lock());
45289b16bb4SAndrew Lindesay				fModel.SetCategory(code);
453ab172803SStephan Aßmus			}
454ab172803SStephan Aßmus			_AdoptModel();
455ab172803SStephan Aßmus			break;
456ab172803SStephan Aßmus		}
457ab172803SStephan Aßmus
45809d44cecSStephan Aßmus		case MSG_DEPOT_SELECTED:
45909d44cecSStephan Aßmus		{
46009d44cecSStephan Aßmus			BString name;
46109d44cecSStephan Aßmus			if (message->FindString("name", &name) != B_OK)
46209d44cecSStephan Aßmus				name = "";
463ab172803SStephan Aßmus			{
464ab172803SStephan Aßmus				BAutolock locker(fModel.Lock());
465ab172803SStephan Aßmus				fModel.SetDepot(name);
466ab172803SStephan Aßmus			}
46709d44cecSStephan Aßmus			_AdoptModel();
468b965ce70SHumdinger			_UpdateAvailableRepositories();
46909d44cecSStephan Aßmus			break;
47009d44cecSStephan Aßmus		}
4711f67148fSRene Gollent
47209d44cecSStephan Aßmus		case MSG_SEARCH_TERMS_MODIFIED:
47309d44cecSStephan Aßmus		{
47409d44cecSStephan Aßmus			// TODO: Do this with a delay!
47509d44cecSStephan Aßmus			BString searchTerms;
47609d44cecSStephan Aßmus			if (message->FindString("search terms", &searchTerms) != B_OK)
47709d44cecSStephan Aßmus				searchTerms = "";
478ab172803SStephan Aßmus			{
479ab172803SStephan Aßmus				BAutolock locker(fModel.Lock());
480ab172803SStephan Aßmus				fModel.SetSearchTerms(searchTerms);
481ab172803SStephan Aßmus			}
48209d44cecSStephan Aßmus			_AdoptModel();
483e550d7b8SRene Gollent			break;
484e550d7b8SRene Gollent		}
485e550d7b8SRene Gollent
486da651104SStephan Aßmus		case MSG_PACKAGE_CHANGED:
487e550d7b8SRene Gollent		{
488e550d7b8SRene Gollent			PackageInfo* info;
4895f448959SAxel Dörfler			if (message->FindPointer("package", (void**)&info) == B_OK) {
490e550d7b8SRene Gollent				PackageInfoRef ref(info, true);
491da651104SStephan Aßmus				uint32 changes;
492da651104SStephan Aßmus				if (message->FindUInt32("changes", &changes) != B_OK)
493da651104SStephan Aßmus					changes = 0;
494da651104SStephan Aßmus				if ((changes & PKG_CHANGED_STATE) != 0) {
495da651104SStephan Aßmus					BAutolock locker(fModel.Lock());
496da651104SStephan Aßmus					fModel.SetPackageState(ref, ref->State());
497da651104SStephan Aßmus				}
49857e51fffSStephan Aßmus
49957e51fffSStephan Aßmus				// Asynchronous updates to the package information
50057e51fffSStephan Aßmus				// can mean that the package needs to be added or
50157e51fffSStephan Aßmus				// removed to/from the visible packages when the current
50257e51fffSStephan Aßmus				// filter parameters are re-evaluated on this package.
50357e51fffSStephan Aßmus				bool wasVisible = fVisiblePackages.Contains(ref);
50457e51fffSStephan Aßmus				bool isVisible;
50557e51fffSStephan Aßmus				{
506da651104SStephan Aßmus					BAutolock locker(fModel.Lock());
5070c6df5d5SStephan Aßmus					// The package didn't get a chance yet to be in the
5080c6df5d5SStephan Aßmus					// visible package list
50939f49f70SJulian Harnath					isVisible = fModel.MatchesFilter(ref);
51057e51fffSStephan Aßmus
51157e51fffSStephan Aßmus					// Transfer this single package, otherwise we miss
51257e51fffSStephan Aßmus					// other packages if they appear or disappear along
51357e51fffSStephan Aßmus					// with this one before receive a notification for
51457e51fffSStephan Aßmus					// them.
51557e51fffSStephan Aßmus					if (isVisible) {
51657e51fffSStephan Aßmus						fVisiblePackages.Add(ref);
51757e51fffSStephan Aßmus					} else if (wasVisible)
51857e51fffSStephan Aßmus						fVisiblePackages.Remove(ref);
51957e51fffSStephan Aßmus				}
52057e51fffSStephan Aßmus
52157e51fffSStephan Aßmus				if (wasVisible != isVisible) {
52257e51fffSStephan Aßmus					if (!isVisible) {
52357e51fffSStephan Aßmus						fPackageListView->RemovePackage(ref);
52457e51fffSStephan Aßmus						fFeaturedPackagesView->RemovePackage(ref);
52557e51fffSStephan Aßmus					} else {
52657e51fffSStephan Aßmus						fPackageListView->AddPackage(ref);
52757e51fffSStephan Aßmus						if (ref->IsProminent())
52857e51fffSStephan Aßmus							fFeaturedPackagesView->AddPackage(ref);
52957e51fffSStephan Aßmus					}
530da651104SStephan Aßmus				}
5314e6fbe03SJulian Harnath
5324e6fbe03SJulian Harnath				if (!fSinglePackageMode && (changes & PKG_CHANGED_STATE) != 0)
5334e6fbe03SJulian Harnath					fWorkStatusView->PackageStatusChanged(ref);
534e550d7b8SRene Gollent			}
535a6c0fea7SStephan Aßmus			break;
536a6c0fea7SStephan Aßmus		}
537a6c0fea7SStephan Aßmus
538a6c0fea7SStephan Aßmus		case MSG_RATE_PACKAGE:
5391bbda92dSStephan Aßmus			_RatePackage();
540a6c0fea7SStephan Aßmus			break;
5411f67148fSRene Gollent
542d5ef985eSStephan Aßmus		case MSG_SHOW_SCREENSHOT:
543d5ef985eSStephan Aßmus			_ShowScreenshot();
544d5ef985eSStephan Aßmus			break;
545d5ef985eSStephan Aßmus
546125d42d9SJulian Harnath		case MSG_PACKAGE_WORKER_BUSY:
547125d42d9SJulian Harnath		{
548125d42d9SJulian Harnath			BString reason;
549125d42d9SJulian Harnath			status_t status = message->FindString("reason", &reason);
550125d42d9SJulian Harnath			if (status != B_OK)
551125d42d9SJulian Harnath				break;
552d78bfd8dSJulian Harnath			if (!fSinglePackageMode)
553d78bfd8dSJulian Harnath				fWorkStatusView->SetBusy(reason);
554125d42d9SJulian Harnath			break;
555125d42d9SJulian Harnath		}
556125d42d9SJulian Harnath
557125d42d9SJulian Harnath		case MSG_PACKAGE_WORKER_IDLE:
558d78bfd8dSJulian Harnath			if (!fSinglePackageMode)
559d78bfd8dSJulian Harnath				fWorkStatusView->SetIdle();
560125d42d9SJulian Harnath			break;
561125d42d9SJulian Harnath
56272fff6d3SJulian Harnath		case MSG_ADD_VISIBLE_PACKAGES:
56372fff6d3SJulian Harnath		{
56472fff6d3SJulian Harnath			struct SemaphoreReleaser {
56572fff6d3SJulian Harnath				SemaphoreReleaser(sem_id semaphore)
56672fff6d3SJulian Harnath					:
56772fff6d3SJulian Harnath					fSemaphore(semaphore)
56872fff6d3SJulian Harnath				{ }
56972fff6d3SJulian Harnath
57072fff6d3SJulian Harnath				~SemaphoreReleaser() { release_sem(fSemaphore); }
57172fff6d3SJulian Harnath
57272fff6d3SJulian Harnath				sem_id fSemaphore;
57372fff6d3SJulian Harnath			};
57472fff6d3SJulian Harnath
57572fff6d3SJulian Harnath			// Make sure acknowledge semaphore is released even on error,
57672fff6d3SJulian Harnath			// so the worker thread won't be blocked
57772fff6d3SJulian Harnath			SemaphoreReleaser acknowledger(fShowPackagesAcknowledgeSem);
57872fff6d3SJulian Harnath
57972fff6d3SJulian Harnath			int32 numPackages = 0;
58072fff6d3SJulian Harnath			type_code unused;
58172fff6d3SJulian Harnath			status_t status = message->GetInfo("package_ref", &unused,
58272fff6d3SJulian Harnath				&numPackages);
58372fff6d3SJulian Harnath			if (status != B_OK || numPackages == 0)
58472fff6d3SJulian Harnath				break;
58572fff6d3SJulian Harnath
58672fff6d3SJulian Harnath			int32 listID = 0;
58772fff6d3SJulian Harnath			status = message->FindInt32("list_id", &listID);
58872fff6d3SJulian Harnath			if (status != B_OK)
58972fff6d3SJulian Harnath				break;
59072fff6d3SJulian Harnath			if (listID != atomic_get(&fPackagesToShowListID)) {
59172fff6d3SJulian Harnath				// list is outdated, ignore
59272fff6d3SJulian Harnath				break;
59372fff6d3SJulian Harnath			}
59472fff6d3SJulian Harnath
59572fff6d3SJulian Harnath			for (int i = 0; i < numPackages; i++) {
59672fff6d3SJulian Harnath				PackageInfo* packageRaw = NULL;
59772fff6d3SJulian Harnath				status = message->FindPointer("package_ref", i,
59872fff6d3SJulian Harnath					(void**)&packageRaw);
59972fff6d3SJulian Harnath				if (status != B_OK)
60072fff6d3SJulian Harnath					break;
60172fff6d3SJulian Harnath				PackageInfoRef package(packageRaw, true);
60272fff6d3SJulian Harnath
60372fff6d3SJulian Harnath				fPackageListView->AddPackage(package);
60472fff6d3SJulian Harnath				if (package->IsProminent())
60572fff6d3SJulian Harnath					fFeaturedPackagesView->AddPackage(package);
60672fff6d3SJulian Harnath			}
60772fff6d3SJulian Harnath			break;
60872fff6d3SJulian Harnath		}
60972fff6d3SJulian Harnath
61072fff6d3SJulian Harnath		case MSG_UPDATE_SELECTED_PACKAGE:
61172fff6d3SJulian Harnath		{
61272fff6d3SJulian Harnath			const PackageInfoRef& selectedPackage = fPackageInfoView->Package();
61372fff6d3SJulian Harnath			fFeaturedPackagesView->SelectPackage(selectedPackage, true);
61472fff6d3SJulian Harnath			fPackageListView->SelectPackage(selectedPackage);
61572fff6d3SJulian Harnath
616