From a5e4976d39d790942b064f777d107518ea95be83 Mon Sep 17 00:00:00 2001 From: Andrew Lindesay Date: Tue, 22 Sep 2020 22:11:34 +1200 Subject: [PATCH] HaikuDepot: Lists; Categories + Stabilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove use of custom list class where it is not really required in the area of Categories. Also introduces stabilities relayed over from the Server and used in the HD user interface instead of being hard-coded. Relates To #15534 Change-Id: Ib71141e71cd4a0b4882827e2e59b62072de01b4b Reviewed-on: https://review.haiku-os.org/c/haiku/+/3331 Reviewed-by: Jérôme Duval --- src/apps/haikudepot/Jamfile | 1 + src/apps/haikudepot/model/Model.cpp | 142 ++++++++++++++---- src/apps/haikudepot/model/Model.h | 24 ++- src/apps/haikudepot/model/PackageInfo.cpp | 105 ++++++------- src/apps/haikudepot/model/PackageInfo.h | 41 ++--- src/apps/haikudepot/model/RatingStability.cpp | 84 +++++++++++ src/apps/haikudepot/model/RatingStability.h | 53 +++++++ .../server/ServerPkgDataUpdateProcess.cpp | 39 +---- .../ServerReferenceDataUpdateProcess.cpp | 38 ++++- .../server/ServerReferenceDataUpdateProcess.h | 4 +- .../haikudepot/ui/FeaturedPackagesView.cpp | 2 +- src/apps/haikudepot/ui/FilterView.cpp | 39 ++--- src/apps/haikudepot/ui/FilterView.h | 3 +- src/apps/haikudepot/ui/RatePackageWindow.cpp | 119 +++++++-------- src/apps/haikudepot/ui/RatePackageWindow.h | 12 +- src/apps/haikudepot/util/AppUtils.cpp | 62 +++++++- src/apps/haikudepot/util/AppUtils.h | 12 +- .../haikudepot/util/LanguageMenuUtils.cpp | 49 +----- src/apps/haikudepot/util/LanguageMenuUtils.h | 7 +- 19 files changed, 536 insertions(+), 300 deletions(-) create mode 100644 src/apps/haikudepot/model/RatingStability.cpp create mode 100644 src/apps/haikudepot/model/RatingStability.h diff --git a/src/apps/haikudepot/Jamfile b/src/apps/haikudepot/Jamfile index ca70cf2e06..f56bc2ea0d 100644 --- a/src/apps/haikudepot/Jamfile +++ b/src/apps/haikudepot/Jamfile @@ -141,6 +141,7 @@ local applicationSources = PackageManager.cpp RatePackageWindow.cpp RatingView.cpp + RatingStability.cpp RatingUtils.cpp support.cpp ScreenshotWindow.cpp diff --git a/src/apps/haikudepot/model/Model.cpp b/src/apps/haikudepot/model/Model.cpp index faecc2ecb7..cff14623cf 100644 --- a/src/apps/haikudepot/model/Model.cpp +++ b/src/apps/haikudepot/model/Model.cpp @@ -7,6 +7,7 @@ #include "Model.h" +#include #include #include @@ -15,7 +16,6 @@ #include #include -#include #include #include #include @@ -107,9 +107,8 @@ public: if (package.Get() == NULL) return false; - const CategoryList& categories = package->Categories(); - for (int i = categories.CountItems() - 1; i >= 0; i--) { - const CategoryRef& category = categories.ItemAtFast(i); + for (int i = package->CountCategories() - 1; i >= 0; i--) { + const CategoryRef& category = package->CategoryAtIndex(i); if (category.Get() == NULL) continue; if (category->Code() == fCategory) @@ -303,22 +302,10 @@ is_develop_package(const PackageInfoRef& package) // #pragma mark - Model -static int32 -PackageCategoryCompareFn(const CategoryRef& c1, const CategoryRef& c2) -{ - BCollator* collator = LocaleUtils::GetSharedCollator(); - int32 result = collator->Compare(c1->Name().String(), - c2->Name().String()); - if (result == 0) - result = c1->Code().Compare(c2->Code()); - return result; -} - - Model::Model() : fDepots(), - fCategories(&PackageCategoryCompareFn, NULL), + fCategories(), fCategoryFilter(PackageFilterRef(new AnyFilter(), true)), fDepotFilter(""), fSearchTermsFilter(PackageFilterRef(new AnyFilter(), true)), @@ -1066,26 +1053,123 @@ Model::_MaybeLogJsonRpcError(const BMessage &responsePayload, } -void -Model::AddCategories(const CategoryList& categories) +// #pragma mark - Rating Stabilities + + +int32 +Model::CountRatingStabilities() const { - int32 i; - for (i = 0; i < categories.CountItems(); i++) - _AddCategory(categories.ItemAt(i)); + return fRatingStabilities.size(); +} + + +RatingStabilityRef +Model::RatingStabilityByCode(BString& code) const +{ + std::vector::const_iterator it; + for (it = fRatingStabilities.begin(); it != fRatingStabilities.end(); + it++) { + RatingStabilityRef aRatingStability = *it; + if (aRatingStability->Code() == code) + return aRatingStability; + } + return RatingStabilityRef(); +} + + +RatingStabilityRef +Model::RatingStabilityAtIndex(int32 index) const +{ + return fRatingStabilities[index]; +} + + +void +Model::AddRatingStabilities(std::vector& values) +{ + std::vector::const_iterator it; + for (it = values.begin(); it != values.end(); it++) + _AddRatingStability(*it); +} + + +void +Model::_AddRatingStability(const RatingStabilityRef& value) +{ + std::vector::const_iterator itInsertionPt + = std::lower_bound( + fRatingStabilities.begin(), + fRatingStabilities.end(), + value, + &IsRatingStabilityBefore); + + if (itInsertionPt != fRatingStabilities.end() + && (*itInsertionPt)->Code() == value->Code()) { + itInsertionPt = fRatingStabilities.erase(itInsertionPt); + // replace the one with the same code. + } + + fRatingStabilities.insert(itInsertionPt, value); +} + + +// #pragma mark - Categories + + +int32 +Model::CountCategories() const +{ + return fCategories.size(); +} + + +CategoryRef +Model::CategoryByCode(BString& code) const +{ + std::vector::const_iterator it; + for (it = fCategories.begin(); it != fCategories.end(); it++) { + CategoryRef aCategory = *it; + if (aCategory->Code() == code) + return aCategory; + } + return CategoryRef(); +} + + +CategoryRef +Model::CategoryAtIndex(int32 index) const +{ + return fCategories[index]; +} + + +void +Model::AddCategories(std::vector& values) +{ + std::vector::iterator it; + for (it = values.begin(); it != values.end(); it++) + _AddCategory(*it); _NotifyCategoryListChanged(); } +/*! This will insert the category in order. + */ void Model::_AddCategory(const CategoryRef& category) { - int32 i; - for (i = 0; i < fCategories.CountItems(); i++) { - if (fCategories.ItemAt(i)->Code() == category->Code()) { - fCategories.Replace(i, category); - return; - } + std::vector::const_iterator itInsertionPt + = std::lower_bound( + fCategories.begin(), + fCategories.end(), + category, + &IsPackageCategoryBefore); + + if (itInsertionPt != fCategories.end() + && (*itInsertionPt)->Code() == category->Code()) { + itInsertionPt = fCategories.erase(itInsertionPt); + // replace the one with the same code. } - fCategories.Add(category); + fCategories.insert(itInsertionPt, category); } diff --git a/src/apps/haikudepot/model/Model.h b/src/apps/haikudepot/model/Model.h index e79f0d8dbd..4e16686410 100644 --- a/src/apps/haikudepot/model/Model.h +++ b/src/apps/haikudepot/model/Model.h @@ -14,6 +14,7 @@ #include "PackageIconTarRepository.h" #include "LanguageModel.h" #include "PackageInfo.h" +#include "RatingStability.h" #include "WebAppInterface.h" @@ -88,9 +89,17 @@ public: void Clear(); - void AddCategories(const CategoryList& categories); - const CategoryList& Categories() const - { return fCategories; } + int32 CountCategories() const; + CategoryRef CategoryByCode(BString& code) const; + CategoryRef CategoryAtIndex(int32 index) const; + void AddCategories( + std::vector& values); + + int32 CountRatingStabilities() const; + RatingStabilityRef RatingStabilityByCode(BString& code) const; + RatingStabilityRef RatingStabilityAtIndex(int32 index) const; + void AddRatingStabilities( + std::vector& values); void SetPackageState( const PackageInfoRef& package, @@ -153,6 +162,9 @@ public: private: void _AddCategory(const CategoryRef& category); + void _AddRatingStability( + const RatingStabilityRef& value); + void _MaybeLogJsonRpcError( const BMessage &responsePayload, const char *sourceDescription) const; @@ -175,8 +187,10 @@ private: std::vector fDepots; - - CategoryList fCategories; + std::vector + fCategories; + std::vector + fRatingStabilities; PackageList fInstalledPackages; PackageList fActivatedPackages; diff --git a/src/apps/haikudepot/model/PackageInfo.cpp b/src/apps/haikudepot/model/PackageInfo.cpp index cb7b25489b..b56c3ec098 100644 --- a/src/apps/haikudepot/model/PackageInfo.cpp +++ b/src/apps/haikudepot/model/PackageInfo.cpp @@ -7,11 +7,15 @@ #include "PackageInfo.h" +#include + +#include #include #include #include #include +#include "LocaleUtils.h" #include "Logger.h" // #pragma mark - Language @@ -224,58 +228,6 @@ RatingSummary::operator!=(const RatingSummary& other) const } -// #pragma mark - StabilityRating - - -StabilityRating::StabilityRating() - : - fLabel(), - fName() -{ -} - - -StabilityRating::StabilityRating(const BString& label, - const BString& name) - : - fLabel(label), - fName(name) -{ -} - - -StabilityRating::StabilityRating(const StabilityRating& other) - : - fLabel(other.fLabel), - fName(other.fName) -{ -} - - -StabilityRating& -StabilityRating::operator=(const StabilityRating& other) -{ - fLabel = other.fLabel; - fName = other.fName; - return *this; -} - - -bool -StabilityRating::operator==(const StabilityRating& other) const -{ - return fLabel == other.fLabel - && fName == other.fName; -} - - -bool -StabilityRating::operator!=(const StabilityRating& other) const -{ - return !(*this == other); -} - - // #pragma mark - PublisherInfo @@ -391,6 +343,27 @@ PackageCategory::operator!=(const PackageCategory& other) const } +int +PackageCategory::Compare(const PackageCategory& other) const +{ + BCollator* collator = LocaleUtils::GetSharedCollator(); + int32 result = collator->Compare(Name().String(), + other.Name().String()); + if (result == 0) + result = Code().Compare(other.Code()); + return result; +} + + +bool IsPackageCategoryBefore(const CategoryRef& c1, + const CategoryRef& c2) +{ + if (c1.Get() == NULL || c2.Get() == NULL) + HDFATAL("unexpected NULL reference in a referencable"); + return c1.Get()->Compare(*(c2.Get())) < 0; +} + + // #pragma mark - ScreenshotInfo @@ -722,11 +695,25 @@ PackageInfo::IsSystemPackage() const } +int32 +PackageInfo::CountCategories() const +{ + return fCategories.size(); +} + + +CategoryRef +PackageInfo::CategoryAtIndex(int32 index) const +{ + return fCategories[index]; +} + + void PackageInfo::ClearCategories() { - if (!fCategories.IsEmpty()) { - fCategories.Clear(); + if (!fCategories.empty()) { + fCategories.clear(); _NotifyListeners(PKG_CHANGED_CATEGORIES); } } @@ -735,7 +722,15 @@ PackageInfo::ClearCategories() bool PackageInfo::AddCategory(const CategoryRef& category) { - if (fCategories.Add(category)) { + std::vector::const_iterator itInsertionPt + = std::lower_bound( + fCategories.begin(), + fCategories.end(), + category, + &IsPackageCategoryBefore); + + if (itInsertionPt == fCategories.end()) { + fCategories.push_back(category); _NotifyListeners(PKG_CHANGED_CATEGORIES); return true; } diff --git a/src/apps/haikudepot/model/PackageInfo.h b/src/apps/haikudepot/model/PackageInfo.h index 522a7b36f4..0c10686a2c 100644 --- a/src/apps/haikudepot/model/PackageInfo.h +++ b/src/apps/haikudepot/model/PackageInfo.h @@ -8,6 +8,7 @@ #include +#include #include #include @@ -121,31 +122,6 @@ public: }; -class StabilityRating { -public: - StabilityRating(); - StabilityRating( - const BString& label, - const BString& name); - StabilityRating(const StabilityRating& other); - - StabilityRating& operator=(const StabilityRating& other); - bool operator==(const StabilityRating& other) const; - bool operator!=(const StabilityRating& other) const; - - const BString& Label() const - { return fLabel; } - const BString& Name() const - { return fName; } -private: - BString fLabel; - BString fName; -}; - - -typedef List StabilityRatingList; - - class PublisherInfo { public: PublisherInfo(); @@ -191,6 +167,9 @@ public: { return fCode; } const BString& Name() const { return fName; } + + int Compare(const PackageCategory& other) const; + private: BString fCode; BString fName; @@ -198,7 +177,10 @@ private: typedef BReference CategoryRef; -typedef List CategoryList; + + +extern bool IsPackageCategoryBefore(const CategoryRef& c1, + const CategoryRef& c2); class ScreenshotInfo { @@ -323,8 +305,8 @@ public: void ClearCategories(); bool AddCategory(const CategoryRef& category); - const CategoryList& Categories() const - { return fCategories; } + int32 CountCategories() const; + CategoryRef CategoryAtIndex(int32 index) const; void ClearUserRatings(); bool AddUserRating(const UserRating& rating); @@ -380,7 +362,8 @@ private: BString fFullDescription; bool fHasChangelog; BString fChangelog; - CategoryList fCategories; + std::vector + fCategories; UserRatingList fUserRatings; RatingSummary fCachedRatingSummary; int64 fProminence; diff --git a/src/apps/haikudepot/model/RatingStability.cpp b/src/apps/haikudepot/model/RatingStability.cpp new file mode 100644 index 0000000000..d85ec02d16 --- /dev/null +++ b/src/apps/haikudepot/model/RatingStability.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 2020, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +#include "RatingStability.h" + +#include + +#include "LocaleUtils.h" +#include "Logger.h" + + +bool IsRatingStabilityBefore(const RatingStabilityRef& rs1, + const RatingStabilityRef& rs2) +{ + if (rs1.Get() == NULL || rs2.Get() == NULL) + HDFATAL("unexpected NULL reference in a referencable"); + return rs1.Get()->Compare(*(rs2.Get())) < 0; +} + + +RatingStability::RatingStability() + : + fCode(), + fName(), + fOrdering(0) +{ +} + + +RatingStability::RatingStability(const BString& code, + const BString& name, int64 ordering) + : + fCode(code), + fName(name), + fOrdering(ordering) +{ +} + + +RatingStability::RatingStability(const RatingStability& other) + : + fCode(other.fCode), + fName(other.fName), + fOrdering(other.fOrdering) +{ +} + + +RatingStability& +RatingStability::operator=(const RatingStability& other) +{ + fCode = other.fCode; + fName = other.fName; + fOrdering = other.fOrdering; + return *this; +} + + +bool +RatingStability::operator==(const RatingStability& other) const +{ + return fCode == other.fCode && fName == other.fName + && fOrdering == other.fOrdering; +} + + +bool +RatingStability::operator!=(const RatingStability& other) const +{ + return !(*this == other); +} + + +int +RatingStability::Compare(const RatingStability& other) const +{ + int32 result = other.Ordering() - Ordering(); + if (0 == result) + result = Code().Compare(other.Code()); + return result; +} diff --git a/src/apps/haikudepot/model/RatingStability.h b/src/apps/haikudepot/model/RatingStability.h new file mode 100644 index 0000000000..f8733cf4d4 --- /dev/null +++ b/src/apps/haikudepot/model/RatingStability.h @@ -0,0 +1,53 @@ +/* + * Copyright 2020, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef RATING_STABILITY_H +#define RATING_STABILITY_H + + +#include +#include + + +class RatingStability : public BReferenceable { +public: + RatingStability(); + RatingStability( + const BString& code, + const BString& name, + int64 ordering); + RatingStability( + const RatingStability& other); + + RatingStability& + operator=(const RatingStability& other); + bool operator==(const RatingStability& other) + const; + bool operator!=(const RatingStability& other) + const; + + const BString& Code() const + { return fCode; } + const BString& Name() const + { return fName; } + int64 Ordering() const + { return fOrdering; } + + int Compare(const RatingStability& other) + const; +private: + BString fCode; + BString fName; + int64 fOrdering; +}; + + +typedef BReference RatingStabilityRef; + + +extern bool IsRatingStabilityBefore(const RatingStabilityRef& rs1, + const RatingStabilityRef& rs2); + + +#endif // RATING_STABILITY_H diff --git a/src/apps/haikudepot/server/ServerPkgDataUpdateProcess.cpp b/src/apps/haikudepot/server/ServerPkgDataUpdateProcess.cpp index c932d9236e..9418f8c491 100644 --- a/src/apps/haikudepot/server/ServerPkgDataUpdateProcess.cpp +++ b/src/apps/haikudepot/server/ServerPkgDataUpdateProcess.cpp @@ -51,14 +51,12 @@ public: private: int32 IndexOfPackageByName(const BString& name) const; - int32 IndexOfCategoryByName( - const BString& name) const; - int32 IndexOfCategoryByCode( - const BString& code) const; +private: BString fDepotName; Model* fModel; - CategoryList fCategories; + std::vector + fCategories; Stoppable* fStoppable; uint32 fCount; bool fDebugEnabled; @@ -74,7 +72,6 @@ PackageFillingPkgListener::PackageFillingPkgListener(Model* model, fCount(0), fDebugEnabled(Logger::IsDebugEnabled()) { - fCategories = model->Categories(); } @@ -83,26 +80,6 @@ PackageFillingPkgListener::~PackageFillingPkgListener() } - // TODO; performance could be improved by not needing the linear search - -inline int32 -PackageFillingPkgListener::IndexOfCategoryByCode( - const BString& code) const -{ - int32 i; - int32 categoryCount = fCategories.CountItems(); - - for (i = 0; i < categoryCount; i++) { - const CategoryRef categoryRef = fCategories.ItemAtFast(i); - - if (categoryRef->Code() == code) - return i; - } - - return -1; -} - - bool PackageFillingPkgListener::ConsumePackage(const PackageInfoRef& package, DumpExportPkg* pkg) @@ -140,15 +117,13 @@ PackageFillingPkgListener::ConsumePackage(const PackageInfoRef& package, for (i = 0; i < countPkgCategories; i++) { BString* categoryCode = pkg->PkgCategoriesItemAt(i)->Code(); - int categoryIndex = IndexOfCategoryByCode(*(categoryCode)); + CategoryRef category = fModel->CategoryByCode(*categoryCode); - if (categoryIndex == -1) { + if (category.Get() == NULL) { HDERROR("unable to find the category for [%s]", categoryCode->String()); - } else { - package->AddCategory( - fCategories.ItemAtFast(categoryIndex)); - } + } else + package->AddCategory(category); } RatingSummary summary; diff --git a/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.cpp b/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.cpp index 04348c91d7..2cc914ecdb 100644 --- a/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.cpp +++ b/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.cpp @@ -113,6 +113,8 @@ ServerReferenceDataUpdateProcess::_ProcessData(DumpExportReference* data) result = _ProcessNaturalLanguages(data); if (result == B_OK) result = _ProcessPkgCategories(data); + if (result == B_OK) + result = _ProcessRatingStabilities(data); return result; } @@ -157,12 +159,12 @@ ServerReferenceDataUpdateProcess::_ProcessPkgCategories( HDINFO("[%s] will populate %" B_PRId32 " pkg categories", Name(), data->CountPkgCategories()); - CategoryList result; + std::vector assembledCategories; for (int32 i = 0; i < data->CountPkgCategories(); i++) { DumpExportReferencePkgCategory* pkgCategory = data->PkgCategoriesItemAt(i); - result.Add(CategoryRef( + assembledCategories.push_back(CategoryRef( new PackageCategory( *(pkgCategory->Code()), *(pkgCategory->Name()) @@ -172,7 +174,37 @@ ServerReferenceDataUpdateProcess::_ProcessPkgCategories( { AutoLocker locker(fModel->Lock()); - fModel->AddCategories(result); + fModel->AddCategories(assembledCategories); + } + + return B_OK; +} + + +status_t +ServerReferenceDataUpdateProcess::_ProcessRatingStabilities( + DumpExportReference* data) +{ + HDINFO("[%s] will populate %" B_PRId32 " rating stabilities", + Name(), data->CountUserRatingStabilities()); + + std::vector assembledRatingStabilities; + + for (int32 i = 0; i < data->CountUserRatingStabilities(); i++) { + DumpExportReferenceUserRatingStability* ratingStability = + data->UserRatingStabilitiesItemAt(i); + assembledRatingStabilities.push_back(RatingStabilityRef( + new RatingStability( + *(ratingStability->Code()), + *(ratingStability->Name()), + ratingStability->Ordering() + ), + true)); + } + + { + AutoLocker locker(fModel->Lock()); + fModel->AddRatingStabilities(assembledRatingStabilities); } return B_OK; diff --git a/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.h b/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.h index 25ff2c1101..a969e9d8cb 100644 --- a/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.h +++ b/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.h @@ -1,5 +1,5 @@ /* - * Copyright 2019, Andrew Lindesay . + * Copyright 2019-2020, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef SERVER_REFERENCE_DATA_UPDATE_PROCESS_H @@ -48,6 +48,8 @@ private: DumpExportReference* data); status_t _ProcessPkgCategories( DumpExportReference* data); + status_t _ProcessRatingStabilities( + DumpExportReference* data); private: Model* fModel; diff --git a/src/apps/haikudepot/ui/FeaturedPackagesView.cpp b/src/apps/haikudepot/ui/FeaturedPackagesView.cpp index 854d88f3e8..9176fcc84f 100644 --- a/src/apps/haikudepot/ui/FeaturedPackagesView.cpp +++ b/src/apps/haikudepot/ui/FeaturedPackagesView.cpp @@ -246,7 +246,7 @@ public: const PackageInfoRef& packageB) { if (packageA.Get() == NULL || packageB.Get() == NULL) - debugger("unexpected NULL reference in a referencable"); + HDFATAL("unexpected NULL reference in a referencable"); int c = _CmpProminences(packageA->Prominence(), packageB->Prominence()); if (c == 0) c = packageA->Title().ICompare(packageB->Title()); diff --git a/src/apps/haikudepot/ui/FilterView.cpp b/src/apps/haikudepot/ui/FilterView.cpp index cccf70185d..9372139ae9 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, Andrew Lindesay . + * Copyright 2019-2020, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -27,19 +27,6 @@ #define B_TRANSLATION_CONTEXT "FilterView" -static void -add_categories_to_menu(const CategoryList& categories, BMenu* menu) -{ - for (int i = 0; i < categories.CountItems(); i++) { - const CategoryRef& category = categories.ItemAtFast(i); - BMessage* message = new BMessage(MSG_CATEGORY_SELECTED); - message->AddString("code", category->Code()); - BMenuItem* item = new BMenuItem(category->Name(), message); - menu->AddItem(item); - } -} - - FilterView::FilterView() : BGroupView("filter view", B_VERTICAL) @@ -124,14 +111,14 @@ FilterView::AdoptModel(Model& model) new BMessage(MSG_CATEGORY_SELECTED))); AutoLocker locker(model.Lock()); - CategoryList categories = model.Categories(); + int32 categoryCount = model.CountCategories(); - if (!categories.IsEmpty()) { + if (categoryCount > 0) { showMenu->AddItem(new BSeparatorItem()); - add_categories_to_menu(categories, showMenu); + _AddCategoriesToMenu(model, showMenu); } - showMenu->SetEnabled(!categories.IsEmpty()); + showMenu->SetEnabled(categoryCount > 0); if (!_SelectCategoryCode(showMenu, model.Category())) showMenu->ItemAt(0)->SetMarked(true); @@ -166,4 +153,18 @@ FilterView::_MatchesCategoryCode(BMenuItem* item, const BString& code) BString itemCode; message->FindString("code", &itemCode); return itemCode == code; -} \ No newline at end of file +} + + +/*static*/ void +FilterView::_AddCategoriesToMenu(Model& model, BMenu* menu) +{ + int count = model.CountCategories(); + for (int i = 0; i < count; i++) { + const CategoryRef& category = model.CategoryAtIndex(i); + BMessage* message = new BMessage(MSG_CATEGORY_SELECTED); + message->AddString("code", 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 795c095a60..9697ca1c88 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, Andrew Lindesay . + * Copyright 2019-2020, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef FILTER_VIEW_H @@ -35,6 +35,7 @@ public: void AdoptModel(Model& model); private: + static void _AddCategoriesToMenu(Model& model, BMenu* menu); static bool _SelectCategoryCode(BMenu* menu, const BString& code); static bool _MatchesCategoryCode(BMenuItem* item, diff --git a/src/apps/haikudepot/ui/RatePackageWindow.cpp b/src/apps/haikudepot/ui/RatePackageWindow.cpp index 885417dfd0..8cfd90643f 100644 --- a/src/apps/haikudepot/ui/RatePackageWindow.cpp +++ b/src/apps/haikudepot/ui/RatePackageWindow.cpp @@ -18,10 +18,10 @@ #include #include #include -#include #include #include +#include "AppUtils.h" #include "HaikuDepotConstants.h" #include "LanguageMenuUtils.h" #include "Logger.h" @@ -169,19 +169,6 @@ private: }; -static void -add_stabilities_to_menu(const StabilityRatingList& stabilities, BMenu* menu) -{ - for (int i = 0; i < stabilities.CountItems(); i++) { - const StabilityRating& stability = stabilities.ItemAtFast(i); - BMessage* message = new BMessage(MSG_STABILITY_SELECTED); - message->AddString("name", stability.Name()); - BMenuItem* item = new BMenuItem(stability.Label(), message); - menu->AddItem(item); - } -} - - RatePackageWindow::RatePackageWindow(BWindow* parent, BRect frame, Model& model) : @@ -224,41 +211,13 @@ RatePackageWindow::RatePackageWindow(BWindow* parent, BRect frame, BPopUpMenu* stabilityMenu = new BPopUpMenu(B_TRANSLATE("Stability")); fStabilityField = new BMenuField("stability", B_TRANSLATE("Stability:"), stabilityMenu); + _InitStabilitiesMenu(stabilityMenu); - fStabilityCodes.Add(StabilityRating( - B_TRANSLATE("Not specified"), "unspecified")); - fStabilityCodes.Add(StabilityRating( - B_TRANSLATE("Stable"), "stable")); - fStabilityCodes.Add(StabilityRating( - B_TRANSLATE("Mostly stable"), "mostlystable")); - fStabilityCodes.Add(StabilityRating( - B_TRANSLATE("Unstable but usable"), "unstablebutusable")); - fStabilityCodes.Add(StabilityRating( - B_TRANSLATE("Very unstable"), "veryunstable")); - fStabilityCodes.Add(StabilityRating( - B_TRANSLATE("Does not start"), "nostart")); - - add_stabilities_to_menu(fStabilityCodes, stabilityMenu); - stabilityMenu->SetTargetForItems(this); - - fStability = fStabilityCodes.ItemAt(0).Name(); - stabilityMenu->ItemAt(0)->SetMarked(true); - - - { - AutoLocker locker(fModel.Lock()); - fCommentLanguageCode = fModel.Language()->PreferredLanguage()->Code(); - - // Construct languages popup - BPopUpMenu* languagesMenu = new BPopUpMenu(B_TRANSLATE("Language")); - fCommentLanguageField = new BMenuField("language", - B_TRANSLATE("Comment language:"), languagesMenu); - - LanguageMenuUtils::AddLanguagesToMenu(fModel.Language(), languagesMenu); - languagesMenu->SetTargetForItems(this); - LanguageMenuUtils::MarkLanguageInMenu(fCommentLanguageCode, - languagesMenu); - } + // Construct languages popup + BPopUpMenu* languagesMenu = new BPopUpMenu(B_TRANSLATE("Language")); + fCommentLanguageField = new BMenuField("language", + B_TRANSLATE("Comment language:"), languagesMenu); + _InitLanguagesMenu(languagesMenu); fRatingActiveCheckBox = new BCheckBox("rating active", B_TRANSLATE("This rating is visible to other users"), @@ -307,6 +266,46 @@ RatePackageWindow::~RatePackageWindow() } +void +RatePackageWindow::_InitLanguagesMenu(BPopUpMenu* menu) +{ + AutoLocker locker(fModel.Lock()); + fCommentLanguageCode = fModel.Language()->PreferredLanguage()->Code(); + + LanguageMenuUtils::AddLanguagesToMenu(fModel.Language(), menu); + menu->SetTargetForItems(this); + LanguageMenuUtils::MarkLanguageInMenu(fCommentLanguageCode, menu); +} + + +void +RatePackageWindow::_InitStabilitiesMenu(BPopUpMenu* menu) +{ + AutoLocker locker(fModel.Lock()); + int32 countStabilities = fModel.CountRatingStabilities(); + + menu->SetTargetForItems(this); + + if (0 == countStabilities) { + menu->SetEnabled(false); + return; + } + + for (int32 i = 0; i < countStabilities; i++) { + const RatingStabilityRef stability = fModel.RatingStabilityAtIndex(i); + BMessage* message = new BMessage(MSG_STABILITY_SELECTED); + message->AddString("code", stability->Code()); + BMenuItem* item = new BMenuItem(stability->Name(), message); + menu->AddItem(item); + + if (i == 0) { + fStabilityCode = stability->Code(); + item->SetMarked(true); + } + } +} + + void RatePackageWindow::DispatchMessage(BMessage* message, BHandler *handler) { @@ -336,7 +335,7 @@ RatePackageWindow::MessageReceived(BMessage* message) break; case MSG_STABILITY_SELECTED: - message->FindString("name", &fStability); + message->FindString("code", &fStabilityCode); break; case MSG_LANGUAGE_SELECTED: @@ -491,19 +490,9 @@ RatePackageWindow::_RelayServerDataToUI(BMessage& response) fTextView->SetTextDocument(fRatingText); } if (response.FindString("userRatingStabilityCode", - &fStability) == B_OK) { - int32 index = 0; - for (int32 i = fStabilityCodes.CountItems() - 1; i >= 0; i--) { - const StabilityRating& stability - = fStabilityCodes.ItemAtFast(i); - if (stability.Name() == fStability) { - index = i; - break; - } - } - BMenuItem* item = fStabilityField->Menu()->ItemAt(index); - if (item != NULL) - item->SetMarked(true); + &fStabilityCode) == B_OK) { + BMenu* menu = fStabilityField->Menu(); + AppUtils::MarkItemWithCodeInMenu(fStabilityCode, menu); } if (response.FindString("naturalLanguageCode", &fCommentLanguageCode) == B_OK) { @@ -570,8 +559,8 @@ RatePackageWindow::_QueryRatingThread() } else { status_t status = interface .RetreiveUserRatingForPackageAndVersionByUser(package->Name(), - package->Version(), package->Architecture(), repositoryCode, - nickname, info); + package->Version(), package->Architecture(), repositoryCode, + nickname, info); if (status == B_OK) { // could be an error or could be a valid response envelope @@ -636,7 +625,7 @@ RatePackageWindow::_SendRatingThread() BString architecture = fPackage->Architecture(); BString repositoryCode; int rating = (int)fRating; - BString stability = fStability; + BString stability = fStabilityCode; BString comment = fRatingText->Text(); BString languageCode = fCommentLanguageCode; BString ratingID = fRatingID; diff --git a/src/apps/haikudepot/ui/RatePackageWindow.h b/src/apps/haikudepot/ui/RatePackageWindow.h index bd6e2c5393..fa885c8191 100644 --- a/src/apps/haikudepot/ui/RatePackageWindow.h +++ b/src/apps/haikudepot/ui/RatePackageWindow.h @@ -1,11 +1,14 @@ /* * Copyright 2014, Stephan Aßmus . - * Copyright 2018-2019, Andrew Lindesay . + * Copyright 2018-2020, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef RATE_PACKAGE_WINDOW_H #define RATE_PACKAGE_WINDOW_H +#include + +#include #include #include "Model.h" @@ -34,6 +37,10 @@ public: void SetPackage(const PackageInfoRef& package); private: + void _InitLanguagesMenu(BPopUpMenu* menu); + void _InitStabilitiesMenu(BPopUpMenu* menu); + void _MarkStabilityInMenu(BString* code); + void _RelayServerDataToUI(BMessage& result); void _SendRating(); @@ -54,8 +61,7 @@ private: TextEditorRef fTextEditor; float fRating; bool fRatingDeterminate; - BString fStability; - StabilityRatingList fStabilityCodes; + BString fStabilityCode; BString fCommentLanguageCode; BString fRatingID; bool fRatingActive; diff --git a/src/apps/haikudepot/util/AppUtils.cpp b/src/apps/haikudepot/util/AppUtils.cpp index 79bdfff77a..b4d39351c3 100644 --- a/src/apps/haikudepot/util/AppUtils.cpp +++ b/src/apps/haikudepot/util/AppUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2018, Andrew Lindesay . + * Copyright 2018-2020, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -9,15 +9,18 @@ #include #include +#include +#include #include "HaikuDepotConstants.h" +#include "Logger.h" /*! This method can be called to pop up an error in the user interface; typically in a background thread. */ -/* static */ void +/*static*/ void AppUtils::NotifySimpleError(const char* title, const char* text) { BMessage message(MSG_ALERT_SIMPLE_ERROR); @@ -29,4 +32,57 @@ AppUtils::NotifySimpleError(const char* title, const char* text) message.AddString(KEY_ALERT_TEXT, text); be_app->PostMessage(&message); -} \ No newline at end of file +} + + +/*static*/ status_t +AppUtils::MarkItemWithCodeInMenuOrFirst(const BString& code, BMenu* menu) +{ + status_t result = AppUtils::MarkItemWithCodeInMenu(code, menu); + if (result != B_OK) + menu->ItemAt(0)->SetMarked(true); + return result; +} + + +/*static*/ status_t +AppUtils::MarkItemWithCodeInMenu(const BString& code, BMenu* menu) +{ + if (menu->CountItems() == 0) + HDFATAL("menu contains no items; not able to mark the item"); + + int32 index = AppUtils::IndexOfCodeInMenu(code, menu); + + if (index == -1) { + HDINFO("unable to find the menu item [%s]", code.String()); + return B_ERROR; + } + + menu->ItemAt(index)->SetMarked(true); + return B_OK; +} + + +/*static*/ int32 +AppUtils::IndexOfCodeInMenu(const BString& code, BMenu* menu) +{ + BString itemCode; + for (int32 i = 0; i < menu->CountItems(); i++) { + if (AppUtils::GetCodeAtIndexInMenu(menu, i, &itemCode) == B_OK + && itemCode == code) { + return i; + } + } + + return -1; +} + + +/*static*/ status_t +AppUtils::GetCodeAtIndexInMenu(BMenu* menu, int32 index, BString* result) +{ + BMessage *itemMessage = menu->ItemAt(index)->Message(); + if (itemMessage == NULL) + return B_ERROR; + return itemMessage->FindString("code", result); +} diff --git a/src/apps/haikudepot/util/AppUtils.h b/src/apps/haikudepot/util/AppUtils.h index 1efae0abfe..02fdf3b34a 100644 --- a/src/apps/haikudepot/util/AppUtils.h +++ b/src/apps/haikudepot/util/AppUtils.h @@ -1,17 +1,27 @@ /* - * Copyright 2018, Andrew Lindesay . + * Copyright 2018-2020, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef APP_UTILS_H #define APP_UTILS_H +#include "Menu.h" + + class AppUtils { public: static void NotifySimpleError(const char* title, const char* text); + static status_t MarkItemWithCodeInMenuOrFirst(const BString& code, + BMenu* menu); + static status_t MarkItemWithCodeInMenu(const BString& code, + BMenu* menu); + static int32 IndexOfCodeInMenu(const BString& code, BMenu* menu); + static status_t GetCodeAtIndexInMenu(BMenu* menu, int32 index, + BString* result); }; diff --git a/src/apps/haikudepot/util/LanguageMenuUtils.cpp b/src/apps/haikudepot/util/LanguageMenuUtils.cpp index f3d597730d..67b887fbd3 100644 --- a/src/apps/haikudepot/util/LanguageMenuUtils.cpp +++ b/src/apps/haikudepot/util/LanguageMenuUtils.cpp @@ -10,6 +10,7 @@ #include #include +#include "AppUtils.h" #include "HaikuDepotConstants.h" #include "Logger.h" @@ -44,22 +45,7 @@ LanguageMenuUtils::AddLanguagesToMenu( /* static */ void LanguageMenuUtils::MarkLanguageInMenu( const BString& languageCode, BMenu* menu) { - if (menu->CountItems() == 0) { - debugger("menu contains no items; not able to set the " - "language"); - return; - } - - int32 index = LanguageMenuUtils::_IndexOfLanguageInMenu( - languageCode, menu); - - if (index == -1) { - HDINFO("unable to find the language [%s] in the menu", - languageCode.String()); - menu->ItemAt(0)->SetMarked(true); - } - else - menu->ItemAt(index)->SetMarked(true); + AppUtils::MarkItemWithCodeInMenuOrFirst(languageCode, menu); } @@ -102,34 +88,3 @@ LanguageMenuUtils::_AddLanguagesToMenu(const LanguageModel* languageModel, return count; } - - -/* static */ status_t -LanguageMenuUtils::_GetLanguageAtIndexInMenu(BMenu* menu, int32 index, - BString* result) -{ - BMessage *itemMessage = menu->ItemAt(index)->Message(); - - if (itemMessage == NULL) - return B_ERROR; - - return itemMessage->FindString("code", result); -} - - -/* static */ int32 -LanguageMenuUtils::_IndexOfLanguageInMenu( - const BString& languageCode, BMenu* menu) -{ - BString itemLanguageCode; - for (int32 i = 0; i < menu->CountItems(); i++) { - if (_GetLanguageAtIndexInMenu( - menu, i, &itemLanguageCode) == B_OK) { - if (itemLanguageCode == languageCode) { - return i; - } - } - } - - return -1; -} \ No newline at end of file diff --git a/src/apps/haikudepot/util/LanguageMenuUtils.h b/src/apps/haikudepot/util/LanguageMenuUtils.h index bf33c70ffa..0a01dea703 100644 --- a/src/apps/haikudepot/util/LanguageMenuUtils.h +++ b/src/apps/haikudepot/util/LanguageMenuUtils.h @@ -1,5 +1,5 @@ /* - * Copyright 2019, Andrew Lindesay . + * Copyright 2019-2020, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef LANGUAGE_MENU_UTILS_H @@ -23,11 +23,6 @@ public: BMenu* menu); private: - static int32 _IndexOfLanguageInMenu( - const BString& languageCode, - BMenu* menu); - static status_t _GetLanguageAtIndexInMenu(BMenu* menu, - int32 index, BString* result); static int32 _AddLanguagesToMenu( const LanguageModel* languagesModel, BMenu* menu, bool isPopular);