HaikuDepot: Lists; Categories + Stabilities

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 <[email protected]>
This commit is contained in:
Andrew Lindesay
2020-10-22 08:51:25 +00:00
parent 380234c5d8
commit a5e4976d39
19 changed files with 536 additions and 300 deletions
+1
View File
@@ -141,6 +141,7 @@ local applicationSources =
PackageManager.cpp PackageManager.cpp
RatePackageWindow.cpp RatePackageWindow.cpp
RatingView.cpp RatingView.cpp
RatingStability.cpp
RatingUtils.cpp RatingUtils.cpp
support.cpp support.cpp
ScreenshotWindow.cpp ScreenshotWindow.cpp
+113 -29
View File
@@ -7,6 +7,7 @@
#include "Model.h" #include "Model.h"
#include <algorithm>
#include <ctime> #include <ctime>
#include <vector> #include <vector>
@@ -15,7 +16,6 @@
#include <Autolock.h> #include <Autolock.h>
#include <Catalog.h> #include <Catalog.h>
#include <Collator.h>
#include <Directory.h> #include <Directory.h>
#include <Entry.h> #include <Entry.h>
#include <File.h> #include <File.h>
@@ -107,9 +107,8 @@ public:
if (package.Get() == NULL) if (package.Get() == NULL)
return false; return false;
const CategoryList& categories = package->Categories(); for (int i = package->CountCategories() - 1; i >= 0; i--) {
for (int i = categories.CountItems() - 1; i >= 0; i--) { const CategoryRef& category = package->CategoryAtIndex(i);
const CategoryRef& category = categories.ItemAtFast(i);
if (category.Get() == NULL) if (category.Get() == NULL)
continue; continue;
if (category->Code() == fCategory) if (category->Code() == fCategory)
@@ -303,22 +302,10 @@ is_develop_package(const PackageInfoRef& package)
// #pragma mark - Model // #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() Model::Model()
: :
fDepots(), fDepots(),
fCategories(&PackageCategoryCompareFn, NULL), fCategories(),
fCategoryFilter(PackageFilterRef(new AnyFilter(), true)), fCategoryFilter(PackageFilterRef(new AnyFilter(), true)),
fDepotFilter(""), fDepotFilter(""),
fSearchTermsFilter(PackageFilterRef(new AnyFilter(), true)), fSearchTermsFilter(PackageFilterRef(new AnyFilter(), true)),
@@ -1066,26 +1053,123 @@ Model::_MaybeLogJsonRpcError(const BMessage &responsePayload,
} }
void // #pragma mark - Rating Stabilities
Model::AddCategories(const CategoryList& categories)
int32
Model::CountRatingStabilities() const
{ {
int32 i; return fRatingStabilities.size();
for (i = 0; i < categories.CountItems(); i++) }
_AddCategory(categories.ItemAt(i));
RatingStabilityRef
Model::RatingStabilityByCode(BString& code) const
{
std::vector<RatingStabilityRef>::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<RatingStabilityRef>& values)
{
std::vector<RatingStabilityRef>::const_iterator it;
for (it = values.begin(); it != values.end(); it++)
_AddRatingStability(*it);
}
void
Model::_AddRatingStability(const RatingStabilityRef& value)
{
std::vector<RatingStabilityRef>::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<CategoryRef>::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<CategoryRef>& values)
{
std::vector<CategoryRef>::iterator it;
for (it = values.begin(); it != values.end(); it++)
_AddCategory(*it);
_NotifyCategoryListChanged(); _NotifyCategoryListChanged();
} }
/*! This will insert the category in order.
*/
void void
Model::_AddCategory(const CategoryRef& category) Model::_AddCategory(const CategoryRef& category)
{ {
int32 i; std::vector<CategoryRef>::const_iterator itInsertionPt
for (i = 0; i < fCategories.CountItems(); i++) { = std::lower_bound(
if (fCategories.ItemAt(i)->Code() == category->Code()) { fCategories.begin(),
fCategories.Replace(i, category); fCategories.end(),
return; 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);
} }
+19 -5
View File
@@ -14,6 +14,7 @@
#include "PackageIconTarRepository.h" #include "PackageIconTarRepository.h"
#include "LanguageModel.h" #include "LanguageModel.h"
#include "PackageInfo.h" #include "PackageInfo.h"
#include "RatingStability.h"
#include "WebAppInterface.h" #include "WebAppInterface.h"
@@ -88,9 +89,17 @@ public:
void Clear(); void Clear();
void AddCategories(const CategoryList& categories); int32 CountCategories() const;
const CategoryList& Categories() const CategoryRef CategoryByCode(BString& code) const;
{ return fCategories; } CategoryRef CategoryAtIndex(int32 index) const;
void AddCategories(
std::vector<CategoryRef>& values);
int32 CountRatingStabilities() const;
RatingStabilityRef RatingStabilityByCode(BString& code) const;
RatingStabilityRef RatingStabilityAtIndex(int32 index) const;
void AddRatingStabilities(
std::vector<RatingStabilityRef>& values);
void SetPackageState( void SetPackageState(
const PackageInfoRef& package, const PackageInfoRef& package,
@@ -153,6 +162,9 @@ public:
private: private:
void _AddCategory(const CategoryRef& category); void _AddCategory(const CategoryRef& category);
void _AddRatingStability(
const RatingStabilityRef& value);
void _MaybeLogJsonRpcError( void _MaybeLogJsonRpcError(
const BMessage &responsePayload, const BMessage &responsePayload,
const char *sourceDescription) const; const char *sourceDescription) const;
@@ -175,8 +187,10 @@ private:
std::vector<DepotInfoRef> std::vector<DepotInfoRef>
fDepots; fDepots;
std::vector<CategoryRef>
CategoryList fCategories; fCategories;
std::vector<RatingStabilityRef>
fRatingStabilities;
PackageList fInstalledPackages; PackageList fInstalledPackages;
PackageList fActivatedPackages; PackageList fActivatedPackages;
+50 -55
View File
@@ -7,11 +7,15 @@
#include "PackageInfo.h" #include "PackageInfo.h"
#include <algorithm>
#include <Collator.h>
#include <FindDirectory.h> #include <FindDirectory.h>
#include <package/PackageDefs.h> #include <package/PackageDefs.h>
#include <package/PackageFlags.h> #include <package/PackageFlags.h>
#include <Path.h> #include <Path.h>
#include "LocaleUtils.h"
#include "Logger.h" #include "Logger.h"
// #pragma mark - Language // #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 // #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 // #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 void
PackageInfo::ClearCategories() PackageInfo::ClearCategories()
{ {
if (!fCategories.IsEmpty()) { if (!fCategories.empty()) {
fCategories.Clear(); fCategories.clear();
_NotifyListeners(PKG_CHANGED_CATEGORIES); _NotifyListeners(PKG_CHANGED_CATEGORIES);
} }
} }
@@ -735,7 +722,15 @@ PackageInfo::ClearCategories()
bool bool
PackageInfo::AddCategory(const CategoryRef& category) PackageInfo::AddCategory(const CategoryRef& category)
{ {
if (fCategories.Add(category)) { std::vector<CategoryRef>::const_iterator itInsertionPt
= std::lower_bound(
fCategories.begin(),
fCategories.end(),
category,
&IsPackageCategoryBefore);
if (itInsertionPt == fCategories.end()) {
fCategories.push_back(category);
_NotifyListeners(PKG_CHANGED_CATEGORIES); _NotifyListeners(PKG_CHANGED_CATEGORIES);
return true; return true;
} }
+12 -29
View File
@@ -8,6 +8,7 @@
#include <set> #include <set>
#include <vector>
#include <Language.h> #include <Language.h>
#include <Referenceable.h> #include <Referenceable.h>
@@ -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<StabilityRating, false> StabilityRatingList;
class PublisherInfo { class PublisherInfo {
public: public:
PublisherInfo(); PublisherInfo();
@@ -191,6 +167,9 @@ public:
{ return fCode; } { return fCode; }
const BString& Name() const const BString& Name() const
{ return fName; } { return fName; }
int Compare(const PackageCategory& other) const;
private: private:
BString fCode; BString fCode;
BString fName; BString fName;
@@ -198,7 +177,10 @@ private:
typedef BReference<PackageCategory> CategoryRef; typedef BReference<PackageCategory> CategoryRef;
typedef List<CategoryRef, false> CategoryList;
extern bool IsPackageCategoryBefore(const CategoryRef& c1,
const CategoryRef& c2);
class ScreenshotInfo { class ScreenshotInfo {
@@ -323,8 +305,8 @@ public:
void ClearCategories(); void ClearCategories();
bool AddCategory(const CategoryRef& category); bool AddCategory(const CategoryRef& category);
const CategoryList& Categories() const int32 CountCategories() const;
{ return fCategories; } CategoryRef CategoryAtIndex(int32 index) const;
void ClearUserRatings(); void ClearUserRatings();
bool AddUserRating(const UserRating& rating); bool AddUserRating(const UserRating& rating);
@@ -380,7 +362,8 @@ private:
BString fFullDescription; BString fFullDescription;
bool fHasChangelog; bool fHasChangelog;
BString fChangelog; BString fChangelog;
CategoryList fCategories; std::vector<CategoryRef>
fCategories;
UserRatingList fUserRatings; UserRatingList fUserRatings;
RatingSummary fCachedRatingSummary; RatingSummary fCachedRatingSummary;
int64 fProminence; int64 fProminence;
@@ -0,0 +1,84 @@
/*
* Copyright 2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "RatingStability.h"
#include <Collator.h>
#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;
}
@@ -0,0 +1,53 @@
/*
* Copyright 2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef RATING_STABILITY_H
#define RATING_STABILITY_H
#include <Referenceable.h>
#include <String.h>
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<RatingStability> RatingStabilityRef;
extern bool IsRatingStabilityBefore(const RatingStabilityRef& rs1,
const RatingStabilityRef& rs2);
#endif // RATING_STABILITY_H
@@ -51,14 +51,12 @@ public:
private: private:
int32 IndexOfPackageByName(const BString& name) const; int32 IndexOfPackageByName(const BString& name) const;
int32 IndexOfCategoryByName(
const BString& name) const;
int32 IndexOfCategoryByCode(
const BString& code) const;
private:
BString fDepotName; BString fDepotName;
Model* fModel; Model* fModel;
CategoryList fCategories; std::vector<CategoryRef>
fCategories;
Stoppable* fStoppable; Stoppable* fStoppable;
uint32 fCount; uint32 fCount;
bool fDebugEnabled; bool fDebugEnabled;
@@ -74,7 +72,6 @@ PackageFillingPkgListener::PackageFillingPkgListener(Model* model,
fCount(0), fCount(0),
fDebugEnabled(Logger::IsDebugEnabled()) 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 bool
PackageFillingPkgListener::ConsumePackage(const PackageInfoRef& package, PackageFillingPkgListener::ConsumePackage(const PackageInfoRef& package,
DumpExportPkg* pkg) DumpExportPkg* pkg)
@@ -140,15 +117,13 @@ PackageFillingPkgListener::ConsumePackage(const PackageInfoRef& package,
for (i = 0; i < countPkgCategories; i++) { for (i = 0; i < countPkgCategories; i++) {
BString* categoryCode = pkg->PkgCategoriesItemAt(i)->Code(); 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]", HDERROR("unable to find the category for [%s]",
categoryCode->String()); categoryCode->String());
} else { } else
package->AddCategory( package->AddCategory(category);
fCategories.ItemAtFast(categoryIndex));
}
} }
RatingSummary summary; RatingSummary summary;
@@ -113,6 +113,8 @@ ServerReferenceDataUpdateProcess::_ProcessData(DumpExportReference* data)
result = _ProcessNaturalLanguages(data); result = _ProcessNaturalLanguages(data);
if (result == B_OK) if (result == B_OK)
result = _ProcessPkgCategories(data); result = _ProcessPkgCategories(data);
if (result == B_OK)
result = _ProcessRatingStabilities(data);
return result; return result;
} }
@@ -157,12 +159,12 @@ ServerReferenceDataUpdateProcess::_ProcessPkgCategories(
HDINFO("[%s] will populate %" B_PRId32 " pkg categories", HDINFO("[%s] will populate %" B_PRId32 " pkg categories",
Name(), data->CountPkgCategories()); Name(), data->CountPkgCategories());
CategoryList result; std::vector<CategoryRef> assembledCategories;
for (int32 i = 0; i < data->CountPkgCategories(); i++) { for (int32 i = 0; i < data->CountPkgCategories(); i++) {
DumpExportReferencePkgCategory* pkgCategory = DumpExportReferencePkgCategory* pkgCategory =
data->PkgCategoriesItemAt(i); data->PkgCategoriesItemAt(i);
result.Add(CategoryRef( assembledCategories.push_back(CategoryRef(
new PackageCategory( new PackageCategory(
*(pkgCategory->Code()), *(pkgCategory->Code()),
*(pkgCategory->Name()) *(pkgCategory->Name())
@@ -172,7 +174,37 @@ ServerReferenceDataUpdateProcess::_ProcessPkgCategories(
{ {
AutoLocker<BLocker> locker(fModel->Lock()); AutoLocker<BLocker> 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<RatingStabilityRef> 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<BLocker> locker(fModel->Lock());
fModel->AddRatingStabilities(assembledRatingStabilities);
} }
return B_OK; return B_OK;
@@ -1,5 +1,5 @@
/* /*
* Copyright 2019, Andrew Lindesay <[email protected]>. * Copyright 2019-2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef SERVER_REFERENCE_DATA_UPDATE_PROCESS_H #ifndef SERVER_REFERENCE_DATA_UPDATE_PROCESS_H
@@ -48,6 +48,8 @@ private:
DumpExportReference* data); DumpExportReference* data);
status_t _ProcessPkgCategories( status_t _ProcessPkgCategories(
DumpExportReference* data); DumpExportReference* data);
status_t _ProcessRatingStabilities(
DumpExportReference* data);
private: private:
Model* fModel; Model* fModel;
@@ -246,7 +246,7 @@ public:
const PackageInfoRef& packageB) const PackageInfoRef& packageB)
{ {
if (packageA.Get() == NULL || packageB.Get() == NULL) 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()); int c = _CmpProminences(packageA->Prominence(), packageB->Prominence());
if (c == 0) if (c == 0)
c = packageA->Title().ICompare(packageB->Title()); c = packageA->Title().ICompare(packageB->Title());
+20 -19
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright 2013, Stephan Aßmus <[email protected]>. * Copyright 2013, Stephan Aßmus <[email protected]>.
* Copyright 2019, Andrew Lindesay <[email protected]>. * Copyright 2019-2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@@ -27,19 +27,6 @@
#define B_TRANSLATION_CONTEXT "FilterView" #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() FilterView::FilterView()
: :
BGroupView("filter view", B_VERTICAL) BGroupView("filter view", B_VERTICAL)
@@ -124,14 +111,14 @@ FilterView::AdoptModel(Model& model)
new BMessage(MSG_CATEGORY_SELECTED))); new BMessage(MSG_CATEGORY_SELECTED)));
AutoLocker<BLocker> locker(model.Lock()); AutoLocker<BLocker> locker(model.Lock());
CategoryList categories = model.Categories(); int32 categoryCount = model.CountCategories();
if (!categories.IsEmpty()) { if (categoryCount > 0) {
showMenu->AddItem(new BSeparatorItem()); 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())) if (!_SelectCategoryCode(showMenu, model.Category()))
showMenu->ItemAt(0)->SetMarked(true); showMenu->ItemAt(0)->SetMarked(true);
@@ -166,4 +153,18 @@ FilterView::_MatchesCategoryCode(BMenuItem* item, const BString& code)
BString itemCode; BString itemCode;
message->FindString("code", &itemCode); message->FindString("code", &itemCode);
return itemCode == code; return itemCode == code;
} }
/*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);
}
}
+2 -1
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright 2013, Stephan Aßmus <[email protected]>. * Copyright 2013, Stephan Aßmus <[email protected]>.
* Copyright 2019, Andrew Lindesay <[email protected]>. * Copyright 2019-2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef FILTER_VIEW_H #ifndef FILTER_VIEW_H
@@ -35,6 +35,7 @@ public:
void AdoptModel(Model& model); void AdoptModel(Model& model);
private: private:
static void _AddCategoriesToMenu(Model& model, BMenu* menu);
static bool _SelectCategoryCode(BMenu* menu, static bool _SelectCategoryCode(BMenu* menu,
const BString& code); const BString& code);
static bool _MatchesCategoryCode(BMenuItem* item, static bool _MatchesCategoryCode(BMenuItem* item,
+54 -65
View File
@@ -18,10 +18,10 @@
#include <LayoutBuilder.h> #include <LayoutBuilder.h>
#include <MenuField.h> #include <MenuField.h>
#include <MenuItem.h> #include <MenuItem.h>
#include <PopUpMenu.h>
#include <ScrollView.h> #include <ScrollView.h>
#include <StringView.h> #include <StringView.h>
#include "AppUtils.h"
#include "HaikuDepotConstants.h" #include "HaikuDepotConstants.h"
#include "LanguageMenuUtils.h" #include "LanguageMenuUtils.h"
#include "Logger.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, RatePackageWindow::RatePackageWindow(BWindow* parent, BRect frame,
Model& model) Model& model)
: :
@@ -224,41 +211,13 @@ RatePackageWindow::RatePackageWindow(BWindow* parent, BRect frame,
BPopUpMenu* stabilityMenu = new BPopUpMenu(B_TRANSLATE("Stability")); BPopUpMenu* stabilityMenu = new BPopUpMenu(B_TRANSLATE("Stability"));
fStabilityField = new BMenuField("stability", fStabilityField = new BMenuField("stability",
B_TRANSLATE("Stability:"), stabilityMenu); B_TRANSLATE("Stability:"), stabilityMenu);
_InitStabilitiesMenu(stabilityMenu);
fStabilityCodes.Add(StabilityRating( // Construct languages popup
B_TRANSLATE("Not specified"), "unspecified")); BPopUpMenu* languagesMenu = new BPopUpMenu(B_TRANSLATE("Language"));
fStabilityCodes.Add(StabilityRating( fCommentLanguageField = new BMenuField("language",
B_TRANSLATE("Stable"), "stable")); B_TRANSLATE("Comment language:"), languagesMenu);
fStabilityCodes.Add(StabilityRating( _InitLanguagesMenu(languagesMenu);
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<BLocker> 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);
}
fRatingActiveCheckBox = new BCheckBox("rating active", fRatingActiveCheckBox = new BCheckBox("rating active",
B_TRANSLATE("This rating is visible to other users"), B_TRANSLATE("This rating is visible to other users"),
@@ -307,6 +266,46 @@ RatePackageWindow::~RatePackageWindow()
} }
void
RatePackageWindow::_InitLanguagesMenu(BPopUpMenu* menu)
{
AutoLocker<BLocker> 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<BLocker> 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 void
RatePackageWindow::DispatchMessage(BMessage* message, BHandler *handler) RatePackageWindow::DispatchMessage(BMessage* message, BHandler *handler)
{ {
@@ -336,7 +335,7 @@ RatePackageWindow::MessageReceived(BMessage* message)
break; break;
case MSG_STABILITY_SELECTED: case MSG_STABILITY_SELECTED:
message->FindString("name", &fStability); message->FindString("code", &fStabilityCode);
break; break;
case MSG_LANGUAGE_SELECTED: case MSG_LANGUAGE_SELECTED:
@@ -491,19 +490,9 @@ RatePackageWindow::_RelayServerDataToUI(BMessage& response)
fTextView->SetTextDocument(fRatingText); fTextView->SetTextDocument(fRatingText);
} }
if (response.FindString("userRatingStabilityCode", if (response.FindString("userRatingStabilityCode",
&fStability) == B_OK) { &fStabilityCode) == B_OK) {
int32 index = 0; BMenu* menu = fStabilityField->Menu();
for (int32 i = fStabilityCodes.CountItems() - 1; i >= 0; i--) { AppUtils::MarkItemWithCodeInMenu(fStabilityCode, menu);
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);
} }
if (response.FindString("naturalLanguageCode", if (response.FindString("naturalLanguageCode",
&fCommentLanguageCode) == B_OK) { &fCommentLanguageCode) == B_OK) {
@@ -570,8 +559,8 @@ RatePackageWindow::_QueryRatingThread()
} else { } else {
status_t status = interface status_t status = interface
.RetreiveUserRatingForPackageAndVersionByUser(package->Name(), .RetreiveUserRatingForPackageAndVersionByUser(package->Name(),
package->Version(), package->Architecture(), repositoryCode, package->Version(), package->Architecture(), repositoryCode,
nickname, info); nickname, info);
if (status == B_OK) { if (status == B_OK) {
// could be an error or could be a valid response envelope // could be an error or could be a valid response envelope
@@ -636,7 +625,7 @@ RatePackageWindow::_SendRatingThread()
BString architecture = fPackage->Architecture(); BString architecture = fPackage->Architecture();
BString repositoryCode; BString repositoryCode;
int rating = (int)fRating; int rating = (int)fRating;
BString stability = fStability; BString stability = fStabilityCode;
BString comment = fRatingText->Text(); BString comment = fRatingText->Text();
BString languageCode = fCommentLanguageCode; BString languageCode = fCommentLanguageCode;
BString ratingID = fRatingID; BString ratingID = fRatingID;
+9 -3
View File
@@ -1,11 +1,14 @@
/* /*
* Copyright 2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2018-2019, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2018-2020, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef RATE_PACKAGE_WINDOW_H #ifndef RATE_PACKAGE_WINDOW_H
#define RATE_PACKAGE_WINDOW_H #define RATE_PACKAGE_WINDOW_H
#include <vector>
#include <PopUpMenu.h>
#include <Window.h> #include <Window.h>
#include "Model.h" #include "Model.h"
@@ -34,6 +37,10 @@ public:
void SetPackage(const PackageInfoRef& package); void SetPackage(const PackageInfoRef& package);
private: private:
void _InitLanguagesMenu(BPopUpMenu* menu);
void _InitStabilitiesMenu(BPopUpMenu* menu);
void _MarkStabilityInMenu(BString* code);
void _RelayServerDataToUI(BMessage& result); void _RelayServerDataToUI(BMessage& result);
void _SendRating(); void _SendRating();
@@ -54,8 +61,7 @@ private:
TextEditorRef fTextEditor; TextEditorRef fTextEditor;
float fRating; float fRating;
bool fRatingDeterminate; bool fRatingDeterminate;
BString fStability; BString fStabilityCode;
StabilityRatingList fStabilityCodes;
BString fCommentLanguageCode; BString fCommentLanguageCode;
BString fRatingID; BString fRatingID;
bool fRatingActive; bool fRatingActive;
+59 -3
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2018, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2018-2020, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@@ -9,15 +9,18 @@
#include <string.h> #include <string.h>
#include <Application.h> #include <Application.h>
#include <MenuItem.h>
#include <String.h>
#include "HaikuDepotConstants.h" #include "HaikuDepotConstants.h"
#include "Logger.h"
/*! This method can be called to pop up an error in the user interface; /*! This method can be called to pop up an error in the user interface;
typically in a background thread. typically in a background thread.
*/ */
/* static */ void /*static*/ void
AppUtils::NotifySimpleError(const char* title, const char* text) AppUtils::NotifySimpleError(const char* title, const char* text)
{ {
BMessage message(MSG_ALERT_SIMPLE_ERROR); BMessage message(MSG_ALERT_SIMPLE_ERROR);
@@ -29,4 +32,57 @@ AppUtils::NotifySimpleError(const char* title, const char* text)
message.AddString(KEY_ALERT_TEXT, text); message.AddString(KEY_ALERT_TEXT, text);
be_app->PostMessage(&message); be_app->PostMessage(&message);
} }
/*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);
}
+11 -1
View File
@@ -1,17 +1,27 @@
/* /*
* Copyright 2018, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2018-2020, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef APP_UTILS_H #ifndef APP_UTILS_H
#define APP_UTILS_H #define APP_UTILS_H
#include "Menu.h"
class AppUtils { class AppUtils {
public: public:
static void NotifySimpleError(const char* title, static void NotifySimpleError(const char* title,
const char* text); 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);
}; };
+2 -47
View File
@@ -10,6 +10,7 @@
#include <MenuItem.h> #include <MenuItem.h>
#include <Messenger.h> #include <Messenger.h>
#include "AppUtils.h"
#include "HaikuDepotConstants.h" #include "HaikuDepotConstants.h"
#include "Logger.h" #include "Logger.h"
@@ -44,22 +45,7 @@ LanguageMenuUtils::AddLanguagesToMenu(
/* static */ void /* static */ void
LanguageMenuUtils::MarkLanguageInMenu( LanguageMenuUtils::MarkLanguageInMenu(
const BString& languageCode, BMenu* menu) { const BString& languageCode, BMenu* menu) {
if (menu->CountItems() == 0) { AppUtils::MarkItemWithCodeInMenuOrFirst(languageCode, menu);
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);
} }
@@ -102,34 +88,3 @@ LanguageMenuUtils::_AddLanguagesToMenu(const LanguageModel* languageModel,
return count; 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;
}
+1 -6
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2019, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2019-2020, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef LANGUAGE_MENU_UTILS_H #ifndef LANGUAGE_MENU_UTILS_H
@@ -23,11 +23,6 @@ public:
BMenu* menu); BMenu* menu);
private: private:
static int32 _IndexOfLanguageInMenu(
const BString& languageCode,
BMenu* menu);
static status_t _GetLanguageAtIndexInMenu(BMenu* menu,
int32 index, BString* result);
static int32 _AddLanguagesToMenu( static int32 _AddLanguagesToMenu(
const LanguageModel* languagesModel, const LanguageModel* languagesModel,
BMenu* menu, bool isPopular); BMenu* menu, bool isPopular);