diff --git a/src/apps/haikudepot/HaikuDepotConstants.cpp b/src/apps/haikudepot/HaikuDepotConstants.cpp new file mode 100644 index 0000000000..fdc27c96cc --- /dev/null +++ b/src/apps/haikudepot/HaikuDepotConstants.cpp @@ -0,0 +1,10 @@ +/* + * Copyright 2026, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ +#include "HaikuDepotConstants.h" + +const char* const shared_message_keys::kKeyPackageName = "package_name"; +const char* const shared_message_keys::kKeyDepotName = "depot_name"; +const char* const shared_message_keys::kKeyCode = "code"; +const char* const shared_message_keys::kKeyLanguageId = "language_id"; diff --git a/src/apps/haikudepot/HaikuDepotConstants.h b/src/apps/haikudepot/HaikuDepotConstants.h index 36e422d3a3..0e1e606b50 100644 --- a/src/apps/haikudepot/HaikuDepotConstants.h +++ b/src/apps/haikudepot/HaikuDepotConstants.h @@ -1,5 +1,5 @@ /* - * Copyright 2018-2025, Andrew Lindesay . + * Copyright 2018-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef HAIKU_DEPOT_CONSTANTS_H @@ -63,19 +63,20 @@ enum BitmapSize { #define REPOSITORY_NAME_SYSTEM "system" #define REPOSITORY_NAME_INSTALLED "installed" +/*! Namespace to contain keys that are used for data inside `BMessage` instances + */ +namespace shared_message_keys { -#define KEY_ALERT_TEXT "alert_text" -#define KEY_ALERT_TITLE "alert_title" -#define KEY_ALERT_TYPE "alert_type" -#define KEY_WORK_STATUS_TEXT "work_status_text" -#define KEY_WORK_STATUS_PROGRESS "work_status_progress" -#define KEY_WINDOW_SETTINGS "window_settings" -#define KEY_MAIN_SETTINGS "main_settings" -#define KEY_PACKAGE_NAME "package_name" -#define KEY_TITLE "title" -#define KEY_DESKBAR_LINK "deskbar_link" +extern const char* const kKeyPackageName; +extern const char* const kKeyDepotName; +extern const char* const kKeyCode; +extern const char* const kKeyLanguageId; + +}; // namespace shared_message_keys +#define SETTING_NICKNAME "username" + // historical difference #define SETTING_SHOW_DESKTOP_PACKAGES "show only desktop packages" #define SETTING_SHOW_NATIVE_DESKTOP_PACKAGES "show only native desktop packages" #define SETTING_SHOW_AVAILABLE_PACKAGES "show available packages" diff --git a/src/apps/haikudepot/Jamfile b/src/apps/haikudepot/Jamfile index 169d1ea2de..be587d95bf 100644 --- a/src/apps/haikudepot/Jamfile +++ b/src/apps/haikudepot/Jamfile @@ -125,6 +125,7 @@ local applicationSources = FeaturedPackagesView.cpp FilterView.cpp GeneralContentScrollView.cpp + HaikuDepotConstants.cpp IdentityAndAccessUtils.cpp IncrementViewCounterProcess.cpp JobStateListener.cpp @@ -152,6 +153,7 @@ local applicationSources = ScrollableGroupView.cpp SettingsWindow.cpp SharedIcons.cpp + SimpleAlert.cpp ShuttingDownWindow.cpp ToLatestUserUsageConditionsWindow.cpp UserCredentials.cpp diff --git a/src/apps/haikudepot/model/AccessToken.cpp b/src/apps/haikudepot/model/AccessToken.cpp index c6eb3aab67..9335a60aab 100644 --- a/src/apps/haikudepot/model/AccessToken.cpp +++ b/src/apps/haikudepot/model/AccessToken.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023, Andrew Lindesay . + * Copyright 2023-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "AccessToken.h" @@ -9,8 +9,8 @@ // These are keys that are used to store this object's data into a BMessage instance. -#define KEY_TOKEN "token" -#define KEY_EXPIRY_TIMESTAMP "expiryTimestamp" +static const char* const kKeyToken = "token"; +static const char* const kKeyExpiryLanguage = "expiry_language"; AccessToken::AccessToken(BMessage* from) @@ -18,14 +18,12 @@ AccessToken::AccessToken(BMessage* from) fToken(""), fExpiryTimestamp(0) { - if (from->FindString(KEY_TOKEN, &fToken) != B_OK) { - HDERROR("expected key [%s] in the message data when creating an access" - " token", KEY_TOKEN); - } + if (from->FindString(kKeyToken, &fToken) != B_OK) + HDERROR("expected key [%s] in the message data when creating an access token", kKeyToken); - if (from->FindUInt64(KEY_EXPIRY_TIMESTAMP, &fExpiryTimestamp) != B_OK) { - HDERROR("expected key [%s] in the message data when creating an access" - " token", KEY_EXPIRY_TIMESTAMP); + if (from->FindUInt64(kKeyExpiryLanguage, &fExpiryTimestamp) != B_OK) { + HDERROR("expected key [%s] in the message data when creating an access token", + kKeyExpiryLanguage); } } @@ -127,8 +125,8 @@ AccessToken::Archive(BMessage* into, bool deep) const if (result == B_OK && into == NULL) result = B_ERROR; if (result == B_OK) - result = into->AddString(KEY_TOKEN, fToken); + result = into->AddString(kKeyToken, fToken); if (result == B_OK) - result = into->AddUInt64(KEY_EXPIRY_TIMESTAMP, fExpiryTimestamp); + result = into->AddUInt64(kKeyExpiryLanguage, fExpiryTimestamp); return result; } \ No newline at end of file diff --git a/src/apps/haikudepot/model/Captcha.cpp b/src/apps/haikudepot/model/Captcha.cpp index 1e6f648a3f..887468d381 100644 --- a/src/apps/haikudepot/model/Captcha.cpp +++ b/src/apps/haikudepot/model/Captcha.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020, Andrew Lindesay . + * Copyright 2019-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "Captcha.h" @@ -11,8 +11,8 @@ // These are keys that are used to store this object's data into a BMessage // instance. -#define KEY_TOKEN "token" -#define KEY_PNG_IMAGE_DATA "pngImageData" +static const char* const kKeyToken = "token"; +static const char* const kKeyPngImageData = "png_image_data"; Captcha::Captcha(BMessage* from) @@ -20,16 +20,14 @@ Captcha::Captcha(BMessage* from) fToken(""), fPngImageData(NULL) { - if (from->FindString(KEY_TOKEN, &fToken) != B_OK) { - HDERROR("expected key [%s] in the message data when creating a " - "captcha", KEY_TOKEN); - } + if (from->FindString(kKeyToken, &fToken) != B_OK) + HDERROR("expected key [%s] in the message data when creating a captcha", kKeyToken); const void* data; ssize_t len; - if (from->FindData(KEY_PNG_IMAGE_DATA, B_ANY_TYPE, &data, &len) != B_OK) - HDERROR("expected key [%s] in the message data", KEY_PNG_IMAGE_DATA); + if (from->FindData(kKeyPngImageData, B_ANY_TYPE, &data, &len) != B_OK) + HDERROR("expected key [%s] in the message data", kKeyPngImageData); else SetPngImageData(data, len); } @@ -90,10 +88,10 @@ Captcha::Archive(BMessage* into, bool deep) const if (result == B_OK && into == NULL) result = B_ERROR; if (result == B_OK) - result = into->AddString(KEY_TOKEN, fToken); + result = into->AddString(kKeyToken, fToken); if (result == B_OK && fPngImageData != NULL) { - result = into->AddData(KEY_PNG_IMAGE_DATA, B_ANY_TYPE, - fPngImageData->Buffer(), fPngImageData->BufferLength()); + result = into->AddData(kKeyPngImageData, B_ANY_TYPE, fPngImageData->Buffer(), + fPngImageData->BufferLength()); } return result; } \ No newline at end of file diff --git a/src/apps/haikudepot/model/CreateUserDetail.cpp b/src/apps/haikudepot/model/CreateUserDetail.cpp index c8d1e42b5e..cb3917d704 100644 --- a/src/apps/haikudepot/model/CreateUserDetail.cpp +++ b/src/apps/haikudepot/model/CreateUserDetail.cpp @@ -1,33 +1,32 @@ /* - * Copyright 2019-2024, Andrew Lindesay . + * Copyright 2019-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ - #include "CreateUserDetail.h" +#include "CreateUserDetail.h" - // These are keys that are used to store this object's data into a BMessage - // instance. +// These are keys that are used to store this object's data into a BMessage +// instance. -#define KEY_NICKNAME "nickname" -#define KEY_PASSWORD_CLEAR "passwordClear" -#define KEY_IS_PASSWORD_REPEATED "isPasswordRepeated" -#define KEY_EMAIL "email" -#define KEY_CAPTCHA_TOKEN "captchaToken" -#define KEY_CAPTCHA_RESPONSE "captchaResponse" -#define KEY_LANGUAGE_ID "languageId" -#define KEY_AGREED_USER_USAGE_CONDITIONS_CODE "agreedUserUsageConditionsCode" +static const char* const kKeyNickname = "nickname"; +static const char* const kKeyPasswordClear = "password_clear"; +static const char* const kKeyIsPasswordRepeated = "is_password_repeated"; +static const char* const kKeyEmail = "email"; +static const char* const kKeyCaptchaToken = "captcha_token"; +static const char* const kKeyCaptchaResponse = "captcha_response"; +static const char* const kKeyLanguageId = "language_id"; +static const char* const kKeyAgreedUserUsageConditionsCode = "agreed_user_usage_conditions_code"; CreateUserDetail::CreateUserDetail(BMessage* from) { - from->FindString(KEY_NICKNAME, &fNickname); - from->FindString(KEY_PASSWORD_CLEAR, &fPasswordClear); - from->FindBool(KEY_IS_PASSWORD_REPEATED, &fIsPasswordRepeated); - from->FindString(KEY_EMAIL, &fEmail); - from->FindString(KEY_CAPTCHA_TOKEN, &fCaptchaToken); - from->FindString(KEY_CAPTCHA_RESPONSE, &fCaptchaResponse); - from->FindString(KEY_LANGUAGE_ID, &fLanguageId); - from->FindString(KEY_AGREED_USER_USAGE_CONDITIONS_CODE, - &fAgreedUserUsageConditionsCode); + from->FindString(kKeyNickname, &fNickname); + from->FindString(kKeyPasswordClear, &fPasswordClear); + from->FindBool(kKeyIsPasswordRepeated, &fIsPasswordRepeated); + from->FindString(kKeyEmail, &fEmail); + from->FindString(kKeyCaptchaToken, &fCaptchaToken); + from->FindString(kKeyCaptchaResponse, &fCaptchaResponse); + from->FindString(kKeyLanguageId, &fLanguageId); + from->FindString(kKeyAgreedUserUsageConditionsCode, &fAgreedUserUsageConditionsCode); } @@ -160,22 +159,20 @@ CreateUserDetail::Archive(BMessage* into, bool deep) const { status_t result = B_OK; if (result == B_OK) - result = into->AddString(KEY_NICKNAME, fNickname); + result = into->AddString(kKeyNickname, fNickname); if (result == B_OK) - result = into->AddString(KEY_PASSWORD_CLEAR, fPasswordClear); + result = into->AddString(kKeyPasswordClear, fPasswordClear); if (result == B_OK) - result = into->AddBool(KEY_IS_PASSWORD_REPEATED, fIsPasswordRepeated); + result = into->AddBool(kKeyIsPasswordRepeated, fIsPasswordRepeated); if (result == B_OK) - result = into->AddString(KEY_EMAIL, fEmail); + result = into->AddString(kKeyEmail, fEmail); if (result == B_OK) - result = into->AddString(KEY_CAPTCHA_TOKEN, fCaptchaToken); + result = into->AddString(kKeyCaptchaToken, fCaptchaToken); if (result == B_OK) - result = into->AddString(KEY_CAPTCHA_RESPONSE, fCaptchaResponse); + result = into->AddString(kKeyCaptchaResponse, fCaptchaResponse); if (result == B_OK) - result = into->AddString(KEY_LANGUAGE_ID, fLanguageId); - if (result == B_OK) { - result = into->AddString(KEY_AGREED_USER_USAGE_CONDITIONS_CODE, - fAgreedUserUsageConditionsCode); - } + result = into->AddString(kKeyLanguageId, fLanguageId); + if (result == B_OK) + result = into->AddString(kKeyAgreedUserUsageConditionsCode, fAgreedUserUsageConditionsCode); return result; } \ No newline at end of file diff --git a/src/apps/haikudepot/model/DeskbarLink.cpp b/src/apps/haikudepot/model/DeskbarLink.cpp index 171e2fc051..5e793ab735 100644 --- a/src/apps/haikudepot/model/DeskbarLink.cpp +++ b/src/apps/haikudepot/model/DeskbarLink.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024, Haiku, Inc. All Rights Reserved. + * Copyright 2013-2026, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -19,8 +19,8 @@ #include "Logger.h" -#define kPathKey "path" -#define kLinkKey "link" +static const char* const kKeyPath = "path"; +static const char* const kKeyLink = "link"; DeskbarLink::DeskbarLink() @@ -44,17 +44,13 @@ DeskbarLink::DeskbarLink(const DeskbarLink& other) } -DeskbarLink::DeskbarLink(BMessage* from) +DeskbarLink::DeskbarLink(const BMessage* from) { - if (from->FindString(kPathKey, &fPath) != B_OK) { - HDERROR("expected key [%s] in the message data when creating a " - "captcha", kPathKey); - } + if (from->FindString(kKeyPath, &fPath) != B_OK) + HDERROR("expected key [%s] in the message data when creating a captcha", kKeyPath); - if (from->FindString(kLinkKey, &fLink) != B_OK) { - HDERROR("expected key [%s] in the message data when creating a " - "captcha", kLinkKey); - } + if (from->FindString(kKeyLink, &fLink) != B_OK) + HDERROR("expected key [%s] in the message data when creating a captcha", kKeyLink); } @@ -96,6 +92,13 @@ DeskbarLink::Title() const } +bool +DeskbarLink::IsValid() const +{ + return !fPath.IsEmpty() && !fLink.IsEmpty(); +} + + status_t DeskbarLink::Archive(BMessage* into, bool deep) const { @@ -103,9 +106,9 @@ DeskbarLink::Archive(BMessage* into, bool deep) const if (result == B_OK && into == NULL) result = B_ERROR; if (result == B_OK) - result = into->AddString(kPathKey, fPath); + result = into->AddString(kKeyPath, fPath); if (result == B_OK) - result = into->AddString(kLinkKey, fLink); + result = into->AddString(kKeyLink, fLink); return result; } diff --git a/src/apps/haikudepot/model/DeskbarLink.h b/src/apps/haikudepot/model/DeskbarLink.h index 8d9f11101c..f644a15463 100644 --- a/src/apps/haikudepot/model/DeskbarLink.h +++ b/src/apps/haikudepot/model/DeskbarLink.h @@ -24,7 +24,7 @@ public: DeskbarLink(const BString& path, const BString& link); DeskbarLink(const DeskbarLink& other); - DeskbarLink(BMessage* from); + DeskbarLink(const BMessage* from); virtual ~DeskbarLink(); @@ -36,6 +36,8 @@ public: bool operator!=(const DeskbarLink& other); DeskbarLink& operator=(const DeskbarLink& other); + bool IsValid() const; + status_t Archive(BMessage* into, bool deep = true) const; private: diff --git a/src/apps/haikudepot/model/Model.cpp b/src/apps/haikudepot/model/Model.cpp index a74c2bc734..06fdbb68f0 100644 --- a/src/apps/haikudepot/model/Model.cpp +++ b/src/apps/haikudepot/model/Model.cpp @@ -1,7 +1,7 @@ /* * Copyright 2013-2014, Stephan Aßmus . * Copyright 2014, Axel Dörfler . - * Copyright 2016-2025, Andrew Lindesay . + * Copyright 2016-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "Model.h" @@ -235,48 +235,6 @@ Model::AddPackageListener(const PackageInfoListenerRef& packageListener) } -/*! This method will take the event info data stored in the supplied message - and turn it back into an instance of `PackageInfoEvents`. It is done in - this way because the lookup of the packages within each `PackageInfoEvent` - has to come from the model. -*/ -status_t -Model::DearchiveInfoEvents(const BMessage* message, PackageInfoEvents& packageInfoEvents) const -{ - BAutolock locker(&fLock); - int32 i = 0; - BMessage eventMessage; - BString packageName; - uint32 changeMask; - - while (message->FindMessage(kPackageInfoEventsKey, i, &eventMessage) == B_OK) { - status_t result = B_OK; - - if (result == B_OK) - result = eventMessage.FindString(kPackageInfoPackageNameKey, &packageName); - - if (result == B_OK) - result = eventMessage.FindUInt32(kPackageInfoChangesKey, &changeMask); - - if (result == B_OK) { - PackageInfoRef package = PackageForName(packageName); - - if (package.IsSet()) { - PackageInfoEvent event(package, changeMask); - packageInfoEvents.AddEvent(event); - } - } else { - HDFATAL("broken event info found processing events"); - // should not occur as the data assembly is entirely inside the application - } - - i++; - } - - return B_OK; -} - - const LanguageRef Model::PreferredLanguage() const { @@ -423,7 +381,7 @@ Model::AddPackage(const PackageInfoRef& package) BAutolock locker(&fLock); uint32 changeMask = _ChangeDiff(package); fPackages[package->Name()] = package; - _NotifyPackageChange(PackageInfoEvent(package, changeMask)); + _NotifyPackageChange(PackageChangeEvent(package, changeMask)); } @@ -434,12 +392,12 @@ Model::AddPackages(const std::vector& packages) return; BAutolock locker(&fLock); - PackageInfoEvents events; + PackageChangeEvents events; std::vector::const_iterator it; for (it = packages.begin(); it != packages.end(); it++) { PackageInfoRef package = *it; - events.AddEvent(PackageInfoEvent(package, _ChangeDiff(package))); + events.AddEvent(PackageChangeEvent(package, _ChangeDiff(package))); fPackages[package->Name()] = package; } @@ -454,12 +412,12 @@ Model::AddPackagesWithChange(const std::vector& packages, uint32 return; BAutolock locker(&fLock); - PackageInfoEvents events; + PackageChangeEvents events; std::vector::const_iterator it; for (it = packages.begin(); it != packages.end(); it++) { PackageInfoRef package = *it; - events.AddEvent(PackageInfoEvent(package, changeMask)); + events.AddEvent(PackageChangeEvent(package, changeMask)); fPackages[package->Name()] = package; } @@ -652,20 +610,20 @@ Model::_NotifyCategoryListChanged() void -Model::_NotifyPackageChange(const PackageInfoEvent& event) +Model::_NotifyPackageChange(const PackageChangeEvent& event) { std::vector::const_iterator it; for (it = fPackageListeners.begin(); it != fPackageListeners.end(); it++) { const PackageInfoListenerRef& listener = *it; if (listener.IsSet()) - listener->PackagesChanged(PackageInfoEvents(event)); + listener->PackagesChanged(PackageChangeEvents(event)); } } // TODO: future work to optimize how this is conveyed to the listener in one go. void -Model::_NotifyPackageChanges(const PackageInfoEvents& events) +Model::_NotifyPackageChanges(const PackageChangeEvents& events) { if (events.IsEmpty()) return; diff --git a/src/apps/haikudepot/model/Model.h b/src/apps/haikudepot/model/Model.h index 088b04c579..6864f055fe 100644 --- a/src/apps/haikudepot/model/Model.h +++ b/src/apps/haikudepot/model/Model.h @@ -95,9 +95,6 @@ public: void AddListener(const ModelListenerRef& listener); void AddPackageListener(const PackageInfoListenerRef& packageListener); - status_t DearchiveInfoEvents(const BMessage* message, - PackageInfoEvents& packageInfoEvents) const; - PackageScreenshotRepository* GetPackageScreenshotRepository(); @@ -178,8 +175,8 @@ private: void _NotifyIconsChanged(); void _NotifyAuthorizationChanged(); void _NotifyCategoryListChanged(); - void _NotifyPackageChange(const PackageInfoEvent& event); - void _NotifyPackageChanges(const PackageInfoEvents& events); + void _NotifyPackageChange(const PackageChangeEvent& event); + void _NotifyPackageChanges(const PackageChangeEvents& events); private: mutable BLocker fLock; diff --git a/src/apps/haikudepot/model/PackageInfoListener.cpp b/src/apps/haikudepot/model/PackageInfoListener.cpp index a4d5309db7..dadff632f8 100644 --- a/src/apps/haikudepot/model/PackageInfoListener.cpp +++ b/src/apps/haikudepot/model/PackageInfoListener.cpp @@ -1,31 +1,24 @@ /* * Copyright 2013-2025, Stephan Aßmus . + * Copyright 2026, Andrew Lindesay * All rights reserved. Distributed under the terms of the MIT License. */ #include "PackageInfoListener.h" #include +#include "HaikuDepotConstants.h" +#include "Logger.h" #include "PackageInfo.h" -const char* kPackageInfoChangesKey = "change"; -const char* kPackageInfoPackageNameKey = "packageName"; -const char* kPackageInfoEventsKey = "events"; +static const char* const kKeyEvents = "events"; +static const char* const kKeyChanges = "changes"; + +// #pragma mark - PackageInfoChangeEvent -// #pragma mark - PackageInfoEvent - - -PackageInfoEvent::PackageInfoEvent() - : - fPackage(), - fChanges(0) -{ -} - - -PackageInfoEvent::PackageInfoEvent(const PackageInfoRef& package, uint32 changes) +PackageInfoChangeEvent::PackageInfoChangeEvent(PackageInfoRef package, uint32 changes) : fPackage(package), fChanges(changes) @@ -33,40 +26,87 @@ PackageInfoEvent::PackageInfoEvent(const PackageInfoRef& package, uint32 changes } -PackageInfoEvent::PackageInfoEvent(const PackageInfoEvent& other) +PackageInfoChangeEvent::~PackageInfoChangeEvent() +{ +} + + +// #pragma mark - PackageChangeEvent + + +PackageChangeEvent::PackageChangeEvent() : - fPackage(other.fPackage), + fPackageName(), + fChanges(0) +{ +} + + +PackageChangeEvent::PackageChangeEvent(const BString& packageName, uint32 changes) + : + fPackageName(packageName), + fChanges(changes) +{ +} + + +PackageChangeEvent::PackageChangeEvent(const PackageInfoRef& package, uint32 changes) + : + PackageChangeEvent(package->Name(), changes) +{ +} + + +PackageChangeEvent::PackageChangeEvent(const PackageChangeEvent& other) + : + fPackageName(other.fPackageName), fChanges(other.fChanges) { } -PackageInfoEvent::~PackageInfoEvent() +PackageChangeEvent::PackageChangeEvent(const BMessage* from) +{ + if (from->FindString(shared_message_keys::kKeyPackageName, &fPackageName) != B_OK) + HDERROR("expected key [%s] in the message data", shared_message_keys::kKeyPackageName); + if (from->FindUInt32(kKeyChanges, &fChanges) != B_OK) + HDERROR("expected key [%s] in the message data", kKeyChanges); +} + + +PackageChangeEvent::~PackageChangeEvent() { } bool -PackageInfoEvent::operator==(const PackageInfoEvent& other) +PackageChangeEvent::IsValid() const +{ + return !fPackageName.IsEmpty(); +} + + +bool +PackageChangeEvent::operator==(const PackageChangeEvent& other) { if (this == &other) return true; - return fPackage == other.fPackage && fChanges == other.fChanges; + return fPackageName == other.fPackageName && fChanges == other.fChanges; } bool -PackageInfoEvent::operator!=(const PackageInfoEvent& other) +PackageChangeEvent::operator!=(const PackageChangeEvent& other) { return !(*this == other); } -PackageInfoEvent& -PackageInfoEvent::operator=(const PackageInfoEvent& other) +PackageChangeEvent& +PackageChangeEvent::operator=(const PackageChangeEvent& other) { if (this != &other) { - fPackage = other.fPackage; + fPackageName = other.fPackageName; fChanges = other.fChanges; } @@ -75,78 +115,98 @@ PackageInfoEvent::operator=(const PackageInfoEvent& other) status_t -PackageInfoEvent::Archive(BMessage* into, bool deep) const +PackageChangeEvent::Archive(BMessage* into, bool deep) const { status_t result = B_OK; + if (result == B_OK && into == NULL) + result = B_ERROR; if (result == B_OK) - result = into->AddUInt32(kPackageInfoChangesKey, fChanges); + result = into->AddUInt32(kKeyChanges, fChanges); if (result == B_OK) - result = into->AddString(kPackageInfoPackageNameKey, fPackage->Name()); + result = into->AddString(shared_message_keys::kKeyPackageName, fPackageName); return result; } -// #pragma mark - PackageInfoEvents +// #pragma mark - PackageChangeEvents -PackageInfoEvents::PackageInfoEvents() +PackageChangeEvents::PackageChangeEvents() { } -PackageInfoEvents::PackageInfoEvents(const PackageInfoEvent& event) +PackageChangeEvents::PackageChangeEvents(const PackageChangeEvent& event) { - fEvents.push_back(event); + AddEvent(event); } -PackageInfoEvents::PackageInfoEvents(const PackageInfoEvents& other) +PackageChangeEvents::PackageChangeEvents(const PackageChangeEvents& other) { for (int32 i = other.CountEvents() - 1; i >= 0; i--) - fEvents.push_back(other.EventAtIndex(i)); + AddEvent(other.EventAtIndex(i)); +} + + +PackageChangeEvents::PackageChangeEvents(const BMessage* from) +{ + int32 i = 0; + BMessage eventMessage; + + while (from->FindMessage(kKeyEvents, i, &eventMessage) == B_OK) { + PackageChangeEvent event = PackageChangeEvent(&eventMessage); + + if (event.IsValid()) + AddEvent(event); + else + HDERROR("unable to deserialize package info event"); + + i++; + } } void -PackageInfoEvents::AddEvent(const PackageInfoEvent event) +PackageChangeEvents::AddEvent(const PackageChangeEvent event) { fEvents.push_back(event); } bool -PackageInfoEvents::IsEmpty() const +PackageChangeEvents::IsEmpty() const { return fEvents.empty(); } int32 -PackageInfoEvents::CountEvents() const +PackageChangeEvents::CountEvents() const { return fEvents.size(); } -const PackageInfoEvent& -PackageInfoEvents::EventAtIndex(int32 index) const +const PackageChangeEvent& +PackageChangeEvents::EventAtIndex(int32 index) const { return fEvents[index]; } status_t -PackageInfoEvents::Archive(BMessage* into, bool deep) const +PackageChangeEvents::Archive(BMessage* into, bool deep) const { status_t result = B_OK; BString indexString; - std::vector::const_iterator it; + std::vector::const_iterator it; for (it = fEvents.begin(); it != fEvents.end(); it++) { BMessage eventMessage; result = (*it).Archive(&eventMessage); if (result == B_OK) - result = into->AddMessage(kPackageInfoEventsKey, &eventMessage); + result = into->AddMessage(kKeyEvents, &eventMessage); } return result; diff --git a/src/apps/haikudepot/model/PackageInfoListener.h b/src/apps/haikudepot/model/PackageInfoListener.h index 8b7cff6306..c91b4ab5fa 100644 --- a/src/apps/haikudepot/model/PackageInfoListener.h +++ b/src/apps/haikudepot/model/PackageInfoListener.h @@ -1,6 +1,6 @@ /* * Copyright 2013, Stephan Aßmus . - * Copyright 2022-2025, Andrew Lindesay . + * Copyright 2022-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef PACKAGE_INFO_LISTENER_H @@ -14,11 +14,6 @@ #include -extern const char* kPackageInfoChangesKey; -extern const char* kPackageInfoPackageNameKey; -extern const char* kPackageInfoEventsKey; - - enum { PKG_CHANGED_LOCALIZED_TEXT = 1 << 0, // ^ Covers title, summary, description and changelog. @@ -37,58 +32,93 @@ class PackageInfo; typedef BReference PackageInfoRef; -class PackageInfoEvent : public BArchivable { +/*! PackageInfoChangeEvent is akin to the PackageChangeEvent but couples a + change-mask together with the actual PackageInfo class rather than just the + name. +*/ +class PackageInfoChangeEvent { + public: - PackageInfoEvent(); - PackageInfoEvent(const PackageInfoRef& package, uint32 changes); - PackageInfoEvent(const PackageInfoEvent& other); - virtual ~PackageInfoEvent(); + PackageInfoChangeEvent(PackageInfoRef package, uint32 change); + virtual ~PackageInfoChangeEvent(); - bool operator==(const PackageInfoEvent& other); - bool operator!=(const PackageInfoEvent& other); - PackageInfoEvent& operator=(const PackageInfoEvent& other); - - inline const PackageInfoRef& - Package() const + const PackageInfoRef Package() const { return fPackage; } - - inline uint32 Changes() const + uint32 Changes() const { return fChanges; } - status_t Archive(BMessage* into, bool deep = true) const; - private: PackageInfoRef fPackage; uint32 fChanges; }; -class PackageInfoEvents : public BArchivable { +/*! Couples together the name of a package together with a mask which describes + the change that has occurred against that package. +*/ +class PackageChangeEvent : public BArchivable +{ public: - PackageInfoEvents(); - PackageInfoEvents(const PackageInfoEvent& event); - PackageInfoEvents(const PackageInfoEvents& other); + PackageChangeEvent(); + PackageChangeEvent(const PackageInfoRef& package, uint32 changes); + PackageChangeEvent(const BString& packageName, uint32 changes); + PackageChangeEvent(const PackageChangeEvent& other); + PackageChangeEvent(const BMessage* from); + virtual ~PackageChangeEvent(); + + bool operator==(const PackageChangeEvent& other); + bool operator!=(const PackageChangeEvent& other); + PackageChangeEvent& operator=(const PackageChangeEvent& other); + + inline const BString& PackageName() const + { return fPackageName; } + + inline uint32 Changes() const + { return fChanges; } + + bool IsValid() const; + + status_t Archive(BMessage* into, bool deep = true) const; + +private: + BString fPackageName; + uint32 fChanges; +}; + + +/*! This is a collection class designed to carry a number of `PackageChangeEvent` + instances. It can conveniently serialize and deserialize to and from a + `BMessage`. +*/ +class PackageChangeEvents : public BArchivable +{ +public: + PackageChangeEvents(); + PackageChangeEvents(const PackageChangeEvent& event); + PackageChangeEvents(const PackageChangeEvents& other); + PackageChangeEvents(const BMessage* from); bool IsEmpty() const; - void AddEvent(const PackageInfoEvent event); + void AddEvent(const PackageChangeEvent event); int32 CountEvents() const; - const PackageInfoEvent& + const PackageChangeEvent& EventAtIndex(int32 index) const; status_t Archive(BMessage* into, bool deep = true) const; private: - std::vector + std::vector fEvents; }; -class PackageInfoListener : public BReferenceable { +class PackageInfoListener : public BReferenceable +{ public: PackageInfoListener(); virtual ~PackageInfoListener(); - virtual void PackagesChanged(const PackageInfoEvents& events) = 0; + virtual void PackagesChanged(const PackageChangeEvents& events) = 0; }; diff --git a/src/apps/haikudepot/model/ScreenshotCoordinate.cpp b/src/apps/haikudepot/model/ScreenshotCoordinate.cpp index d45beb10a5..ad055e2cc7 100644 --- a/src/apps/haikudepot/model/ScreenshotCoordinate.cpp +++ b/src/apps/haikudepot/model/ScreenshotCoordinate.cpp @@ -1,13 +1,16 @@ /* - * Copyright 2024, Andrew Lindesay . + * Copyright 2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "ScreenshotCoordinate.h" -static const char* kCodeKey = "code"; -static const char* kWidthKey = "width"; -static const char* kHeightKey = "height"; +#include "Logger.h" + + +static const char* const kKeyCode = "code"; +static const char* const kKeyWidth = "width"; +static const char* const kKeyHeight = "height"; ScreenshotCoordinate::ScreenshotCoordinate() @@ -21,9 +24,12 @@ ScreenshotCoordinate::ScreenshotCoordinate() ScreenshotCoordinate::ScreenshotCoordinate(const BMessage* from) { - from->FindString(kCodeKey, &fCode); - from->FindUInt32(kWidthKey, &fWidth); - from->FindUInt32(kHeightKey, &fHeight); + if (from->FindString(kKeyCode, &fCode) != B_OK) + HDERROR("expected key [%s] in the message data", kKeyCode); + if (from->FindUInt32(kKeyWidth, &fWidth) != B_OK) + HDERROR("expected key [%s] in the message data", kKeyWidth); + if (from->FindUInt32(kKeyHeight, &fHeight) != B_OK) + HDERROR("expected key [%s] in the message data", kKeyHeight); } @@ -97,10 +103,10 @@ ScreenshotCoordinate::Archive(BMessage* into, bool deep) const { status_t result = B_OK; if (result == B_OK) - result = into->AddString(kCodeKey, fCode); + result = into->AddString(kKeyCode, fCode); if (result == B_OK) - result = into->AddUInt32(kWidthKey, fWidth); + result = into->AddUInt32(kKeyWidth, fWidth); if (result == B_OK) - result = into->AddUInt32(kHeightKey, fHeight); + result = into->AddUInt32(kKeyHeight, fHeight); return result; } diff --git a/src/apps/haikudepot/model/SimpleAlert.cpp b/src/apps/haikudepot/model/SimpleAlert.cpp new file mode 100644 index 0000000000..d17b966080 --- /dev/null +++ b/src/apps/haikudepot/model/SimpleAlert.cpp @@ -0,0 +1,102 @@ +/* + * Copyright 2026, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ +#include "SimpleAlert.h" + +#include + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "SimpleAlert" + + +static const char* const kKeyAlertText = "text"; +static const char* const kKeyAlertTitle = "title"; +static const char* const kKeyAlertType = "type"; + + +SimpleAlert::SimpleAlert() + : + fTitle(B_TRANSLATE("Error")), + fText("?"), + fType(B_INFO_ALERT) +{ +} + + +SimpleAlert::SimpleAlert(const BMessage* from) +{ + if (from->FindString(kKeyAlertTitle, &fTitle) != B_OK) + fTitle = B_TRANSLATE("Error"); + + if (from->FindString(kKeyAlertText, &fText) != B_OK) + fText = "?"; + + uint32 typeInt; + + if (from->FindUInt32(kKeyAlertType, &typeInt) == B_OK) + fType = static_cast(typeInt); + else + fType = B_INFO_ALERT; +} + + +SimpleAlert::SimpleAlert(const BString& title, const BString& text, alert_type type) + : + fTitle(title), + fText(text), + fType(type) +{ + if (fTitle.IsEmpty()) + fTitle = B_TRANSLATE("Error"); + if (fText.IsEmpty()) + fText = "?"; +} + + +SimpleAlert::~SimpleAlert() +{ +} + + +const BString +SimpleAlert::Title() const +{ + return fTitle; +} + + +const BString +SimpleAlert::Text() const +{ + return fText; +} + + +alert_type +SimpleAlert::Type() const +{ + return fType; +} + + +bool +SimpleAlert::operator==(const SimpleAlert& other) const +{ + return fTitle == other.fTitle && fText == other.fText && fType == other.fType; +} + + +status_t +SimpleAlert::Archive(BMessage* into, bool deep) const +{ + status_t result = B_OK; + if (result == B_OK) + result = into->AddString(kKeyAlertTitle, fTitle); + if (result == B_OK) + result = into->AddString(kKeyAlertText, fText); + if (result == B_OK) + result = into->AddUInt32(kKeyAlertType, static_cast(fType)); + return result; +} diff --git a/src/apps/haikudepot/model/SimpleAlert.h b/src/apps/haikudepot/model/SimpleAlert.h new file mode 100644 index 0000000000..6f3857e429 --- /dev/null +++ b/src/apps/haikudepot/model/SimpleAlert.h @@ -0,0 +1,41 @@ +/* + * Copyright 2026, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef SIMPLE_ALERT_H +#define SIMPLE_ALERT_H + + +#include +#include +#include + + +/*! A model for conveying a simple alert. This can be passed from background + processes to the application for display in the UI. +*/ + +class SimpleAlert : public BArchivable { +public: + SimpleAlert(const BMessage* from); + SimpleAlert(const BString& title, const BString& text, + alert_type type = B_INFO_ALERT); + SimpleAlert(); + virtual ~SimpleAlert(); + + const BString Title() const; + const BString Text() const; + alert_type Type() const; + + bool operator==(const SimpleAlert& other) const; + + status_t Archive(BMessage* into, bool deep = true) const; + +private: + BString fTitle; + BString fText; + alert_type fType; +}; + + +#endif // SIMPLE_ALERT_H diff --git a/src/apps/haikudepot/model/UserCredentials.cpp b/src/apps/haikudepot/model/UserCredentials.cpp index 202b299cb3..1a56fe6c63 100644 --- a/src/apps/haikudepot/model/UserCredentials.cpp +++ b/src/apps/haikudepot/model/UserCredentials.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019, Andrew Lindesay . + * Copyright 2019-2026, Andrew Lindesay . * * All rights reserved. Distributed under the terms of the MIT License. */ @@ -9,16 +9,16 @@ // These are keys that are used to store this object's data into a BMessage // instance. -#define KEY_NICKNAME "nickname" -#define KEY_PASSWORD_CLEAR "passwordClear" -#define KEY_IS_SUCCESSFUL "isSuccessful" +static const char* const kKeyNickname = "nickname"; +static const char* const kKeyPasswordClear = "password_clear"; +static const char* const kKeyIsSuccessful = "is_successful"; UserCredentials::UserCredentials(BMessage* from) { - from->FindString(KEY_NICKNAME, &fNickname); - from->FindString(KEY_PASSWORD_CLEAR, &fPasswordClear); - from->FindBool(KEY_IS_SUCCESSFUL, &fIsSuccessful); + from->FindString(kKeyNickname, &fNickname); + from->FindString(kKeyPasswordClear, &fPasswordClear); + from->FindBool(kKeyIsSuccessful, &fIsSuccessful); } @@ -133,10 +133,10 @@ UserCredentials::Archive(BMessage* into, bool deep) const { status_t result = B_OK; if (result == B_OK) - result = into->AddString(KEY_NICKNAME, fNickname); + result = into->AddString(kKeyNickname, fNickname); if (result == B_OK) - result = into->AddString(KEY_PASSWORD_CLEAR, fPasswordClear); + result = into->AddString(kKeyPasswordClear, fPasswordClear); if (result == B_OK) - result = into->AddBool(KEY_IS_SUCCESSFUL, fIsSuccessful); + result = into->AddBool(kKeyIsSuccessful, fIsSuccessful); return result; } diff --git a/src/apps/haikudepot/model/UserDetail.cpp b/src/apps/haikudepot/model/UserDetail.cpp index 8b0788a13c..ef97689c8e 100644 --- a/src/apps/haikudepot/model/UserDetail.cpp +++ b/src/apps/haikudepot/model/UserDetail.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019, Andrew Lindesay . + * Copyright 2019-2026, Andrew Lindesay . * * All rights reserved. Distributed under the terms of the MIT License. */ @@ -9,18 +9,18 @@ // These are keys that are used to store this object's data into a BMessage // instance. -#define KEY_NICKNAME "nickname" -#define KEY_AGREEMENT "agreement" -#define KEY_IS_LATEST "isLatest" -#define KEY_CODE "code" -#define KEY_TIMESTAMP_AGREED "timestampAgreed" +static const char* const kKeyNickname = "nickname"; +static const char* const kKeyAgreement = "agreement"; +static const char* const kKeyIsLatest = "is_latest"; +static const char* const kKeyCode = "code"; +static const char* const kKeyTimestampAgreed = "timestamp_agreed"; UserUsageConditionsAgreement::UserUsageConditionsAgreement(BMessage* from) { - from->FindUInt64(KEY_TIMESTAMP_AGREED, &fTimestampAgreed); - from->FindString(KEY_CODE, &fCode); - from->FindBool(KEY_IS_LATEST, &fIsLatest); + from->FindUInt64(kKeyTimestampAgreed, &fTimestampAgreed); + from->FindString(kKeyCode, &fCode); + from->FindBool(kKeyIsLatest, &fIsLatest); } @@ -96,11 +96,11 @@ UserUsageConditionsAgreement::Archive(BMessage* into, bool deep) const { status_t result = B_OK; if (result == B_OK) - result = into->AddUInt64(KEY_TIMESTAMP_AGREED, fTimestampAgreed); + result = into->AddUInt64(kKeyTimestampAgreed, fTimestampAgreed); if (result == B_OK) - result = into->AddString(KEY_CODE, fCode); + result = into->AddString(kKeyCode, fCode); if (result == B_OK) - result = into->AddBool(KEY_IS_LATEST, fIsLatest); + result = into->AddBool(kKeyIsLatest, fIsLatest); return result; } @@ -108,11 +108,9 @@ UserUsageConditionsAgreement::Archive(BMessage* into, bool deep) const UserDetail::UserDetail(BMessage* from) { BMessage agreementMessage; - if (from->FindMessage(KEY_AGREEMENT, - &agreementMessage) == B_OK) { + if (from->FindMessage(kKeyAgreement, &agreementMessage) == B_OK) fAgreement = UserUsageConditionsAgreement(&agreementMessage); - } - from->FindString(KEY_NICKNAME, &fNickname); + from->FindString(kKeyNickname, &fNickname); } @@ -175,9 +173,9 @@ UserDetail::Archive(BMessage* into, bool deep) const BMessage agreementMessage; result = fAgreement.Archive(&agreementMessage, true); if (result == B_OK) - result = into->AddMessage(KEY_AGREEMENT, &agreementMessage); + result = into->AddMessage(kKeyAgreement, &agreementMessage); } if (result == B_OK) - result = into->AddString(KEY_NICKNAME, fNickname); + result = into->AddString(kKeyNickname, fNickname); return result; } diff --git a/src/apps/haikudepot/model/UserUsageConditions.cpp b/src/apps/haikudepot/model/UserUsageConditions.cpp index 1659f3eed4..3e9f21f6d9 100644 --- a/src/apps/haikudepot/model/UserUsageConditions.cpp +++ b/src/apps/haikudepot/model/UserUsageConditions.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020, Andrew Lindesay . + * Copyright 2019-2026, Andrew Lindesay . * * All rights reserved. Distributed under the terms of the MIT License. */ @@ -10,9 +10,9 @@ // These are keys that are used to store this object's data into a BMessage // instance. -#define KEY_COPY_MARKDOWN "copyMarkdown" -#define KEY_CODE "code" -#define KEY_MINIMUM_AGE "minimumAge" +static const char* const kKeyCode = "code"; +static const char* const kKeyCopyMarkdown = "copy_markdown"; +static const char* const kKeyMinimumAge = "minimum_age"; UserUsageConditions::UserUsageConditions(BMessage* from) @@ -23,14 +23,14 @@ UserUsageConditions::UserUsageConditions(BMessage* from) { int16 minimumAge; - if (from->FindInt16(KEY_MINIMUM_AGE, &minimumAge) != B_OK) - HDERROR("expected key [%s] in the message data", KEY_MINIMUM_AGE); + if (from->FindInt16(kKeyMinimumAge, &minimumAge) != B_OK) + HDERROR("expected key [%s] in the message data", kKeyMinimumAge); fMinimumAge = (uint8) minimumAge; - if (from->FindString(KEY_CODE, &fCode) != B_OK) - HDERROR("expected key [%s] in the message data", KEY_CODE); - if (from->FindString(KEY_COPY_MARKDOWN, &fCopyMarkdown) != B_OK) - HDERROR("expected key [%s] in the message data", KEY_COPY_MARKDOWN); + if (from->FindString(kKeyCode, &fCode) != B_OK) + HDERROR("expected key [%s] in the message data", kKeyCode); + if (from->FindString(kKeyCopyMarkdown, &fCopyMarkdown) != B_OK) + HDERROR("expected key [%s] in the message data", kKeyCopyMarkdown); } @@ -93,8 +93,12 @@ UserUsageConditions::SetCopyMarkdown(const BString& copyMarkdown) status_t UserUsageConditions::Archive(BMessage* into, bool deep) const { - into->AddInt16(KEY_MINIMUM_AGE, (int16) fMinimumAge); - into->AddString(KEY_CODE, fCode); - into->AddString(KEY_COPY_MARKDOWN, fCopyMarkdown); - return B_OK; + status_t result = B_OK; + if (result == B_OK) + result = into->AddInt16(kKeyMinimumAge, (int16)fMinimumAge); + if (result == B_OK) + result = into->AddString(kKeyCode, fCode); + if (result == B_OK) + result = into->AddString(kKeyCopyMarkdown, fCopyMarkdown); + return result; } \ No newline at end of file diff --git a/src/apps/haikudepot/model/ValidationFailure.cpp b/src/apps/haikudepot/model/ValidationFailure.cpp index 5f7819158b..bf49edd60a 100644 --- a/src/apps/haikudepot/model/ValidationFailure.cpp +++ b/src/apps/haikudepot/model/ValidationFailure.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019, Andrew Lindesay . + * Copyright 2019-2026, Andrew Lindesay . * * All rights reserved. Distributed under the terms of the MIT License. */ @@ -8,9 +8,9 @@ // These are keys that are used to store this object's data into a BMessage // instance. -#define KEY_PROPERTY "property" -#define KEY_PREFIX_MESSAGE "message_" -#define KEY_PREFIX_ITEM "item_" +static const char* const kKeyProperty = "property"; +static const char* const kKeyPrefixMessage = "message_"; +static const char* const kKeyPrefixItem = "item_"; // #pragma mark - Single Validation Failure @@ -18,7 +18,7 @@ ValidationFailure::ValidationFailure(BMessage* from) { - from->FindString(KEY_PROPERTY, &fProperty); + from->FindString(kKeyProperty, &fProperty); if (fProperty.IsEmpty()) debugger("illegal state; missing property in message"); @@ -28,7 +28,7 @@ ValidationFailure::ValidationFailure(BMessage* from) BString message; for (int32 i = 0; result == B_OK; i++) { - name.SetToFormat("%s%" B_PRId32, KEY_PREFIX_MESSAGE, i); + name.SetToFormat("%s%" B_PRId32, kKeyPrefixMessage, i); result = from->FindString(name, &message); if (result == B_OK) @@ -89,9 +89,9 @@ ValidationFailure::Archive(BMessage* into, bool deep) const status_t result = B_OK; BString key; if (result == B_OK) - result = into->AddString(KEY_PROPERTY, fProperty); + result = into->AddString(kKeyProperty, fProperty); for (int32 i = 0; result == B_OK && i < fMessages.CountStrings(); i++) { - key.SetToFormat("%s%" B_PRId32, KEY_PREFIX_MESSAGE, i); + key.SetToFormat("%s%" B_PRId32, kKeyPrefixMessage, i); result = into->AddString(key, fMessages.StringAt(i)); } return result; @@ -177,7 +177,7 @@ ValidationFailures::Archive(BMessage* into, bool deep) const BMessage itemMessage; result = item->Archive(&itemMessage); if (result == B_OK) { - key.SetToFormat("%s%" B_PRId32, KEY_PREFIX_ITEM, i); + key.SetToFormat("%s%" B_PRId32, kKeyPrefixItem, i); result = into->AddMessage(key, &itemMessage); } } @@ -221,7 +221,7 @@ ValidationFailures::_AddFromMessage(const BMessage* from) while (true) { BMessage itemMessage; - key.SetToFormat("%s%" B_PRId32, KEY_PREFIX_ITEM, i); + key.SetToFormat("%s%" B_PRId32, kKeyPrefixItem, i); if (from->FindMessage(key, &itemMessage) != B_OK) return; fItems.AddItem(new ValidationFailure(&itemMessage)); diff --git a/src/apps/haikudepot/packagemanagement/InstallPackageProcess.cpp b/src/apps/haikudepot/packagemanagement/InstallPackageProcess.cpp index 06ca8ee6da..2a6d932af1 100644 --- a/src/apps/haikudepot/packagemanagement/InstallPackageProcess.cpp +++ b/src/apps/haikudepot/packagemanagement/InstallPackageProcess.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2025, Haiku, Inc. All Rights Reserved. + * Copyright 2013-2026, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -181,7 +181,8 @@ InstallPackageProcess::RunInternal() BString errorString; errorString.SetToFormat("Fatal error occurred while installing package %s: %s (%s)\n", packageNameString, ex.Message().String(), ex.Details().String()); - AppUtils::NotifySimpleError(B_TRANSLATE("Fatal error"), errorString, B_STOP_ALERT); + AppUtils::NotifySimpleError( + SimpleAlert(B_TRANSLATE("Fatal error"), errorString, B_STOP_ALERT)); _SetDownloadedPackagesState(NONE); SetPackageState(fPackageName, state); return ex.Error(); diff --git a/src/apps/haikudepot/packagemanagement/OpenPackageProcess.cpp b/src/apps/haikudepot/packagemanagement/OpenPackageProcess.cpp index 1ad3414028..fa59c12006 100644 --- a/src/apps/haikudepot/packagemanagement/OpenPackageProcess.cpp +++ b/src/apps/haikudepot/packagemanagement/OpenPackageProcess.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2025, Haiku, Inc. All Rights Reserved. + * Copyright 2013-2026, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -137,6 +137,10 @@ OpenPackageProcess::RunInternal() { status_t status; BPath path; + + HDDEBUG("open package action from deskbar link [%s], path [%s]", fDeskbarLink.Link().String(), + fDeskbarLink.Path().String()); + if (fDeskbarLink.Link().FindFirst('/') == 0) { status = path.SetTo(fDeskbarLink.Link()); HDINFO("trying to launch (absolute link): %s", path.Path()); diff --git a/src/apps/haikudepot/packagemanagement/PackageAction.cpp b/src/apps/haikudepot/packagemanagement/PackageAction.cpp index 22568ce7c8..b0a6a27349 100644 --- a/src/apps/haikudepot/packagemanagement/PackageAction.cpp +++ b/src/apps/haikudepot/packagemanagement/PackageAction.cpp @@ -1,20 +1,43 @@ /* - * Copyright 2021, Andrew Lindesay . + * Copyright 2021-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ - - #include "PackageAction.h" +#include -PackageAction::PackageAction(const BString& title, const BMessage& message) +#include "HaikuDepotConstants.h" +#include "Logger.h" +#include "PackageUtils.h" + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "PackageAction" + + +static const char* const kKeyTitle = "title"; +static const char* const kKeyDeskbarLink = "deskbar_link"; + + +/*! An abstract superclass of the various sorts of package actions which can be + undertaken on a package. +*/ +PackageAction::PackageAction(const BString& title, const BString& packageName) : fTitle(title), - fMessage(message) + fPackageName(packageName) { } +PackageAction::PackageAction(const BMessage* from) +{ + if (from->FindString(kKeyTitle, &fTitle) != B_OK) + HDFATAL("expected key [%s] in message", kKeyTitle); + if (from->FindString(shared_message_keys::kKeyPackageName, &fPackageName) != B_OK) + HDFATAL("expected key [%s] in message", shared_message_keys::kKeyPackageName); +} + + PackageAction::~PackageAction() { } @@ -27,8 +50,150 @@ PackageAction::Title() const } -const BMessage& +const BString& +PackageAction::PackageName() const +{ + return fPackageName; +} + + +/*! Returns a `BMessage` which can be used in BView action to cause the action + to get executed by some UI logic. +*/ +const BMessage PackageAction::Message() const { - return fMessage; + BMessage message(MessageWhat()); + if (Archive(&message) != B_OK) + HDFATAL("unable to archive the action message."); + return message; +} + + +status_t +PackageAction::Archive(BMessage* into, bool deep) const +{ + status_t result = B_OK; + if (result == B_OK && into == NULL) + result = B_ERROR; + if (result == B_OK) + result = into->AddString(kKeyTitle, fTitle); + if (result == B_OK) + result = into->AddString(shared_message_keys::kKeyPackageName, fPackageName); + return result; +} + + +UninstallPackageAction::UninstallPackageAction(const BString& packageName, + const BString& packageTitle) + : + PackageAction("Uninstall", packageName) +{ + fTitle = B_TRANSLATE("Uninstall %PackageTitle%"); + fTitle.ReplaceAll("%PackageTitle%", packageTitle); +} + + +UninstallPackageAction::UninstallPackageAction(const BMessage* from) + : + PackageAction(from) +{ +} + + +UninstallPackageAction::~UninstallPackageAction() +{ +} + + +const uint32 +UninstallPackageAction::MessageWhat() const +{ + return MSG_PKG_UNINSTALL; +} + + +InstallPackageAction::InstallPackageAction(const BString& packageName, + const BString& packageTitle) + : + PackageAction("Install", packageName) +{ + fTitle = B_TRANSLATE("Install %PackageTitle%"); + fTitle.ReplaceAll("%PackageTitle%", packageTitle); +} + + +InstallPackageAction::InstallPackageAction(const BMessage* from) + : + PackageAction(from) +{ +} + + +InstallPackageAction::~InstallPackageAction() +{ +} + + +const uint32 +InstallPackageAction::MessageWhat() const +{ + return MSG_PKG_INSTALL; +} + + +OpenPackageAction::OpenPackageAction(const BString& packageName, const DeskbarLink& deskbarLink) + : + PackageAction("Open", packageName), + fLink(deskbarLink) +{ + fTitle = B_TRANSLATE("Open %DeskbarLink%"); + fTitle.ReplaceAll("%DeskbarLink%", deskbarLink.Title()); +} + + +OpenPackageAction::OpenPackageAction(const BMessage* from) + : + PackageAction(from) +{ + BMessage deskbarLinkMessage; + if (from->FindMessage(kKeyDeskbarLink, &deskbarLinkMessage) == B_OK) + fLink = DeskbarLink(&deskbarLinkMessage); + else + HDFATAL("missing key [%s]", kKeyDeskbarLink); +} + + +OpenPackageAction::~OpenPackageAction() +{ +} + + +const uint32 +OpenPackageAction::MessageWhat() const +{ + return MSG_PKG_OPEN; +} + + +const DeskbarLink +OpenPackageAction::Link() const +{ + return fLink; +} + + +status_t +OpenPackageAction::Archive(BMessage* into, bool deep) const +{ + status_t result = PackageAction::Archive(into, deep); + + if (result == B_OK) { + BMessage deskbarLinkMessage; + result = fLink.Archive(&deskbarLinkMessage); + if (result == B_OK) + result = into->AddMessage(kKeyDeskbarLink, &deskbarLinkMessage); + } + + return result; } diff --git a/src/apps/haikudepot/packagemanagement/PackageAction.h b/src/apps/haikudepot/packagemanagement/PackageAction.h index cff329886f..726d2496b9 100644 --- a/src/apps/haikudepot/packagemanagement/PackageAction.h +++ b/src/apps/haikudepot/packagemanagement/PackageAction.h @@ -1,32 +1,83 @@ /* - * Copyright 2021, Andrew Lindesay . + * Copyright 2021-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef PACKAGE_ACTION_H #define PACKAGE_ACTION_H - #include #include #include +#include "DeskbarLink.h" -class PackageAction : public BReferenceable { + +class PackageAction : public BReferenceable, public BArchivable +{ public: - PackageAction(const BString& title, - const BMessage& message); + PackageAction(const BString& title, const BString& packageName); + PackageAction(const BMessage* from); virtual ~PackageAction(); const BString& Title() const; - const BMessage& Message() const; + const BString& PackageName() const; -private: + const BMessage Message() const; + virtual const uint32 MessageWhat() const = 0; + + virtual status_t Archive(BMessage* into, bool deep = true) const; + +protected: BString fTitle; - BMessage fMessage; + BString fPackageName; }; typedef BReference PackageActionRef; +class UninstallPackageAction : public PackageAction +{ +public: + UninstallPackageAction(const BString& packageName, + const BString& packageTitle); + UninstallPackageAction(const BMessage* from); + virtual ~UninstallPackageAction(); + + virtual const uint32 MessageWhat() const; + +}; + + +class InstallPackageAction : public PackageAction +{ +public: + InstallPackageAction(const BString& packageName, + const BString& packageTitle); + InstallPackageAction(const BMessage* from); + virtual ~InstallPackageAction(); + + virtual const uint32 MessageWhat() const; +}; + + +class OpenPackageAction : public PackageAction +{ +public: + OpenPackageAction(const BString& packageName, + const DeskbarLink& link); + OpenPackageAction(const BMessage* from); + ~OpenPackageAction(); + + virtual const uint32 MessageWhat() const; + + const DeskbarLink Link() const; + + virtual status_t Archive(BMessage* into, bool deep = true) const; + +private: + DeskbarLink fLink; +}; + + #endif // PACKAGE_ACTION_H diff --git a/src/apps/haikudepot/packagemanagement/PackageManager.cpp b/src/apps/haikudepot/packagemanagement/PackageManager.cpp index 0784e97375..414ab73039 100644 --- a/src/apps/haikudepot/packagemanagement/PackageManager.cpp +++ b/src/apps/haikudepot/packagemanagement/PackageManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024, Haiku, Inc. All Rights Reserved. + * Copyright 2013-2026, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -160,8 +160,13 @@ PackageManager::CollectPackageActions(PackageInfoRef package, break; case NONE: case UNINSTALLED: - actionList.Add(_CreateInstallPackageAction(package)); + { + BString packageTitle; + PackageUtils::TitleOrName(package, packageTitle); + actionList.Add( + PackageActionRef(new InstallPackageAction(package->Name(), packageTitle), true)); break; + } case DOWNLOADING: HDINFO("no package actions for [%s] (downloading)", package->Name().String()); @@ -183,7 +188,11 @@ PackageManager::_CollectPackageActionsForActivatedOrInstalled( PackageInfoRef package, Collector& actionList) { - actionList.Add(_CreateUninstallPackageAction(package)); + BString packageTitle; + PackageUtils::TitleOrName(package, packageTitle); + + actionList.Add( + PackageActionRef(new UninstallPackageAction(package->Name(), packageTitle), true)); // Add OpenPackageActions for each deskbar link found in the // package @@ -192,63 +201,17 @@ PackageManager::_CollectPackageActionsForActivatedOrInstalled( std::vector::const_iterator it; for (it = foundLinks.begin(); it != foundLinks.end(); it++) { const DeskbarLink& aLink = *it; - actionList.Add(_CreateOpenPackageAction(package, aLink)); + if (aLink.IsValid()) { + actionList.Add( + PackageActionRef(new OpenPackageAction(package->Name(), aLink), true)); + } else { + HDERROR("broken deskbar link for [%s]", package->Name().String()); + } } } } -PackageActionRef -PackageManager::_CreateUninstallPackageAction(const PackageInfoRef& package) -{ - BString actionTitle = B_TRANSLATE("Uninstall %PackageTitle%"); - BString packageTitle; - PackageUtils::TitleOrName(package, packageTitle); - actionTitle.ReplaceAll("%PackageTitle%", packageTitle); - - BMessage message(MSG_PKG_UNINSTALL); - message.AddString(KEY_TITLE, actionTitle); - message.AddString(KEY_PACKAGE_NAME, package->Name()); - - return PackageActionRef(new PackageAction(actionTitle, message), true); -} - - -PackageActionRef -PackageManager::_CreateInstallPackageAction(const PackageInfoRef& package) -{ - BString actionTitle = B_TRANSLATE("Install %PackageTitle%"); - BString packageTitle; - PackageUtils::TitleOrName(package, packageTitle); - actionTitle.ReplaceAll("%PackageTitle%", packageTitle); - - BMessage message(MSG_PKG_INSTALL); - message.AddString(KEY_TITLE, actionTitle); - message.AddString(KEY_PACKAGE_NAME, package->Name()); - - return PackageActionRef(new PackageAction(actionTitle, message), true); -} - - -PackageActionRef -PackageManager::_CreateOpenPackageAction(const PackageInfoRef& package, const DeskbarLink& link) -{ - BString title = B_TRANSLATE("Open %DeskbarLink%"); - title.ReplaceAll("%DeskbarLink%", link.Title()); - - BMessage deskbarLinkMessage; - if (link.Archive(&deskbarLinkMessage) != B_OK) - HDFATAL("unable to archive the deskbar link"); - - BMessage message(MSG_PKG_OPEN); - message.AddString(KEY_TITLE, title); - message.AddMessage(KEY_DESKBAR_LINK, &deskbarLinkMessage); - message.AddString(KEY_PACKAGE_NAME, package->Name()); - - return PackageActionRef(new PackageAction(title, message), true); -} - - void PackageManager::SetCurrentActionPackage(PackageInfoRef package, bool install) { diff --git a/src/apps/haikudepot/packagemanagement/PackageManager.h b/src/apps/haikudepot/packagemanagement/PackageManager.h index cabe653dd9..7a149cb46b 100644 --- a/src/apps/haikudepot/packagemanagement/PackageManager.h +++ b/src/apps/haikudepot/packagemanagement/PackageManager.h @@ -3,7 +3,7 @@ * Copyright 2011, Ingo Weinhold, * Copyright 2013, Rene Gollent, * Copyright 2017, Julian Harnath . - * Copyright 2021, Andrew Lindesay . + * Copyright 2021-2026, Andrew Lindesay . * * All rights reserved. Distributed under the terms of the MIT License. */ @@ -97,13 +97,6 @@ private: InstalledRepository& repository); private: - PackageActionRef _CreateUninstallPackageAction( - const PackageInfoRef& package); - PackageActionRef _CreateInstallPackageAction( - const PackageInfoRef& package); - PackageActionRef _CreateOpenPackageAction( - const PackageInfoRef& package, - const DeskbarLink& link); void _CollectPackageActionsForActivatedOrInstalled( PackageInfoRef package, diff --git a/src/apps/haikudepot/packagemanagement/UninstallPackageProcess.cpp b/src/apps/haikudepot/packagemanagement/UninstallPackageProcess.cpp index a719562547..04f6edd2fd 100644 --- a/src/apps/haikudepot/packagemanagement/UninstallPackageProcess.cpp +++ b/src/apps/haikudepot/packagemanagement/UninstallPackageProcess.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2025, Haiku, Inc. All Rights Reserved. + * Copyright 2013-2026, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -93,7 +93,8 @@ UninstallPackageProcess::RunInternal() BString errorString; errorString.SetToFormat("Fatal error occurred while uninstalling package %s: %s (%s)\n", fPackageName.String(), ex.Message().String(), ex.Details().String()); - AppUtils::NotifySimpleError(B_TRANSLATE("Fatal error"), errorString, B_STOP_ALERT); + AppUtils::NotifySimpleError( + SimpleAlert(B_TRANSLATE("Fatal error"), errorString, B_STOP_ALERT)); SetPackageState(fPackageName, state); return ex.Error(); } catch (BAbortedByUserException& ex) { diff --git a/src/apps/haikudepot/process/ProcessCoordinator.cpp b/src/apps/haikudepot/process/ProcessCoordinator.cpp index f24bf5a5e6..7694eca433 100644 --- a/src/apps/haikudepot/process/ProcessCoordinator.cpp +++ b/src/apps/haikudepot/process/ProcessCoordinator.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022, Andrew Lindesay . + * Copyright 2018-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -22,11 +22,11 @@ // These are keys that are used to store the ProcessCoordinatorState data into // a BMessage instance. -#define KEY_PROCESS_COORDINATOR_IDENTIFIER "processCoordinatorIdentifier" -#define KEY_PROGRESS "progress" -#define KEY_MESSAGE "message" -#define KEY_IS_RUNNING "isRunning" -#define KEY_ERROR_STATUS "errorStatus" +static const char* const kKeyIdentifier = "identifier"; +static const char* const kKeyProgress = "progress"; +static const char* const kKeyMessage = "message"; +static const char* const kKeyIsRunning = "is_running"; +static const char* const kKeyErrorStatus = "error_status"; // #pragma mark - ProcessCoordinatorState implementation @@ -34,28 +34,18 @@ ProcessCoordinatorState::ProcessCoordinatorState(BMessage* from) { - if (from->FindString(KEY_PROCESS_COORDINATOR_IDENTIFIER, - &fProcessCoordinatorIdentifier) != B_OK) { - HDFATAL("unable to find the key [%s]", - KEY_PROCESS_COORDINATOR_IDENTIFIER); - } - - if (from->FindFloat(KEY_PROGRESS, &fProgress) != B_OK) { - HDFATAL("unable to find the key [%s]", KEY_PROGRESS); - } - - if (from->FindString(KEY_MESSAGE, &fMessage) != B_OK) { - HDFATAL("unable to find the key [%s]", KEY_MESSAGE); - } - - if (from->FindBool(KEY_IS_RUNNING, &fIsRunning) != B_OK) { - HDFATAL("unable to find the key [%s]", KEY_IS_RUNNING); - } + if (from->FindString(kKeyIdentifier, &fProcessCoordinatorIdentifier) != B_OK) + HDFATAL("unable to find the key [%s]", kKeyIdentifier); + if (from->FindFloat(kKeyProgress, &fProgress) != B_OK) + HDFATAL("unable to find the key [%s]", kKeyProgress); + if (from->FindString(kKeyMessage, &fMessage) != B_OK) + HDFATAL("unable to find the key [%s]", kKeyMessage); + if (from->FindBool(kKeyIsRunning, &fIsRunning) != B_OK) + HDFATAL("unable to find the key [%s]", kKeyIsRunning); int64 errorStatusNumeric; - if (from->FindInt64(KEY_ERROR_STATUS, &errorStatusNumeric) != B_OK) { - HDFATAL("unable to find the key [%s]", KEY_ERROR_STATUS); - } + if (from->FindInt64(kKeyErrorStatus, &errorStatusNumeric) != B_OK) + HDFATAL("unable to find the key [%s]", kKeyErrorStatus); fErrorStatus = static_cast(errorStatusNumeric); } @@ -117,18 +107,16 @@ status_t ProcessCoordinatorState::Archive(BMessage* into, bool deep) const { status_t result = B_OK; - if (result == B_OK) { - result = into->AddString(KEY_PROCESS_COORDINATOR_IDENTIFIER, - fProcessCoordinatorIdentifier); - } if (result == B_OK) - result = into->AddFloat(KEY_PROGRESS, fProgress); + result = into->AddString(kKeyIdentifier, fProcessCoordinatorIdentifier); if (result == B_OK) - result = into->AddString(KEY_MESSAGE, fMessage); + result = into->AddFloat(kKeyProgress, fProgress); if (result == B_OK) - result = into->AddBool(KEY_IS_RUNNING, fIsRunning); + result = into->AddString(kKeyMessage, fMessage); if (result == B_OK) - result = into->AddInt64(KEY_ERROR_STATUS, static_cast(fErrorStatus)); + result = into->AddBool(kKeyIsRunning, fIsRunning); + if (result == B_OK) + result = into->AddInt64(kKeyErrorStatus, static_cast(fErrorStatus)); return result; } diff --git a/src/apps/haikudepot/process/ProcessCoordinatorFactory.cpp b/src/apps/haikudepot/process/ProcessCoordinatorFactory.cpp index daa18c5a45..ce7315b273 100644 --- a/src/apps/haikudepot/process/ProcessCoordinatorFactory.cpp +++ b/src/apps/haikudepot/process/ProcessCoordinatorFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2018-2025, Andrew Lindesay . + * Copyright 2018-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "ProcessCoordinatorFactory.h" @@ -136,22 +136,6 @@ ProcessCoordinatorFactory::CreateBulkLoadCoordinator(Model* model, bool forceLoc } -/*static*/ ProcessCoordinator* -ProcessCoordinatorFactory::CreatePackageActionCoordinator(Model* model, BMessage* message) -{ - switch (message->what) { - case MSG_PKG_INSTALL: - return _CreateInstallPackageActionCoordinator(model, message); - case MSG_PKG_UNINSTALL: - return _CreateUninstallPackageActionCoordinator(model, message); - case MSG_PKG_OPEN: - return _CreateOpenPackageActionCoordinator(model, message); - default: - HDFATAL("unexpected package action message what"); - } -} - - /*static*/ ProcessCoordinator* ProcessCoordinatorFactory::CacheScreenshotCoordinator(Model* model, ScreenshotCoordinate& screenshotCoordinate) @@ -178,64 +162,41 @@ ProcessCoordinatorFactory::PopulatePkgUserRatingsCoordinator(Model* model, } -/*static*/ BString -ProcessCoordinatorFactory::_ExtractPackageNameFromMessage(BMessage* message) -{ - BString pkgName; - if (message->FindString(KEY_PACKAGE_NAME, &pkgName) != B_OK) - HDFATAL("malformed message missing key [%s]", KEY_PACKAGE_NAME); - return pkgName; -} - - /*static*/ ProcessCoordinator* -ProcessCoordinatorFactory::_CreateInstallPackageActionCoordinator(Model* model, BMessage* message) +ProcessCoordinatorFactory::CreateInstallPackageActionCoordinator(Model* model, + const InstallPackageAction& action) { ProcessCoordinator* processCoordinator = new ProcessCoordinator("InstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); - - AbstractProcessNode* processNode = new ThreadedProcessNode( - new InstallPackageProcess(_ExtractPackageNameFromMessage(message), model), 10); - + AbstractProcessNode* processNode + = new ThreadedProcessNode(new InstallPackageProcess(action.PackageName(), model), 10); processCoordinator->AddNode(processNode); - return processCoordinator; } /*static*/ ProcessCoordinator* -ProcessCoordinatorFactory::_CreateUninstallPackageActionCoordinator(Model* model, BMessage* message) +ProcessCoordinatorFactory::CreateUninstallPackageActionCoordinator(Model* model, + const UninstallPackageAction& action) { ProcessCoordinator* processCoordinator = new ProcessCoordinator("UninstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); - - AbstractProcessNode* processNode = new ThreadedProcessNode( - new UninstallPackageProcess(_ExtractPackageNameFromMessage(message), model), 10); - + AbstractProcessNode* processNode + = new ThreadedProcessNode(new UninstallPackageProcess(action.PackageName(), model), 10); processCoordinator->AddNode(processNode); - return processCoordinator; } /*static*/ ProcessCoordinator* -ProcessCoordinatorFactory::_CreateOpenPackageActionCoordinator(Model* model, BMessage* message) +ProcessCoordinatorFactory::CreateOpenPackageActionCoordinator(Model* model, + const OpenPackageAction& action) { ProcessCoordinator* processCoordinator = new ProcessCoordinator("OpenPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); - - BMessage deskbarLinkMessage; - - if (message->FindMessage(KEY_DESKBAR_LINK, &deskbarLinkMessage) != B_OK) - HDFATAL("malformed message missing key [%s]", KEY_DESKBAR_LINK); - - DeskbarLink deskbarLink(&deskbarLinkMessage); - AbstractProcessNode* processNode = new ThreadedProcessNode( - new OpenPackageProcess(_ExtractPackageNameFromMessage(message), model, deskbarLink)); - + new OpenPackageProcess(action.PackageName(), model, action.Link())); processCoordinator->AddNode(processNode); - return processCoordinator; } diff --git a/src/apps/haikudepot/process/ProcessCoordinatorFactory.h b/src/apps/haikudepot/process/ProcessCoordinatorFactory.h index f6060034f9..a6b16aec29 100644 --- a/src/apps/haikudepot/process/ProcessCoordinatorFactory.h +++ b/src/apps/haikudepot/process/ProcessCoordinatorFactory.h @@ -8,6 +8,7 @@ #include #include "AbstractProcess.h" +#include "PackageAction.h" #include "PackageInfo.h" #include "PackageScreenshotRepository.h" @@ -32,9 +33,6 @@ public: UserDetailVerifierListener* userDetailVerifierListener, Model* model); - static ProcessCoordinator* CreatePackageActionCoordinator( - Model* model, BMessage* message); - static ProcessCoordinator* CacheScreenshotCoordinator( Model* model, ScreenshotCoordinate& screenshotCoordinate); @@ -44,20 +42,18 @@ public: static ProcessCoordinator* PopulatePkgUserRatingsCoordinator(Model* model, const BString& packageName); + static ProcessCoordinator* CreateInstallPackageActionCoordinator(Model* model, + const InstallPackageAction& action); + + static ProcessCoordinator* CreateUninstallPackageActionCoordinator(Model* model, + const UninstallPackageAction& action); + + static ProcessCoordinator* CreateOpenPackageActionCoordinator(Model* model, + const OpenPackageAction& action); + private: static uint32 _CalculateServerProcessOptions(); - static BString _ExtractPackageNameFromMessage(BMessage* message); - - static ProcessCoordinator* _CreateInstallPackageActionCoordinator( - Model* model, BMessage* message); - - static ProcessCoordinator* _CreateUninstallPackageActionCoordinator( - Model* model, BMessage* message); - - static ProcessCoordinator* _CreateOpenPackageActionCoordinator( - Model* model, BMessage* message); - static ProcessCoordinator* _CreateSingleProcessCoordinator(const char* name, AbstractProcess *process); diff --git a/src/apps/haikudepot/server/LocalPkgDataLoadProcess.cpp b/src/apps/haikudepot/server/LocalPkgDataLoadProcess.cpp index eb9a4129a2..fb0b49872e 100644 --- a/src/apps/haikudepot/server/LocalPkgDataLoadProcess.cpp +++ b/src/apps/haikudepot/server/LocalPkgDataLoadProcess.cpp @@ -741,7 +741,8 @@ LocalPkgDataLoadProcessUtils::_PopulateModel(LocalPkgDataLoadProcessUtilsData& d LocalPkgDataLoadProcessUtils::_NotifyError(const BString& messageText) { HDERROR("an error has arisen loading data of packages from local : %s", messageText.String()); - AppUtils::NotifySimpleError(B_TRANSLATE("Local repository load error"), messageText); + AppUtils::NotifySimpleError( + SimpleAlert(B_TRANSLATE("Local repository load error"), messageText)); } diff --git a/src/apps/haikudepot/server/LocalRepositoryUpdateProcess.cpp b/src/apps/haikudepot/server/LocalRepositoryUpdateProcess.cpp index 201d5e1431..14c75d2130 100644 --- a/src/apps/haikudepot/server/LocalRepositoryUpdateProcess.cpp +++ b/src/apps/haikudepot/server/LocalRepositoryUpdateProcess.cpp @@ -181,7 +181,5 @@ LocalRepositoryUpdateProcess::_NotifyError(const BString& error, alertText.Append(")"); } - AppUtils::NotifySimpleError( - B_TRANSLATE("Repository update error"), - alertText); + AppUtils::NotifySimpleError(SimpleAlert(B_TRANSLATE("Repository update error"), alertText)); } diff --git a/src/apps/haikudepot/server/ServerHelper.cpp b/src/apps/haikudepot/server/ServerHelper.cpp index 59c1472aa8..bb75cbd5ba 100644 --- a/src/apps/haikudepot/server/ServerHelper.cpp +++ b/src/apps/haikudepot/server/ServerHelper.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2017-2025, Andrew Lindesay . + * Copyright 2017-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -24,8 +24,12 @@ #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "ServerHelper" -#define KEY_MSG_MINIMUM_VERSION "minimumVersion" -#define KEY_HEADER_MINIMUM_VERSION "X-Desktop-Application-Minimum-Version" +static const char* const kKeyMinimumVersion = "minimum_version"; + +/*! This is an HTTP header that the sever will send back to the client to inform + it about a version limit. +*/ +static const char* const kKeyHeaderMinimumVersion = "X-Desktop-Application-Minimum-Version"; /*! \brief This method will cause an alert to be shown to the user regarding a @@ -165,11 +169,11 @@ ServerHelper::NotifyClientTooOld(const BHttpHeaders& responseHeaders) if (!ServerSettings::IsClientTooOld()) { ServerSettings::SetClientTooOld(); - const char* minimumVersionC = responseHeaders[KEY_HEADER_MINIMUM_VERSION]; + const char* minimumVersionC = responseHeaders[kKeyHeaderMinimumVersion]; BMessage message(MSG_CLIENT_TOO_OLD); if (minimumVersionC != NULL && strlen(minimumVersionC) != 0) { - message.AddString(KEY_MSG_MINIMUM_VERSION, minimumVersionC); + message.AddString(kKeyMinimumVersion, minimumVersionC); } be_app->PostMessage(&message); @@ -183,7 +187,7 @@ ServerHelper::AlertClientTooOld(BMessage* message) BString minimumVersion; BString alertText; - if (message->FindString(KEY_MSG_MINIMUM_VERSION, &minimumVersion) != B_OK) + if (message->FindString(kKeyMinimumVersion, &minimumVersion) != B_OK) minimumVersion = "???"; alertText.SetToFormat( diff --git a/src/apps/haikudepot/ui/App.cpp b/src/apps/haikudepot/ui/App.cpp index 5286b9712a..81b03d8bb1 100644 --- a/src/apps/haikudepot/ui/App.cpp +++ b/src/apps/haikudepot/ui/App.cpp @@ -1,6 +1,6 @@ /* * Copyright 2013, Stephan Aßmus . - * Copyright 2017-2025, Andrew Lindesay . + * Copyright 2017-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -38,6 +38,9 @@ #define B_TRANSLATION_CONTEXT "App" +static const char* const kKeyMainSettings = "main_settings"; + + App::App() : BApplication("application/x-vnd.Haiku-HaikuDepot"), @@ -109,7 +112,7 @@ App::MessageReceived(BMessage* message) case MSG_MAIN_WINDOW_CLOSED: { BMessage windowSettings; - if (message->FindMessage(KEY_WINDOW_SETTINGS, &windowSettings) == B_OK) + if (message->FindMessage(main_window_keys::kKeyWindowSettings, &windowSettings) == B_OK) _StoreSettings(windowSettings); fWindowCount--; @@ -325,22 +328,9 @@ App::ArgvReceived(int32 argc, char* argv[]) void App::_AlertSimpleError(BMessage* message) { - BString alertTitle; - BString alertText; - int32 typeInt; - - if (message->FindString(KEY_ALERT_TEXT, &alertText) != B_OK) - alertText = "?"; - - if (message->FindString(KEY_ALERT_TITLE, &alertTitle) != B_OK) - alertTitle = B_TRANSLATE("Error"); - - if (message->FindInt32(KEY_ALERT_TYPE, &typeInt) != B_OK) - typeInt = B_INFO_ALERT; - - BAlert* alert = new BAlert(alertTitle, alertText, B_TRANSLATE("OK"), NULL, NULL, - B_WIDTH_AS_USUAL, static_cast(typeInt)); - + SimpleAlert simpleAlert(message); + BAlert* alert = new BAlert(simpleAlert.Title(), simpleAlert.Text(), B_TRANSLATE("OK"), NULL, + NULL, B_WIDTH_AS_USUAL, simpleAlert.Type()); alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); alert->Go(); } @@ -421,7 +411,7 @@ App::_LoadSettings(BMessage& settings) { if (!fSettingsRead) { fSettingsRead = true; - if (load_settings(&fSettings, KEY_MAIN_SETTINGS, "HaikuDepot") != B_OK) + if (load_settings(&fSettings, kKeyMainSettings, "HaikuDepot") != B_OK) fSettings.MakeEmpty(); } settings = fSettings; @@ -452,7 +442,7 @@ App::_StoreSettings(const BMessage& settings) } } - save_settings(&fSettings, KEY_MAIN_SETTINGS, "HaikuDepot"); + save_settings(&fSettings, kKeyMainSettings, "HaikuDepot"); } diff --git a/src/apps/haikudepot/ui/FeaturedPackagesView.cpp b/src/apps/haikudepot/ui/FeaturedPackagesView.cpp index 68a8131130..1d658cde16 100644 --- a/src/apps/haikudepot/ui/FeaturedPackagesView.cpp +++ b/src/apps/haikudepot/ui/FeaturedPackagesView.cpp @@ -1,7 +1,7 @@ /* * Copyright 2013-2014, Stephan Aßmus . * Copyright 2017, Julian Harnath . - * Copyright 2020-2025, Andrew Lindesay . + * Copyright 2020-2026, Andrew Lindesay . * Copyright 2025, Pawan Yerramilli . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -300,7 +300,7 @@ public: if (index != -1) { BMessage message(MSG_PACKAGE_SELECTED); BString packageName = fPackages[index]->Name(); - message.AddString("name", packageName); + message.AddString(shared_message_keys::kKeyPackageName, packageName); Window()->PostMessage(&message); } } @@ -320,17 +320,18 @@ public: // #pragma mark - update / add / remove / clear data - void HandlePackagesChanged(const PackageInfoEvents& events) + void HandlePackagesChanged(const std::vector& events) { - for (int32 i = events.CountEvents() - 1; i >= 0; i--) - _HandlePackageChanged(events.EventAtIndex(i)); + std::vector::const_iterator it; + for (it = events.begin(); it != events.end(); it++) + _HandlePackageChanged(*it); } - void _HandlePackageChanged(const PackageInfoEvent& event) + void _HandlePackageChanged(const PackageInfoChangeEvent& event) { uint32 changes = event.Changes(); - PackageInfoRef package = event.Package(); + const PackageInfoRef package = event.Package(); if (!package.IsSet() || 0 == changes) return; @@ -1089,7 +1090,7 @@ FeaturedPackagesView::HandleIconsChanged() void -FeaturedPackagesView::HandlePackagesChanged(const PackageInfoEvents& events) +FeaturedPackagesView::HandlePackagesChanged(const std::vector& events) { fPackagesView->HandlePackagesChanged(events); } diff --git a/src/apps/haikudepot/ui/FeaturedPackagesView.h b/src/apps/haikudepot/ui/FeaturedPackagesView.h index 1d87dbdf43..38d1a28325 100644 --- a/src/apps/haikudepot/ui/FeaturedPackagesView.h +++ b/src/apps/haikudepot/ui/FeaturedPackagesView.h @@ -40,13 +40,14 @@ public: void HandleIconsChanged(); - void HandlePackagesChanged(const PackageInfoEvents& events); + void HandlePackagesChanged( + const std::vector& events); void SetLoading(bool isLoading); private: void _AdjustViews(); - void _HandlePackageChanged(const PackageInfoEvent& event); + void _HandlePackageChanged(const PackageChangeEvent& event); void _BuildNoResultsView(); private: diff --git a/src/apps/haikudepot/ui/FilterView.cpp b/src/apps/haikudepot/ui/FilterView.cpp index 1725c0dd28..44ce11d233 100644 --- a/src/apps/haikudepot/ui/FilterView.cpp +++ b/src/apps/haikudepot/ui/FilterView.cpp @@ -1,6 +1,6 @@ /* * Copyright 2013, Stephan Aßmus . - * Copyright 2019-2025, Andrew Lindesay . + * Copyright 2019-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -27,6 +27,9 @@ #define B_TRANSLATION_CONTEXT "FilterView" +const char* const filter_view_keys::kKeySearchTerms = "search_terms"; + + FilterView::FilterView() : BGroupView("filter view", B_VERTICAL) @@ -85,7 +88,7 @@ FilterView::MessageReceived(BMessage* message) case MSG_SEARCH_TERMS_MODIFIED: { BMessage searchTerms(MSG_SEARCH_TERMS_MODIFIED); - searchTerms.AddString("search terms", fSearchTermsText->Text()); + searchTerms.AddString(filter_view_keys::kKeySearchTerms, fSearchTermsText->Text()); Window()->PostMessage(&searchTerms); break; } @@ -146,7 +149,7 @@ FilterView::_MatchesCategoryCode(BMenuItem* item, const BString& code) if (message == NULL) return false; BString itemCode; - message->FindString("code", &itemCode); + message->FindString(shared_message_keys::kKeyCode, &itemCode); return itemCode == code; } @@ -159,7 +162,7 @@ FilterView::_AddCategoriesToMenu(Model& model, BMenu* menu) for (it = categories.begin(); it != categories.end(); it++) { const CategoryRef& category = *it; BMessage* message = new BMessage(MSG_CATEGORY_SELECTED); - message->AddString("code", category->Code()); + message->AddString(shared_message_keys::kKeyCode, category->Code()); BMenuItem* item = new BMenuItem(category->Name(), message); menu->AddItem(item); } diff --git a/src/apps/haikudepot/ui/FilterView.h b/src/apps/haikudepot/ui/FilterView.h index 9697ca1c88..ce6e46b142 100644 --- a/src/apps/haikudepot/ui/FilterView.h +++ b/src/apps/haikudepot/ui/FilterView.h @@ -1,6 +1,6 @@ /* * Copyright 2013, Stephan Aßmus . - * Copyright 2019-2020, Andrew Lindesay . + * Copyright 2019-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef FILTER_VIEW_H @@ -24,6 +24,13 @@ enum { }; +/*! Keys used with BMessages */ +namespace filter_view_keys { + +extern const char* const kKeySearchTerms; + +}; // namespace filter_view_keys + class FilterView : public BGroupView { public: FilterView(); diff --git a/src/apps/haikudepot/ui/MainWindow.cpp b/src/apps/haikudepot/ui/MainWindow.cpp index b5e17b156f..14686ce19d 100644 --- a/src/apps/haikudepot/ui/MainWindow.cpp +++ b/src/apps/haikudepot/ui/MainWindow.cpp @@ -3,7 +3,7 @@ * Copyright 2013-2014, Stephan Aßmus . * Copyright 2013, Rene Gollent, rene@gollent.com. * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. - * Copyright 2016-2025, Andrew Lindesay . + * Copyright 2016-2026, Andrew Lindesay . * Copyright 2017, Julian Harnath . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -94,6 +94,18 @@ enum { }; +const char* const main_window_keys::kKeyWindowSettings = "window_settings"; + +static const char* const kKeyWorkStatusText = "work_status_text"; +static const char* const kKeyWorkStatusProgress = "work_status_progress"; +static const char* const kKeyWindowFrame = "window frame"; + // use of spaces is historical +static const char* const kKeySinglePackageWindowFrame = "small window frame"; + // use of spaces is historical +static const char* const kKeyColumnSettings = "column settings"; + // use of spaces is historical + + #define KEY_ERROR_STATUS "errorStatus" const bigtime_t kIncrementViewCounterDelayMicros = 3 * 1000 * 1000; @@ -180,7 +192,7 @@ public: private: // PackageInfoListener - virtual void PackagesChanged(const PackageInfoEvents& events) + virtual void PackagesChanged(const PackageChangeEvents& events) { fMainWindow->PackagesChanged(events); } @@ -261,7 +273,7 @@ MainWindow::MainWindow(const BMessage& settings) fModel.AddPackageListener(fPackageInfoListener); BMessage columnSettings; - if (settings.FindMessage("column settings", &columnSettings) == B_OK) + if (settings.FindMessage(kKeyColumnSettings, &columnSettings) == B_OK) fPackageListView->LoadState(&columnSettings); _RestoreModelSettings(settings); @@ -410,7 +422,7 @@ MainWindow::QuitRequested() BMessage settings; StoreSettings(settings); BMessage message(MSG_MAIN_WINDOW_CLOSED); - message.AddMessage(KEY_WINDOW_SETTINGS, &settings); + message.AddMessage(main_window_keys::kKeyWindowSettings, &settings); be_app->PostMessage(&message); if (fShuttingDownWindow != NULL) { @@ -573,7 +585,7 @@ MainWindow::MessageReceived(BMessage* message) case MSG_SERVER_DATA_CHANGED: { BString name; - if (message->FindString("name", &name) == B_OK) { + if (message->FindString(shared_message_keys::kKeyPackageName, &name) == B_OK) { if (fPackageInfoView->Package()->Name() == name) { _PopulatePackageAsync(true); } else { @@ -592,7 +604,7 @@ MainWindow::MessageReceived(BMessage* message) case MSG_PACKAGE_SELECTED: { BString name; - if (message->FindString("name", &name) == B_OK) { + if (message->FindString(shared_message_keys::kKeyPackageName, &name) == B_OK) { PackageInfoRef package; package = fModel.PackageForName(name); @@ -611,7 +623,7 @@ MainWindow::MessageReceived(BMessage* message) case MSG_CATEGORY_SELECTED: { BString code; - if (message->FindString("code", &code) != B_OK) + if (message->FindString(shared_message_keys::kKeyCode, &code) != B_OK) code = ""; fModel.SetFilterSpecification( PackageFilterSpecificationBuilder(fModel.FilterSpecification()) @@ -623,7 +635,7 @@ MainWindow::MessageReceived(BMessage* message) case MSG_DEPOT_SELECTED: { BString name; - if (message->FindString("name", &name) != B_OK) + if (message->FindString(shared_message_keys::kKeyDepotName, &name) != B_OK) name = ""; fModel.SetFilterSpecification( PackageFilterSpecificationBuilder(fModel.FilterSpecification()) @@ -637,7 +649,7 @@ MainWindow::MessageReceived(BMessage* message) { // TODO: Do this with a delay! BString searchTerms; - if (message->FindString("search terms", &searchTerms) != B_OK) + if (message->FindString(filter_view_keys::kKeySearchTerms, &searchTerms) != B_OK) searchTerms = ""; fModel.SetFilterSpecification( PackageFilterSpecificationBuilder(fModel.FilterSpecification()) @@ -657,6 +669,34 @@ MainWindow::MessageReceived(BMessage* message) break; } + case MSG_PKG_INSTALL: + { + InstallPackageAction action(message); + ProcessCoordinator* coordinator + = ProcessCoordinatorFactory::CreateInstallPackageActionCoordinator(&fModel, action); + _AddProcessCoordinator(coordinator); + break; + } + + case MSG_PKG_UNINSTALL: + { + UninstallPackageAction action(message); + ProcessCoordinator* coordinator + = ProcessCoordinatorFactory::CreateUninstallPackageActionCoordinator(&fModel, + action); + _AddProcessCoordinator(coordinator); + break; + } + + case MSG_PKG_OPEN: + { + OpenPackageAction action(message); + ProcessCoordinator* coordinator + = ProcessCoordinatorFactory::CreateOpenPackageActionCoordinator(&fModel, action); + _AddProcessCoordinator(coordinator); + break; + } + case MSG_RATE_PACKAGE: _RatePackage(); break; @@ -723,13 +763,13 @@ MainWindow::StoreSettings(BMessage& settings) { settings.AddRect(_WindowFrameName(), Frame()); if (!fSinglePackageMode) { - settings.AddRect("window frame", Frame()); + settings.AddRect(kKeyWindowFrame, Frame()); BMessage columnSettings; if (fPackageListView != NULL) fPackageListView->SaveState(&columnSettings); - settings.AddMessage("column settings", &columnSettings); + settings.AddMessage(kKeyColumnSettings, &columnSettings); settings.AddString(SETTING_PACKAGE_LIST_VIEW_MODE, main_window_package_list_view_mode_str(fModel.PackageListViewMode())); @@ -751,7 +791,7 @@ MainWindow::StoreSettings(BMessage& settings) fModel.CanShareAnonymousUsageData()); } - settings.AddString("username", fModel.Nickname()); + settings.AddString(SETTING_NICKNAME, fModel.Nickname()); } @@ -769,7 +809,7 @@ MainWindow::Consume(ProcessCoordinator* item) in the GUI. */ void -MainWindow::PackagesChanged(const PackageInfoEvents& events) +MainWindow::PackagesChanged(const PackageChangeEvents& events) { BMessage message(MSG_PACKAGES_CHANGED); status_t result = events.Archive(&message); @@ -788,32 +828,35 @@ MainWindow::PackagesChanged(const PackageInfoEvents& events) void MainWindow::_HandlePackagesChanged(const BMessage* message) { - PackageInfoEvents events; - - // Unpack the changes and at the same time marry them back up to the - // package from the model. - - if (fModel.DearchiveInfoEvents(message, events) != B_OK) { - HDERROR("unable to de-archive the package info events"); - return; - } - - _HandlePackagesChanged(events); -} - - -void -MainWindow::_HandlePackagesChanged(const PackageInfoEvents& events) -{ + PackageChangeEvents packageEvents(message); // if there are no events to process then drop. - if (events.IsEmpty()) { + if (packageEvents.IsEmpty()) { HDINFO("window encountered an empty packages changed"); return; } - HDTRACE("window processing %" B_PRIi32 " package changes", events.CountEvents()); + HDTRACE("window processing %" B_PRIi32 " package changes", packageEvents.CountEvents()); + + // Transfer the package change events into package *info* change events so + // that the immutable PackageInfo instances can be used in the processing + // without having to continuously query the model causing lock overhead. + + std::vector packageInfoEvents; + + for (int32 i = packageEvents.CountEvents() - 1; i >= 0; i--) { + const PackageChangeEvent packageEvent = packageEvents.EventAtIndex(i); + const PackageInfoRef packageInfo = fModel.PackageForName(packageEvent.PackageName()); + + if (packageInfo.IsSet()) { + const PackageInfoChangeEvent packageInfoEvent(packageInfo, packageEvent.Changes()); + packageInfoEvents.push_back(packageInfoEvent); + } else { + HDERROR("package [%s] from change event not found", + packageEvent.PackageName().String()); + } + } // now process the messages by adding and removing them from lists. @@ -826,14 +869,17 @@ MainWindow::_HandlePackagesChanged(const PackageInfoEvents& events) std::vector addedFeaturedPackages; std::vector removedFeaturedPackages; - for (int32 i = events.CountEvents() - 1; i >= 0; i--) { - const PackageInfoEvent event = events.EventAtIndex(i); + std::vector::const_iterator it; - if (event.Changes() & watchedChanges) { - const PackageInfoRef package = event.Package(); - const bool isProminent = PackageUtils::IsProminent(package); + for (it = packageInfoEvents.begin(); it != packageInfoEvents.end(); it++) { + const PackageInfoChangeEvent packageInfoEvent = *it; + + if (packageInfoEvent.Changes() & watchedChanges) { + const PackageInfoRef package = packageInfoEvent.Package(); if (package.IsSet()) { + const bool isProminent = PackageUtils::IsProminent(package); + if (filter->AcceptsPackage(package)) { addedPackages.push_back(package); @@ -845,6 +891,9 @@ MainWindow::_HandlePackagesChanged(const PackageInfoEvents& events) if (isProminent) removedFeaturedPackages.push_back(package); } + } else { + HDFATAL("package change event for missing package"); + // should have checked earlier so this is an illegal state } } } @@ -859,11 +908,11 @@ MainWindow::_HandlePackagesChanged(const PackageInfoEvents& events) // determine which packages are assigned. if (!fSinglePackageMode) { - fFeaturedPackagesView->HandlePackagesChanged(events); - fPackageListView->HandlePackagesChanged(events); + fFeaturedPackagesView->HandlePackagesChanged(packageInfoEvents); + fPackageListView->HandlePackagesChanged(packageInfoEvents); } - fPackageInfoView->HandlePackagesChanged(events); + fPackageInfoView->HandlePackagesChanged(packageInfoEvents); } @@ -954,7 +1003,7 @@ void MainWindow::_RestoreNickname(const BMessage& settings) { BString nickname; - if (settings.FindString("username", &nickname) == B_OK && nickname.Length() > 0) { + if (settings.FindString(SETTING_NICKNAME, &nickname) == B_OK && nickname.Length() > 0) { UserCredentials credentials; if (IdentityAndAccessUtils::RetrieveCredentials(nickname, credentials) == B_OK) { fModel.SetCredentials(credentials); @@ -972,9 +1021,9 @@ const char* MainWindow::_WindowFrameName() const { if (fSinglePackageMode) - return "small window frame"; + return kKeySinglePackageWindowFrame; - return "window frame"; + return kKeyWindowFrame; } @@ -1173,7 +1222,7 @@ MainWindow::_SetupDelayedIncrementViewCounter(const PackageInfoRef package) delete fIncrementViewCounterDelayedRunner; } BMessage message(MSG_INCREMENT_VIEW_COUNTER); - message.SetString("name", package->Name()); + message.SetString(shared_message_keys::kKeyPackageName, package->Name()); fIncrementViewCounterDelayedRunner = new BMessageRunner(BMessenger(this), &message, kIncrementViewCounterDelayMicros, 1); if (fIncrementViewCounterDelayedRunner->InitCheck() != B_OK) @@ -1185,7 +1234,7 @@ void MainWindow::_HandleIncrementViewCounter(const BMessage* message) { BString name; - if (message->FindString("name", &name) == B_OK) { + if (message->FindString(shared_message_keys::kKeyPackageName, &name) == B_OK) { const PackageInfoRef& viewedPackage = fPackageInfoView->Package(); if (viewedPackage.IsSet()) { const BString& viewedPackageName = viewedPackage->Name(); @@ -1294,12 +1343,12 @@ MainWindow::_BulkLoadCompleteReceived(status_t errorStatus) PackagesSummary packagesSummary = fModel.GeneratePackagesSummary(); if (errorStatus != B_OK) { - AppUtils::NotifySimpleError(B_TRANSLATE("Package update error"), + AppUtils::NotifySimpleError(SimpleAlert(B_TRANSLATE("Package update error"), B_TRANSLATE("While updating package data, a problem has arisen " "that may cause data to be outdated or missing from the " "application's display. Additional details regarding this " "problem may be able to be obtained from the application " - "logs." ALERT_MSG_LOGS_USER_GUIDE)); + "logs." ALERT_MSG_LOGS_USER_GUIDE))); } // after the bulk load concludes, if there are no desktop applications @@ -1373,8 +1422,8 @@ MainWindow::_NotifyWorkStatusChange(const BString& text, float progress) BMessage message(MSG_WORK_STATUS_CHANGE); if (!text.IsEmpty()) - message.AddString(KEY_WORK_STATUS_TEXT, text); - message.AddFloat(KEY_WORK_STATUS_PROGRESS, progress); + message.AddString(kKeyWorkStatusText, text); + message.AddFloat(kKeyWorkStatusProgress, progress); this->PostMessage(&message, this); } @@ -1413,7 +1462,8 @@ MainWindow::_SetStateForPackagesByName(BStringList& packageNames, PackageState s if (package.IsSet()) { PackageLocalInfoRef localInfo - = PackageLocalInfoBuilder(package->LocalInfo()).WithState(state).BuildRef(); + = PackageLocalInfoBuilder(package->LocalInfo()).WithState(state) + .ClearInstallationLocations().BuildRef(); modifiedPackages.push_back( PackageInfoBuilder(package).WithLocalInfo(localInfo).BuildRef()); @@ -1439,10 +1489,10 @@ MainWindow::_HandleWorkStatusChangeMessageReceived(const BMessage* message) BString text; float progress; - if (message->FindString(KEY_WORK_STATUS_TEXT, &text) == B_OK) + if (message->FindString(kKeyWorkStatusText, &text) == B_OK) fWorkStatusView->SetText(text); - if (message->FindFloat(KEY_WORK_STATUS_PROGRESS, &progress) == B_OK) { + if (message->FindFloat(kKeyWorkStatusProgress, &progress) == B_OK) { if (progress < 0.0f) fWorkStatusView->SetBusy(); else @@ -1590,7 +1640,7 @@ MainWindow::_UpdateAvailableRepositories() if (depot->Name().Length() != 0) { BMessage* message = new BMessage(MSG_DEPOT_SELECTED); - message->AddString("name", depot->Name()); + message->AddString(shared_message_keys::kKeyDepotName, depot->Name()); BMenuItem* item = new(std::nothrow) BMenuItem(depot->Name(), message); if (item == NULL) @@ -1709,7 +1759,7 @@ MainWindow::UserCredentialsFailed() "and you should login again with your updated password."); message.ReplaceAll("%Nickname%", fModel.Nickname()); - AppUtils::NotifySimpleError(B_TRANSLATE("Login issue"), message); + AppUtils::NotifySimpleError(SimpleAlert(B_TRANSLATE("Login issue"), message)); if (IdentityAndAccessUtils::ClearCredentials() != B_OK) HDERROR("unable to remove stored credentials"); diff --git a/src/apps/haikudepot/ui/MainWindow.h b/src/apps/haikudepot/ui/MainWindow.h index 45713ef9a9..ced02581c2 100644 --- a/src/apps/haikudepot/ui/MainWindow.h +++ b/src/apps/haikudepot/ui/MainWindow.h @@ -2,7 +2,7 @@ * Copyright 2013-2014, Stephan Aßmus . * Copyright 2013, Rene Gollent . * Copyright 2017, Julian Harnath . - * Copyright 2017-2025, Andrew Lindesay . + * Copyright 2017-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef MAIN_WINDOW_H @@ -38,6 +38,14 @@ class WorkStatusView; enum PackageDesktopFilterMode { DESKTOP, NATIVE_DESKTOP, DESKTOP_AND_NON_DESKTOP }; +/*! Keys used with BMessages */ +namespace main_window_keys { + +extern const char* const kKeyWindowSettings; + +}; // namespace main_window_keys + + class MainWindow : private ProcessCoordinatorConsumer, public ProcessCoordinatorListener, public UserDetailVerifierListener, public BWindow { @@ -66,7 +74,7 @@ public: const UserDetail& userDetail); // services PackageInfoListener via MainWindowPackageInfoListener - void PackagesChanged(const PackageInfoEvents& events); + void PackagesChanged(const PackageChangeEvents& events); private: static const BString _WindowTitleForPackage(const PackageInfoRef& pkg); @@ -128,7 +136,7 @@ private: ProcessCoordinatorState& coordinatorState); void _HandlePackagesChanged(const BMessage* message); - void _HandlePackagesChanged(const PackageInfoEvents& events); + void _HandlePackagesChanged(const PackageChangeEvents& events); static status_t _RefreshModelThreadWorker(void* arg); static status_t _PopulatePackageWorker(void* arg); diff --git a/src/apps/haikudepot/ui/PackageInfoView.cpp b/src/apps/haikudepot/ui/PackageInfoView.cpp index 9c46b46d05..a7c4d60edd 100644 --- a/src/apps/haikudepot/ui/PackageInfoView.cpp +++ b/src/apps/haikudepot/ui/PackageInfoView.cpp @@ -1,6 +1,6 @@ /* * Copyright 2013-2014, Stephan Aßmus . - * Copyright 2018-2025, Andrew Lindesay . + * Copyright 2018-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "PackageInfoView.h" @@ -506,13 +506,10 @@ private: class PackageActionView : public BView { public: - PackageActionView(ProcessCoordinatorConsumer* processCoordinatorConsumer, - Model* model) + PackageActionView() : BView("about view", B_WILL_DRAW), - fModel(model), fLayout(new BGroupLayout(B_HORIZONTAL)), - fProcessCoordinatorConsumer(processCoordinatorConsumer), fStatusLabel(NULL), fStatusBar(NULL) { @@ -526,20 +523,6 @@ public: Clear(); } - virtual void MessageReceived(BMessage* message) - { - switch (message->what) { - case MSG_PKG_INSTALL: - case MSG_PKG_UNINSTALL: - case MSG_PKG_OPEN: - _RunPackageAction(message); - break; - default: - BView::MessageReceived(message); - break; - } - } - void SetPackage(const PackageInfoRef package) { if (PackageUtils::State(package) == DOWNLOADING) @@ -626,6 +609,7 @@ private: BButton* button = (BButton*)fButtons.ItemAtFast(index++); button->SetLabel(action->Title()); button->SetMessage(message); + button->SetTarget(Window()); } } @@ -637,7 +621,7 @@ private: BButton* button = new BButton(action->Title(), message); fLayout->AddView(button); button->SetTarget(this); - + button->SetTarget(Window()); fButtons.AddItem(button); } } @@ -666,19 +650,8 @@ private: } } - void _RunPackageAction(BMessage* message) - { - ProcessCoordinator* processCoordinator - = ProcessCoordinatorFactory::CreatePackageActionCoordinator(fModel, message); - fProcessCoordinatorConsumer->Consume(processCoordinator); - _DisableButtonForPackageActionMessage(message); - } - private: - Model* fModel; BGroupLayout* fLayout; - ProcessCoordinatorConsumer* - fProcessCoordinatorConsumer; BList fButtons; BStringView* fStatusLabel; @@ -1352,7 +1325,7 @@ PackageInfoView::PackageInfoView(Model* model, fCardLayout->SetVisibleItem((int32)0); fTitleView = new TitleView(fModel); - fPackageActionView = new PackageActionView(processCoordinatorConsumer, model); + fPackageActionView = new PackageActionView(); fPackageActionView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); fPagesView = new PagesView(model); @@ -1422,7 +1395,7 @@ PackageInfoView::SetPackage(const PackageInfoRef& packageRef) void -PackageInfoView::_HandlePackageChanged(const PackageInfoEvent& event) +PackageInfoView::_HandlePackageChanged(const PackageInfoChangeEvent& event) { uint32 changes = event.Changes(); @@ -1453,13 +1426,14 @@ PackageInfoView::_HandlePackageChanged(const PackageInfoEvent& event) void -PackageInfoView::HandlePackagesChanged(const PackageInfoEvents& events) +PackageInfoView::HandlePackagesChanged(const std::vector& events) { if (!fPackage.IsSet()) return; - for (int32 i = events.CountEvents() - 1; i >= 0; i--) { - PackageInfoEvent event = events.EventAtIndex(i); - _HandlePackageChanged(event); + std::vector::const_iterator it; + for (it = events.begin(); it != events.end(); it++) { + const PackageInfoChangeEvent packageInfoChangeEvent = *it; + _HandlePackageChanged(packageInfoChangeEvent); } } diff --git a/src/apps/haikudepot/ui/PackageInfoView.h b/src/apps/haikudepot/ui/PackageInfoView.h index b2753a3893..67b12f7d51 100644 --- a/src/apps/haikudepot/ui/PackageInfoView.h +++ b/src/apps/haikudepot/ui/PackageInfoView.h @@ -1,11 +1,13 @@ /* * Copyright 2013-2014, Stephan Aßmus . - * Copyright 2020-2025, Andrew Lindesay + * Copyright 2020-2026, Andrew Lindesay * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef PACKAGE_INFO_VIEW_H #define PACKAGE_INFO_VIEW_H +#include + #include #include "Model.h" @@ -43,7 +45,8 @@ public: void HandleScreenshotCached(const ScreenshotCoordinate& coordinate); void HandleIconsChanged(); - void HandlePackagesChanged(const PackageInfoEvents& events); + void HandlePackagesChanged( + const std::vector& events); private: static const ScreenshotCoordinate @@ -52,7 +55,7 @@ private: void _HandleScreenshotCached(const PackageInfoRef& package, const ScreenshotCoordinate& coordinate); - void _HandlePackageChanged(const PackageInfoEvent& event); + void _HandlePackageChanged(const PackageInfoChangeEvent& event); private: Model* fModel; diff --git a/src/apps/haikudepot/ui/PackageListView.cpp b/src/apps/haikudepot/ui/PackageListView.cpp index 24c3c4c688..9f104d87fd 100644 --- a/src/apps/haikudepot/ui/PackageListView.cpp +++ b/src/apps/haikudepot/ui/PackageListView.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2018-2025, Andrew Lindesay, . + * Copyright 2018-2026, Andrew Lindesay, . * Copyright 2017, Julian Harnath, . * Copyright 2015, Axel Dörfler, . * Copyright 2013-2014, Stephan Aßmus . @@ -1167,18 +1167,19 @@ PackageListView::HandleIconsChanged() void -PackageListView::HandlePackagesChanged(const PackageInfoEvents& events) +PackageListView::HandlePackagesChanged(const std::vector& events) { - for (int32 i = events.CountEvents() - 1; i >= 0; i--) - _HandlePackageChanged(events.EventAtIndex(i)); + std::vector::const_iterator it; + for (it = events.begin(); it != events.end(); it++) + _HandlePackageChanged(*it); } void -PackageListView::_HandlePackageChanged(const PackageInfoEvent& event) +PackageListView::_HandlePackageChanged(const PackageInfoChangeEvent& event) { uint32 changes = event.Changes(); - PackageInfoRef package = event.Package(); + const PackageInfoRef package = event.Package(); if (!package.IsSet() || 0 == changes) return; @@ -1221,7 +1222,7 @@ PackageListView::SelectionChanged() PackageRow* selected = dynamic_cast(CurrentSelection()); if (selected != NULL) - message.AddString("name", selected->Package()->Name()); + message.AddString(shared_message_keys::kKeyPackageName, selected->Package()->Name()); Window()->PostMessage(&message); } diff --git a/src/apps/haikudepot/ui/PackageListView.h b/src/apps/haikudepot/ui/PackageListView.h index ecf2f94d26..ab7efb16f7 100644 --- a/src/apps/haikudepot/ui/PackageListView.h +++ b/src/apps/haikudepot/ui/PackageListView.h @@ -1,7 +1,7 @@ /* * Copyright 2013, Stephan Aßmus . * Copyright 2013, Rene Gollent . - * Copyright 2020-2025, Andrew Lindesay + * Copyright 2020-2026, Andrew Lindesay * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef PACKAGE_LIST_VIEW_H @@ -41,10 +41,11 @@ public: void AttachWorkStatusView(WorkStatusView* view); void HandleIconsChanged(); - void HandlePackagesChanged(const PackageInfoEvents& events); + void HandlePackagesChanged( + const std::vector& events); private: - void _HandlePackageChanged(const PackageInfoEvent& event); + void _HandlePackageChanged(const PackageInfoChangeEvent& event); void _AddPackage(const PackageInfoRef& package); void _RemovePackage(const PackageInfoRef& package); diff --git a/src/apps/haikudepot/ui/RatePackageWindow.cpp b/src/apps/haikudepot/ui/RatePackageWindow.cpp index 0f97bd0c4b..a7f0d7566a 100644 --- a/src/apps/haikudepot/ui/RatePackageWindow.cpp +++ b/src/apps/haikudepot/ui/RatePackageWindow.cpp @@ -1,6 +1,6 @@ /* * Copyright 2014, Stephan Aßmus . - * Copyright 2016-2025, Andrew Lindesay . + * Copyright 2016-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -46,6 +46,9 @@ enum { MSG_RATING_DETERMINATE_CHANGED = 'rdch' }; +static const char* const kKeyRating = "rating"; + + //! Layouts the scrollbar so it looks nice with no border and the document // window look. class ScrollView : public BScrollView { @@ -130,7 +133,7 @@ public: { SetPermanentRating(_RatingForMousePos(where)); BMessage message(MSG_PACKAGE_RATED); - message.AddFloat("rating", fPermanentRating); + message.AddFloat(kKeyRating, fPermanentRating); Window()->PostMessage(&message, Window()); } @@ -286,7 +289,7 @@ RatePackageWindow::_InitStabilitiesMenu(BPopUpMenu* menu) for (it = ratingStabilities.begin(); it != ratingStabilities.end(); it++) { const RatingStabilityRef ratingStability = *it; BMessage* message = new BMessage(MSG_STABILITY_SELECTED); - message->AddString("code", ratingStability->Code()); + message->AddString(shared_message_keys::kKeyCode, ratingStability->Code()); BMenuItem* item = new BMenuItem(ratingStability->Name(), message); menu->AddItem(item); } @@ -301,18 +304,18 @@ RatePackageWindow::MessageReceived(BMessage* message) { switch (message->what) { case MSG_PACKAGE_RATED: - message->FindFloat("rating", &fRating); + message->FindFloat(kKeyRating, &fRating); fRatingDeterminate = true; fSetRatingView->SetRatingDeterminate(true); fRatingDeterminateCheckBox->SetValue(B_CONTROL_ON); break; case MSG_STABILITY_SELECTED: - message->FindString("code", &fStabilityCode); + message->FindString(shared_message_keys::kKeyCode, &fStabilityCode); break; case MSG_LANGUAGE_SELECTED: - message->FindString("id", &fCommentLanguageId); + message->FindString(shared_message_keys::kKeyLanguageId, &fCommentLanguageId); break; case MSG_RATING_DETERMINATE_CHANGED: @@ -369,7 +372,7 @@ void RatePackageWindow::_RefreshPackageData() { BMessage message(MSG_SERVER_DATA_CHANGED); - message.AddString("name", fPackage->Name()); + message.AddString(shared_message_keys::kKeyPackageName, fPackage->Name()); be_app->PostMessage(&message); } diff --git a/src/apps/haikudepot/ui/ToLatestUserUsageConditionsWindow.cpp b/src/apps/haikudepot/ui/ToLatestUserUsageConditionsWindow.cpp index 975245af71..79110353c9 100644 --- a/src/apps/haikudepot/ui/ToLatestUserUsageConditionsWindow.cpp +++ b/src/apps/haikudepot/ui/ToLatestUserUsageConditionsWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025, Andrew Lindesay . + * Copyright 2020-2026, Andrew Lindesay . * Copyright 2024 Haiku, Inc. All rights reserved. * All rights reserved. Distributed under the terms of the MIT License. */ @@ -305,9 +305,9 @@ ToLatestUserUsageConditionsWindow::_FetchDataPerform() void ToLatestUserUsageConditionsWindow::_NotifyFetchProblem() { - AppUtils::NotifySimpleError(B_TRANSLATE("Usage conditions download problem"), + AppUtils::NotifySimpleError(SimpleAlert(B_TRANSLATE("Usage conditions download problem"), B_TRANSLATE("An error has arisen downloading the usage conditions. Check the log for " - "details and try again. " ALERT_MSG_LOGS_USER_GUIDE)); + "details and try again. " ALERT_MSG_LOGS_USER_GUIDE))); } @@ -358,8 +358,8 @@ ToLatestUserUsageConditionsWindow::_AgreePerform() } else { int32 errorCode = WebAppInterface::ErrorCodeFromResponse(responsePayload); if (errorCode == ERROR_CODE_NONE) { - AppUtils::NotifySimpleError(B_TRANSLATE("Usage conditions agreed"), - B_TRANSLATE("The current usage conditions have been agreed to.")); + AppUtils::NotifySimpleError(SimpleAlert(B_TRANSLATE("Usage conditions agreed"), + B_TRANSLATE("The current usage conditions have been agreed to."))); messenger.SendMessage(B_QUIT_REQUESTED); } else { ServerHelper::NotifyServerJsonRpcError(responsePayload); diff --git a/src/apps/haikudepot/ui/UserLoginWindow.cpp b/src/apps/haikudepot/ui/UserLoginWindow.cpp index fef62a91b1..3cb564e06c 100644 --- a/src/apps/haikudepot/ui/UserLoginWindow.cpp +++ b/src/apps/haikudepot/ui/UserLoginWindow.cpp @@ -1,6 +1,6 @@ /* * Copyright 2014, Stephan Aßmus . - * Copyright 2019-2025, Andrew Lindesay . + * Copyright 2019-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -48,11 +48,11 @@ #define PLACEHOLDER_TEXT B_UTF8_ELLIPSIS -#define KEY_USER_CREDENTIALS "userCredentials" -#define KEY_CAPTCHA_IMAGE "captchaImage" -#define KEY_USER_USAGE_CONDITIONS "userUsageConditions" -#define KEY_PASSWORD_REQUIREMENTS "passwordRequirements" -#define KEY_VALIDATION_FAILURES "validationFailures" +static const char* const kKeyUserCredentials = "user_credentials"; +static const char* const kKeyCaptchaImage = "captcha_image"; +static const char* const kKeyUserUsageConditions = "user_usage_conditions"; +static const char* const kKeyPasswordRequirements = "password_requirements"; +static const char* const kKeyValidationFailures = "validation_failures"; enum ActionTabs { @@ -305,7 +305,7 @@ UserLoginWindow::MessageReceived(BMessage* message) break; case MSG_LANGUAGE_SELECTED: - message->FindString("id", &fPreferredLanguageId); + message->FindString(shared_message_keys::kKeyLanguageId, &fPreferredLanguageId); break; case MSG_LOGIN_ERROR: @@ -319,7 +319,7 @@ UserLoginWindow::MessageReceived(BMessage* message) case MSG_LOGIN_SUCCESS: { BMessage credentialsMessage; - if (message->FindMessage(KEY_USER_CREDENTIALS, &credentialsMessage) != B_OK) + if (message->FindMessage(kKeyUserCredentials, &credentialsMessage) != B_OK) debugger("expected key in internal message not found"); _HandleAuthenticationSuccess(UserCredentials(&credentialsMessage)); @@ -328,7 +328,7 @@ UserLoginWindow::MessageReceived(BMessage* message) case MSG_CREATE_ACCOUNT_SUCCESS: { BMessage credentialsMessage; - if (message->FindMessage(KEY_USER_CREDENTIALS, &credentialsMessage) != B_OK) + if (message->FindMessage(kKeyUserCredentials, &credentialsMessage) != B_OK) debugger("expected key in internal message not found"); _HandleCreateAccountSuccess(UserCredentials(&credentialsMessage)); @@ -337,7 +337,7 @@ UserLoginWindow::MessageReceived(BMessage* message) case MSG_CREATE_ACCOUNT_FAILED: { BMessage validationFailuresMessage; - if (message->FindMessage(KEY_VALIDATION_FAILURES, &validationFailuresMessage) != B_OK) + if (message->FindMessage(kKeyValidationFailures, &validationFailuresMessage) != B_OK) debugger("expected key in internal message not found"); ValidationFailures validationFailures(&validationFailuresMessage); _HandleCreateAccountFailure(validationFailures); @@ -530,7 +530,7 @@ UserLoginWindow::_AuthenticateThread(UserCredentials& userCredentials) BMessage credentialsMessage; status = userCredentials.Archive(&credentialsMessage); if (status == B_OK) - status = message.AddMessage(KEY_USER_CREDENTIALS, &credentialsMessage); + status = message.AddMessage(kKeyUserCredentials, &credentialsMessage); if (status == B_OK) messenger.SendMessage(&message); } else { @@ -578,9 +578,9 @@ UserLoginWindow::_HandleAuthenticationError() void UserLoginWindow::_HandleAuthenticationFailed() { - AppUtils::NotifySimpleError(B_TRANSLATE("Authentication failed"), + AppUtils::NotifySimpleError(SimpleAlert(B_TRANSLATE("Authentication failed"), B_TRANSLATE("The user does not exist or the wrong password was" - " supplied. Check your credentials and try again.")); + " supplied. Check your credentials and try again."))); fPasswordField->SetText(""); _EnableMutableControls(true); } @@ -737,21 +737,19 @@ UserLoginWindow::_CreateAccountSetupThreadEntry(void* data) BMessage captchaMessage; result = captcha.Archive(&captchaMessage); if (result == B_OK) - result = message.AddMessage(KEY_CAPTCHA_IMAGE, &captchaMessage); + result = message.AddMessage(kKeyCaptchaImage, &captchaMessage); } if (result == B_OK && shouldFetchUserUsageConditions) { BMessage userUsageConditionsMessage; result = userUsageConditions.Archive(&userUsageConditionsMessage); if (result == B_OK) - result = message.AddMessage(KEY_USER_USAGE_CONDITIONS, &userUsageConditionsMessage); + result = message.AddMessage(kKeyUserUsageConditions, &userUsageConditionsMessage); } if (result == B_OK && shouldFetchPasswordRequirements) { BMessage passwordRequirementsMessage; result = passwordRequirements.Archive(&passwordRequirementsMessage); - if (result == B_OK) { - result - = message.AddMessage(KEY_PASSWORD_REQUIREMENTS, &passwordRequirementsMessage); - } + if (result == B_OK) + result = message.AddMessage(kKeyPasswordRequirements, &passwordRequirementsMessage); } if (result == B_OK) { HDDEBUG("successfully completed collection of create account " @@ -783,10 +781,10 @@ UserLoginWindow::_CreateAccountUserUsageConditionsSetupThread( status_t result = interface->RetrieveUserUsageConditions(NULL, userUsageConditions); if (result != B_OK) { - AppUtils::NotifySimpleError(B_TRANSLATE("Usage conditions download problem"), + AppUtils::NotifySimpleError(SimpleAlert(B_TRANSLATE("Usage conditions download problem"), B_TRANSLATE("An error has arisen downloading the usage " "conditions required to create a new user. Check the log for " - "details and try again. " ALERT_MSG_LOGS_USER_GUIDE)); + "details and try again. " ALERT_MSG_LOGS_USER_GUIDE))); } return result; @@ -801,10 +799,11 @@ UserLoginWindow::_CreateAccountPasswordRequirementsSetupThread( status_t result = interface->RetrievePasswordRequirements(passwordRequirements); if (result != B_OK) { - AppUtils::NotifySimpleError(B_TRANSLATE("Password requirements download problem"), - B_TRANSLATE("An error has arisen downloading the password " - "requirements required to create a new user. Check the log for " - "details and try again. " ALERT_MSG_LOGS_USER_GUIDE)); + AppUtils::NotifySimpleError( + SimpleAlert(B_TRANSLATE("Password requirements download problem"), + B_TRANSLATE("An error has arisen downloading the password requirements required to " + "create a new user. Check the log for details and try " + "again. " ALERT_MSG_LOGS_USER_GUIDE))); } return result; @@ -822,9 +821,9 @@ UserLoginWindow::_CreateAccountCaptchaSetupThread(Captcha& captcha) // check for transport related errors. if (status != B_OK) { - AppUtils::NotifySimpleError(B_TRANSLATE("Captcha error"), + AppUtils::NotifySimpleError(SimpleAlert(B_TRANSLATE("Captcha error"), B_TRANSLATE("It was not possible to communicate with the server to " - "obtain a captcha image required to create a new user.")); + "obtain a captcha image required to create a new user."))); } // check for server-generated errors. @@ -841,9 +840,9 @@ UserLoginWindow::_CreateAccountCaptchaSetupThread(Captcha& captcha) if (status == B_OK) { status = _UnpackCaptcha(responsePayload, captcha); if (status != B_OK) { - AppUtils::NotifySimpleError(B_TRANSLATE("Captcha error"), + AppUtils::NotifySimpleError(SimpleAlert(B_TRANSLATE("Captcha error"), B_TRANSLATE("It was not possible to extract necessary captcha " - "information from the data sent back from the server.")); + "information from the data sent back from the server."))); } } @@ -910,13 +909,13 @@ UserLoginWindow::_HandleCreateAccountSetupSuccess(BMessage* message) BMessage userUsageConditionsMessage; BMessage passwordRequirementsMessage; - if (message->FindMessage(KEY_CAPTCHA_IMAGE, &captchaMessage) == B_OK) + if (message->FindMessage(kKeyCaptchaImage, &captchaMessage) == B_OK) _SetCaptcha(new Captcha(&captchaMessage)); - if (message->FindMessage(KEY_USER_USAGE_CONDITIONS, &userUsageConditionsMessage) == B_OK) + if (message->FindMessage(kKeyUserUsageConditions, &userUsageConditionsMessage) == B_OK) _SetUserUsageConditions(new UserUsageConditions(&userUsageConditionsMessage)); - if (message->FindMessage(KEY_PASSWORD_REQUIREMENTS, &passwordRequirementsMessage) == B_OK) + if (message->FindMessage(kKeyPasswordRequirements, &passwordRequirementsMessage) == B_OK) _SetPasswordRequirements(new PasswordRequirements(&passwordRequirementsMessage)); _EnableMutableControls(true); @@ -1243,6 +1242,9 @@ UserLoginWindow::_CreateAccountThreadEntry(void* data) void UserLoginWindow::_CreateAccountThread(CreateUserDetail* detail) { + if (detail->LanguageId().IsEmpty()) + HDFATAL("the language id was not setup when creating a user"); + WebAppInterfaceRef interface = fModel.WebApp(); BMessage responsePayload; BMessenger messenger(this); @@ -1263,7 +1265,7 @@ UserLoginWindow::_CreateAccountThread(CreateUserDetail* detail) UserCredentials userCredentials(detail->Nickname(), detail->PasswordClear()); userCredentials.Archive(&userCredentialsMessage); BMessage message(MSG_CREATE_ACCOUNT_SUCCESS); - message.AddMessage(KEY_USER_CREDENTIALS, &userCredentialsMessage); + message.AddMessage(kKeyUserCredentials, &userCredentialsMessage); messenger.SendMessage(&message); break; } @@ -1274,7 +1276,7 @@ UserLoginWindow::_CreateAccountThread(CreateUserDetail* detail) BMessage validationFailuresMessage; validationFailures.Archive(&validationFailuresMessage); BMessage message(MSG_CREATE_ACCOUNT_FAILED); - message.AddMessage(KEY_VALIDATION_FAILURES, &validationFailuresMessage); + message.AddMessage(kKeyValidationFailures, &validationFailuresMessage); messenger.SendMessage(&message); break; } @@ -1290,7 +1292,7 @@ UserLoginWindow::_CreateAccountThread(CreateUserDetail* detail) BMessage validationFailuresMessage; validationFailures.Archive(&validationFailuresMessage); BMessage message(MSG_CREATE_ACCOUNT_FAILED); - message.AddMessage(KEY_VALIDATION_FAILURES, &validationFailuresMessage); + message.AddMessage(kKeyValidationFailures, &validationFailuresMessage); messenger.SendMessage(&message); break; } @@ -1300,8 +1302,8 @@ UserLoginWindow::_CreateAccountThread(CreateUserDetail* detail) break; } } else { - AppUtils::NotifySimpleError(B_TRANSLATE("User creation error"), - B_TRANSLATE("It was not possible to create the new user.")); + AppUtils::NotifySimpleError(SimpleAlert(B_TRANSLATE("User creation error"), + B_TRANSLATE("It was not possible to create the new user."))); messenger.SendMessage(MSG_CREATE_ACCOUNT_ERROR); } } diff --git a/src/apps/haikudepot/ui/UserUsageConditionsWindow.cpp b/src/apps/haikudepot/ui/UserUsageConditionsWindow.cpp index 92442bbec6..4f36b74f41 100644 --- a/src/apps/haikudepot/ui/UserUsageConditionsWindow.cpp +++ b/src/apps/haikudepot/ui/UserUsageConditionsWindow.cpp @@ -280,7 +280,7 @@ UserUsageConditionsWindow::_FetchDataPerform() BString message = B_TRANSLATE("The user '%Nickname%' has not agreed to any usage " "conditions."); message.ReplaceAll("%Nickname%", userDetail.Nickname()); - AppUtils::NotifySimpleError(B_TRANSLATE("No usage conditions"), message); + AppUtils::NotifySimpleError(SimpleAlert(B_TRANSLATE("No usage conditions"), message)); BMessenger(this).SendMessage(B_QUIT_REQUESTED); status = B_BAD_DATA; } @@ -378,10 +378,10 @@ UserUsageConditionsWindow::_FetchUserUsageConditionsCodeForUserPerform(UserDetai void UserUsageConditionsWindow::_NotifyFetchProblem() { - AppUtils::NotifySimpleError(B_TRANSLATE("Usage conditions download problem"), + AppUtils::NotifySimpleError(SimpleAlert(B_TRANSLATE("Usage conditions download problem"), B_TRANSLATE( "An error has arisen downloading the usage " - "conditions. Check the log for details and try again. " ALERT_MSG_LOGS_USER_GUIDE)); + "conditions. Check the log for details and try again. " ALERT_MSG_LOGS_USER_GUIDE))); } diff --git a/src/apps/haikudepot/util/AppUtils.cpp b/src/apps/haikudepot/util/AppUtils.cpp index ea33c7ad45..23d6a14b3e 100644 --- a/src/apps/haikudepot/util/AppUtils.cpp +++ b/src/apps/haikudepot/util/AppUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2018-2024, Andrew Lindesay . + * Copyright 2018-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -23,20 +23,13 @@ */ /*static*/ void -AppUtils::NotifySimpleError(const char* title, const char* text, - alert_type type) +AppUtils::NotifySimpleError(const SimpleAlert& alertSimple) { BMessage message(MSG_ALERT_SIMPLE_ERROR); - - if (title != NULL && strlen(title) != 0) - message.AddString(KEY_ALERT_TITLE, title); - - if (text != NULL && strlen(text) != 0) - message.AddString(KEY_ALERT_TEXT, text); - - message.AddInt32(KEY_ALERT_TYPE, static_cast(type)); - - be_app->PostMessage(&message); + if (alertSimple.Archive(&message) != B_OK) + HDERROR("unable to archive alert"); + else + be_app->PostMessage(&message); } diff --git a/src/apps/haikudepot/util/AppUtils.h b/src/apps/haikudepot/util/AppUtils.h index 2ae8d5d11f..82425da06e 100644 --- a/src/apps/haikudepot/util/AppUtils.h +++ b/src/apps/haikudepot/util/AppUtils.h @@ -1,5 +1,5 @@ /* - * Copyright 2018-2024, Andrew Lindesay . + * Copyright 2018-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef APP_UTILS_H @@ -8,14 +8,13 @@ #include "Alert.h" #include "Menu.h" +#include "SimpleAlert.h" class AppUtils { public: - static void NotifySimpleError(const char* title, - const char* text, - alert_type type = B_INFO_ALERT); + static void NotifySimpleError(const SimpleAlert& simpleAlert); static status_t MarkItemWithKeyValueInMenuOrFirst(BMenu* menu, const BString& key, const BString& value); diff --git a/src/apps/haikudepot/util/IdentityAndAccessUtils.cpp b/src/apps/haikudepot/util/IdentityAndAccessUtils.cpp index ac18350430..007247b281 100644 --- a/src/apps/haikudepot/util/IdentityAndAccessUtils.cpp +++ b/src/apps/haikudepot/util/IdentityAndAccessUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2025, Andrew Lindesay . + * Copyright 2025-2026, Andrew Lindesay . * Copyright 2013-2014, Stephan Aßmus . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -12,9 +12,9 @@ #include "Logger.h" -static const char* kHaikuDepotKeyring = "HaikuDepot"; +static const char* const kHaikuDepotKeyring = "HaikuDepot"; -static const char* kKeyIdentifierPrefix = "hds.password."; +static const char* const kKeyIdentifierPrefix = "hds.password."; // this prefix is added before the nickname in the keystore // so that HDS username/password pairs can be identified. diff --git a/src/apps/haikudepot/util/LanguageMenuUtils.cpp b/src/apps/haikudepot/util/LanguageMenuUtils.cpp index 5c95cf15c6..f971b5d6a9 100644 --- a/src/apps/haikudepot/util/LanguageMenuUtils.cpp +++ b/src/apps/haikudepot/util/LanguageMenuUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025, Andrew Lindesay . + * Copyright 2019-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "LanguageMenuUtils.h" @@ -19,9 +19,6 @@ #include "Logger.h" -static const char* kLanguageIdKey = "id"; - - /*! This method will add the supplied languages to the menu. It will add first the popular languages, followed by a separator and then other less popular languages. @@ -57,7 +54,8 @@ LanguageMenuUtils::AddLanguagesToMenu(const std::vector& languages, /* static */ void LanguageMenuUtils::MarkLanguageInMenu(const BString& languageId, BMenu* menu) { - AppUtils::MarkItemWithKeyValueInMenuOrFirst(menu, kLanguageIdKey, languageId); + AppUtils::MarkItemWithKeyValueInMenuOrFirst(menu, shared_message_keys::kKeyLanguageId, + languageId); } @@ -65,7 +63,7 @@ LanguageMenuUtils::MarkLanguageInMenu(const BString& languageId, BMenu* menu) LanguageMenuUtils::_AddLanguageToMenu(const BString& id, const BString& name, BMenu* menu) { BMessage* message = new BMessage(MSG_LANGUAGE_SELECTED); - message->AddString(kLanguageIdKey, id); + message->AddString(shared_message_keys::kKeyLanguageId, id); BMenuItem* item = new BMenuItem(name, message); menu->AddItem(item); }