HaikuDepot: notify work status from main window
[haiku.git] / src / apps / haikudepot / ui / App.cpp
blobe7ede8a8f4de0a1e0e17a1caa84dd5c3a8f4a97e
1 /*
2 * Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
3 * Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>.
4 * All rights reserved. Distributed under the terms of the MIT License.
5 */
8 #include "App.h"
10 #include <stdio.h>
12 #include <Alert.h>
13 #include <Catalog.h>
14 #include <Entry.h>
15 #include <Message.h>
16 #include <package/PackageInfo.h>
17 #include <Path.h>
18 #include <Roster.h>
19 #include <Screen.h>
20 #include <String.h>
22 #include "support.h"
24 #include "FeaturedPackagesView.h"
25 #include "Logger.h"
26 #include "MainWindow.h"
27 #include "ServerSettings.h"
28 #include "ScreenshotWindow.h"
31 #undef B_TRANSLATION_CONTEXT
32 #define B_TRANSLATION_CONTEXT "App"
35 App::App()
37 BApplication("application/x-vnd.Haiku-HaikuDepot"),
38 fMainWindow(NULL),
39 fWindowCount(0),
40 fSettingsRead(false)
42 _CheckPackageDaemonRuns();
46 App::~App()
48 // We cannot let global destructors cleanup static BitmapRef objects,
49 // since calling BBitmap destructors needs a valid BApplication still
50 // around. That's why we do it here.
51 PackageInfo::CleanupDefaultIcon();
52 FeaturedPackagesView::CleanupIcons();
53 ScreenshotWindow::CleanupIcons();
57 bool
58 App::QuitRequested()
60 if (fMainWindow != NULL
61 && fMainWindow->LockLooperWithTimeout(1500000) == B_OK) {
62 BMessage windowSettings;
63 fMainWindow->StoreSettings(windowSettings);
65 fMainWindow->UnlockLooper();
67 _StoreSettings(windowSettings);
70 return true;
74 void
75 App::ReadyToRun()
77 if (fWindowCount > 0)
78 return;
80 BMessage settings;
81 _LoadSettings(settings);
83 fMainWindow = new MainWindow(settings);
84 _ShowWindow(fMainWindow);
88 void
89 App::MessageReceived(BMessage* message)
91 switch (message->what) {
92 case MSG_MAIN_WINDOW_CLOSED:
94 BMessage windowSettings;
95 if (message->FindMessage("window settings",
96 &windowSettings) == B_OK) {
97 _StoreSettings(windowSettings);
100 fWindowCount--;
101 if (fWindowCount == 0)
102 Quit();
103 break;
106 default:
107 BApplication::MessageReceived(message);
108 break;
113 void
114 App::RefsReceived(BMessage* message)
116 entry_ref ref;
117 int32 index = 0;
118 while (message->FindRef("refs", index++, &ref) == B_OK) {
119 BEntry entry(&ref, true);
120 _Open(entry);
125 enum arg_switch {
126 UNKNOWN_SWITCH,
127 NOT_SWITCH,
128 HELP_SWITCH,
129 WEB_APP_BASE_URL_SWITCH,
130 VERBOSITY_SWITCH,
131 FORCE_NO_NETWORKING_SWITCH,
132 PREFER_CACHE_SWITCH,
133 DROP_CACHE_SWITCH
137 static void
138 app_print_help()
140 fprintf(stdout, "HaikuDepot ");
141 fprintf(stdout, "[-u|--webappbaseurl <web-app-base-url>]\n");
142 fprintf(stdout, "[-v|--verbosity [off|info|debug|trace]\n");
143 fprintf(stdout, "[--nonetworking]\n");
144 fprintf(stdout, "[--prefercache]\n");
145 fprintf(stdout, "[--dropcache]\n");
146 fprintf(stdout, "[-h|--help]\n");
147 fprintf(stdout, "\n");
148 fprintf(stdout, "'-h' : causes this help text to be printed out.\n");
149 fprintf(stdout, "'-v' : allows for the verbosity level to be set.\n");
150 fprintf(stdout, "'-u' : allows for the haiku depot server url to be\n");
151 fprintf(stdout, " configured.\n");
152 fprintf(stdout, "'--nonetworking' : prevents network access.**\n");
153 fprintf(stdout, "'--prefercache' : prefer to get data from cache rather\n");
154 fprintf(stdout, " then obtain data from the network.**\n");
155 fprintf(stdout, "'--dropcache' : drop cached data before performing\n");
156 fprintf(stdout, " bulk operations.**\n");
157 fprintf(stdout, "\n");
158 fprintf(stdout, "** = only applies to bulk operations.\n");
162 static arg_switch
163 app_resolve_switch(char *arg)
165 int arglen = strlen(arg);
167 if (arglen > 0 && arg[0] == '-') {
169 if (arglen > 3 && arg[1] == '-') { // long form
170 if (0 == strcmp(&arg[2], "webappbaseurl"))
171 return WEB_APP_BASE_URL_SWITCH;
173 if (0 == strcmp(&arg[2], "help"))
174 return HELP_SWITCH;
176 if (0 == strcmp(&arg[2], "verbosity"))
177 return VERBOSITY_SWITCH;
179 if (0 == strcmp(&arg[2], "nonetworking"))
180 return FORCE_NO_NETWORKING_SWITCH;
182 if (0 == strcmp(&arg[2], "prefercache"))
183 return PREFER_CACHE_SWITCH;
185 if (0 == strcmp(&arg[2], "dropcache"))
186 return DROP_CACHE_SWITCH;
187 } else {
188 if (arglen == 2) { // short form
189 switch (arg[1]) {
190 case 'u':
191 return WEB_APP_BASE_URL_SWITCH;
193 case 'h':
194 return HELP_SWITCH;
196 case 'v':
197 return VERBOSITY_SWITCH;
202 return UNKNOWN_SWITCH;
205 return NOT_SWITCH;
209 void
210 App::ArgvReceived(int32 argc, char* argv[])
212 for (int i = 1; i < argc;) {
214 // check to make sure that if there is a value for the switch,
215 // that the value is in fact supplied.
217 switch (app_resolve_switch(argv[i])) {
218 case VERBOSITY_SWITCH:
219 case WEB_APP_BASE_URL_SWITCH:
220 if (i == argc-1) {
221 fprintf(stdout, "unexpected end of arguments; missing "
222 "value for switch [%s]\n", argv[i]);
223 Quit();
224 return;
226 break;
228 default:
229 break;
232 // now process each switch.
234 switch (app_resolve_switch(argv[i])) {
236 case VERBOSITY_SWITCH:
237 if (!Logger::SetLevelByName(argv[i+1])) {
238 fprintf(stdout, "unknown log level [%s]\n", argv[i + 1]);
239 Quit();
241 i++; // also move past the log level value
242 break;
244 case HELP_SWITCH:
245 app_print_help();
246 Quit();
247 break;
249 case WEB_APP_BASE_URL_SWITCH:
250 if (ServerSettings::SetBaseUrl(BUrl(argv[i + 1])) != B_OK) {
251 fprintf(stdout, "malformed web app base url; %s\n",
252 argv[i + 1]);
253 Quit();
255 else {
256 fprintf(stdout, "did configure the web base url; %s\n",
257 argv[i + 1]);
260 i++; // also move past the url value
262 break;
264 case FORCE_NO_NETWORKING_SWITCH:
265 ServerSettings::SetForceNoNetwork(true);
266 break;
268 case PREFER_CACHE_SWITCH:
269 ServerSettings::SetPreferCache(true);
270 break;
272 case DROP_CACHE_SWITCH:
273 ServerSettings::SetDropCache(true);
274 break;
276 case NOT_SWITCH:
278 BEntry entry(argv[i], true);
279 _Open(entry);
280 break;
283 case UNKNOWN_SWITCH:
284 fprintf(stdout, "unknown switch; %s\n", argv[i]);
285 Quit();
286 break;
289 i++; // move on at least one arg
294 // #pragma mark - private
297 void
298 App::_Open(const BEntry& entry)
300 BPath path;
301 if (!entry.Exists() || entry.GetPath(&path) != B_OK) {
302 fprintf(stderr, "Package file not found: %s\n", path.Path());
303 return;
306 // Try to parse package file via Package Kit
307 BPackageKit::BPackageInfo info;
308 status_t status = info.ReadFromPackageFile(path.Path());
309 if (status != B_OK) {
310 fprintf(stderr, "Failed to parse package file: %s\n",
311 strerror(status));
312 return;
315 // Transfer information into PackageInfo
316 PackageInfoRef package(new(std::nothrow) PackageInfo(info), true);
317 if (package.Get() == NULL) {
318 fprintf(stderr, "Could not allocate PackageInfo\n");
319 return;
322 package->SetLocalFilePath(path.Path());
324 BMessage settings;
325 _LoadSettings(settings);
327 MainWindow* window = new MainWindow(settings, package);
328 _ShowWindow(window);
332 void
333 App::_ShowWindow(MainWindow* window)
335 window->Show();
336 fWindowCount++;
340 bool
341 App::_LoadSettings(BMessage& settings)
343 if (!fSettingsRead) {
344 fSettings = true;
345 if (load_settings(&fSettings, "main_settings", "HaikuDepot") != B_OK)
346 fSettings.MakeEmpty();
348 settings = fSettings;
349 return !fSettings.IsEmpty();
353 void
354 App::_StoreSettings(const BMessage& settings)
356 // Take what is in settings and replace data under the same name in
357 // fSettings, leaving anything in fSettings that is not contained in
358 // settings.
359 int32 i = 0;
361 char* name;
362 type_code type;
363 int32 count;
365 while (settings.GetInfo(B_ANY_TYPE, i++, &name, &type, &count) == B_OK) {
366 fSettings.RemoveName(name);
367 for (int32 j = 0; j < count; j++) {
368 const void* data;
369 ssize_t size;
370 if (settings.FindData(name, type, j, &data, &size) != B_OK)
371 break;
372 fSettings.AddData(name, type, data, size);
376 save_settings(&fSettings, "main_settings", "HaikuDepot");
380 // #pragma mark -
383 static const char* kPackageDaemonSignature
384 = "application/x-vnd.haiku-package_daemon";
386 void
387 App::_CheckPackageDaemonRuns()
389 while (!be_roster->IsRunning(kPackageDaemonSignature)) {
390 BAlert* alert = new BAlert("start_package_daemon",
391 B_TRANSLATE("HaikuDepot needs the package daemon to function, "
392 "and it appears to be not running.\n"
393 "Would you like to start it now?"),
394 B_TRANSLATE("No, quit HaikuDepot"),
395 B_TRANSLATE("Start package daemon"), NULL, B_WIDTH_AS_USUAL,
396 B_WARNING_ALERT);
397 alert->SetShortcut(0, B_ESCAPE);
399 if (alert->Go() == 0)
400 exit(1);
402 if (!_LaunchPackageDaemon())
403 break;
408 bool
409 App::_LaunchPackageDaemon()
411 status_t ret = be_roster->Launch(kPackageDaemonSignature);
412 if (ret != B_OK) {
413 BString errorMessage
414 = B_TRANSLATE("Starting the package daemon failed:\n\n%Error%");
415 errorMessage.ReplaceAll("%Error%", strerror(ret));
417 BAlert* alert = new BAlert("package_daemon_problem",
418 errorMessage,
419 B_TRANSLATE("Quit HaikuDepot"),
420 B_TRANSLATE("Try again"), NULL, B_WIDTH_AS_USUAL,
421 B_WARNING_ALERT);
422 alert->SetShortcut(0, B_ESCAPE);
424 if (alert->Go() == 0)
425 return false;
427 // TODO: Would be nice to send a message to the package daemon instead
428 // and get a reply once it is ready.
429 snooze(2000000);
430 return true;