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);