repository_infos: Enable automatic updates on the main Haiku repostiory.
[haiku.git] / src / apps / haikudepot / ui / App.cpp
blobe12fb26b332cfdc2db7ae7bffba8ce1e91d3bbb5
1 /*
2 * Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
7 #include "App.h"
9 #include <stdio.h>
11 #include <Alert.h>
12 #include <Catalog.h>
13 #include <Entry.h>
14 #include <Message.h>
15 #include <package/PackageInfo.h>
16 #include <Path.h>
17 #include <Roster.h>
18 #include <Screen.h>
19 #include <String.h>
21 #include "support.h"
23 #include "FeaturedPackagesView.h"
24 #include "Logger.h"
25 #include "MainWindow.h"
26 #include "ServerSettings.h"
27 #include "ScreenshotWindow.h"
30 #undef B_TRANSLATION_CONTEXT
31 #define B_TRANSLATION_CONTEXT "App"
34 App::App()
36 BApplication("application/x-vnd.Haiku-HaikuDepot"),
37 fMainWindow(NULL),
38 fWindowCount(0),
39 fSettingsRead(false)
41 _CheckPackageDaemonRuns();
45 App::~App()
47 // We cannot let global destructors cleanup static BitmapRef objects,
48 // since calling BBitmap destructors needs a valid BApplication still
49 // around. That's why we do it here.
50 PackageInfo::CleanupDefaultIcon();
51 FeaturedPackagesView::CleanupIcons();
52 ScreenshotWindow::CleanupIcons();
56 bool
57 App::QuitRequested()
59 if (fMainWindow != NULL
60 && fMainWindow->LockLooperWithTimeout(1500000) == B_OK) {
61 BMessage windowSettings;
62 fMainWindow->StoreSettings(windowSettings);
64 fMainWindow->UnlockLooper();
66 _StoreSettings(windowSettings);
69 return true;
73 void
74 App::ReadyToRun()
76 if (fWindowCount > 0)
77 return;
79 BMessage settings;
80 _LoadSettings(settings);
82 fMainWindow = new MainWindow(settings);
83 _ShowWindow(fMainWindow);
87 void
88 App::MessageReceived(BMessage* message)
90 switch (message->what) {
91 case MSG_MAIN_WINDOW_CLOSED:
93 BMessage windowSettings;
94 if (message->FindMessage("window settings",
95 &windowSettings) == B_OK) {
96 _StoreSettings(windowSettings);
99 fWindowCount--;
100 if (fWindowCount == 0)
101 Quit();
102 break;
105 default:
106 BApplication::MessageReceived(message);
107 break;
112 void
113 App::RefsReceived(BMessage* message)
115 entry_ref ref;
116 int32 index = 0;
117 while (message->FindRef("refs", index++, &ref) == B_OK) {
118 BEntry entry(&ref, true);
119 _Open(entry);
124 enum arg_switch {
125 UNKNOWN_SWITCH,
126 NOT_SWITCH,
127 HELP_SWITCH,
128 WEB_APP_BASE_URL_SWITCH,
129 VERBOSITY_SWITCH,
133 static void
134 app_print_help()
136 fprintf(stdout, "HaikuDepot ");
137 fprintf(stdout, "[-u|--webappbaseurl <web-app-base-url>] ");
138 fprintf(stdout, "[-v|--verbosity [off|info|debug|trace] ");
139 fprintf(stdout, "[-h|--help]\n\n");
140 fprintf(stdout, "'-h' : causes this help text to be printed out.\n");
141 fprintf(stdout, "'-v' : allows for the verbosity level to be set.\n");
142 fprintf(stdout, "'-u' : allows for the haiku depot server to be\n");
143 fprintf(stdout, " configured.");
147 static arg_switch
148 app_resolve_switch(char *arg)
150 int arglen = strlen(arg);
152 if (arglen > 0 && arg[0] == '-') {
154 if (arglen > 3 && arg[1] == '-') { // long form
155 if (0 == strcmp(&arg[2], "webappbaseurl"))
156 return WEB_APP_BASE_URL_SWITCH;
158 if (0 == strcmp(&arg[2], "help"))
159 return HELP_SWITCH;
161 if (0 == strcmp(&arg[2], "verbosity"))
162 return VERBOSITY_SWITCH;
163 } else {
164 if (arglen == 2) { // short form
165 switch (arg[1]) {
166 case 'u':
167 return WEB_APP_BASE_URL_SWITCH;
169 case 'h':
170 return HELP_SWITCH;
172 case 'v':
173 return VERBOSITY_SWITCH;
178 return UNKNOWN_SWITCH;
181 return NOT_SWITCH;
185 void
186 App::ArgvReceived(int32 argc, char* argv[])
188 for (int i = 1; i < argc;) {
190 // check to make sure that if there is a value for the switch,
191 // that the value is in fact supplied.
193 switch (app_resolve_switch(argv[i])) {
194 case VERBOSITY_SWITCH:
195 case WEB_APP_BASE_URL_SWITCH:
196 if (i == argc-1) {
197 fprintf(stdout, "unexpected end of arguments; missing "
198 "value for switch [%s]\n", argv[i]);
199 Quit();
200 return;
202 break;
204 default:
205 break;
208 // now process each switch.
210 switch (app_resolve_switch(argv[i])) {
212 case VERBOSITY_SWITCH:
213 if (!Logger::SetLevelByName(argv[i+1])) {
214 fprintf(stdout, "unknown log level [%s]\n", argv[i + 1]);
215 Quit();
217 i++; // also move past the log level value
218 break;
220 case HELP_SWITCH:
221 app_print_help();
222 Quit();
223 break;
225 case WEB_APP_BASE_URL_SWITCH:
226 if (ServerSettings::SetBaseUrl(BUrl(argv[i + 1])) != B_OK) {
227 fprintf(stdout, "malformed web app base url; %s\n",
228 argv[i + 1]);
229 Quit();
231 else {
232 fprintf(stdout, "did configure the web base url; %s\n",
233 argv[i + 1]);
236 i++; // also move past the url value
238 break;
240 case NOT_SWITCH:
242 BEntry entry(argv[i], true);
243 _Open(entry);
244 break;
247 case UNKNOWN_SWITCH:
248 fprintf(stdout, "unknown switch; %s\n", argv[i]);
249 Quit();
250 break;
253 i++; // move on at least one arg
258 // #pragma mark - private
261 void
262 App::_Open(const BEntry& entry)
264 BPath path;
265 if (!entry.Exists() || entry.GetPath(&path) != B_OK) {
266 fprintf(stderr, "Package file not found: %s\n", path.Path());
267 return;
270 // Try to parse package file via Package Kit
271 BPackageKit::BPackageInfo info;
272 status_t status = info.ReadFromPackageFile(path.Path());
273 if (status != B_OK) {
274 fprintf(stderr, "Failed to parse package file: %s\n",
275 strerror(status));
276 return;
279 // Transfer information into PackageInfo
280 PackageInfoRef package(new(std::nothrow) PackageInfo(info), true);
281 if (package.Get() == NULL) {
282 fprintf(stderr, "Could not allocate PackageInfo\n");
283 return;
286 package->SetLocalFilePath(path.Path());
288 BMessage settings;
289 _LoadSettings(settings);
291 MainWindow* window = new MainWindow(settings, package);
292 _ShowWindow(window);
296 void
297 App::_ShowWindow(MainWindow* window)
299 window->Show();
300 fWindowCount++;
304 bool
305 App::_LoadSettings(BMessage& settings)
307 if (!fSettingsRead) {
308 fSettings = true;
309 if (load_settings(&fSettings, "main_settings", "HaikuDepot") != B_OK)
310 fSettings.MakeEmpty();
312 settings = fSettings;
313 return !fSettings.IsEmpty();
317 void
318 App::_StoreSettings(const BMessage& settings)
320 // Take what is in settings and replace data under the same name in
321 // fSettings, leaving anything in fSettings that is not contained in
322 // settings.
323 int32 i = 0;
325 char* name;
326 type_code type;
327 int32 count;
329 while (settings.GetInfo(B_ANY_TYPE, i++, &name, &type, &count) == B_OK) {
330 fSettings.RemoveName(name);
331 for (int32 j = 0; j < count; j++) {
332 const void* data;
333 ssize_t size;
334 if (settings.FindData(name, type, j, &data, &size) != B_OK)
335 break;
336 fSettings.AddData(name, type, data, size);
340 save_settings(&fSettings, "main_settings", "HaikuDepot");
344 // #pragma mark -
347 static const char* kPackageDaemonSignature
348 = "application/x-vnd.haiku-package_daemon";
350 void
351 App::_CheckPackageDaemonRuns()
353 while (!be_roster->IsRunning(kPackageDaemonSignature)) {
354 BAlert* alert = new BAlert("start_package_daemon",
355 B_TRANSLATE("HaikuDepot needs the package daemon to function, "
356 "and it appears to be not running.\n"
357 "Would you like to start it now?"),
358 B_TRANSLATE("No, quit HaikuDepot"),
359 B_TRANSLATE("Start package daemon"), NULL, B_WIDTH_AS_USUAL,
360 B_WARNING_ALERT);
361 alert->SetShortcut(0, B_ESCAPE);
363 if (alert->Go() == 0)
364 exit(1);
366 if (!_LaunchPackageDaemon())
367 break;
372 bool
373 App::_LaunchPackageDaemon()
375 status_t ret = be_roster->Launch(kPackageDaemonSignature);
376 if (ret != B_OK) {
377 BString errorMessage
378 = B_TRANSLATE("Starting the package daemon failed:\n\n%Error%");
379 errorMessage.ReplaceAll("%Error%", strerror(ret));
381 BAlert* alert = new BAlert("package_daemon_problem",
382 errorMessage,
383 B_TRANSLATE("Quit HaikuDepot"),
384 B_TRANSLATE("Try again"), NULL, B_WIDTH_AS_USUAL,
385 B_WARNING_ALERT);
386 alert->SetShortcut(0, B_ESCAPE);
388 if (alert->Go() == 0)
389 return false;
391 // TODO: Would be nice to send a message to the package daemon instead
392 // and get a reply once it is ready.
393 snooze(2000000);
394 return true;