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
RatePackageWindow.cpp
RatingView.cpp
RatingStability.cpp
RatingUtils.cpp
support.cpp
ScreenshotWindow.cpp
+113 -29
View File
@@ -7,6 +7,7 @@
#include "Model.h"
#include <algorithm>
#include <ctime>
#include <vector>
@@ -15,7 +16,6 @@
#include <Autolock.h>
#include <Catalog.h>
#include <Collator.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
@@ -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<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();
}
/*! 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<CategoryRef>::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);
}
+19 -5
View File
@@ -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<CategoryRef>& values);
int32 CountRatingStabilities() const;
RatingStabilityRef RatingStabilityByCode(BString& code) const;
RatingStabilityRef RatingStabilityAtIndex(int32 index) const;
void AddRatingStabilities(
std::vector<RatingStabilityRef>& 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<DepotInfoRef>
fDepots;
CategoryList fCategories;
std::vector<CategoryRef>
fCategories;
std::vector<RatingStabilityRef>
fRatingStabilities;
PackageList fInstalledPackages;
PackageList fActivatedPackages;
+50 -55
View File
@@ -7,11 +7,15 @@
#include "PackageInfo.h"
#include <algorithm>
#include <Collator.h>
#include <FindDirectory.h>
#include <package/PackageDefs.h>
#include <package/PackageFlags.h>
#include <Path.h>
#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<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);
return true;
}
+12 -29
View File
@@ -8,6 +8,7 @@
#include <set>
#include <vector>
#include <Language.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 {
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<PackageCategory> CategoryRef;
typedef List<CategoryRef, false> 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<CategoryRef>
fCategories;
UserRatingList fUserRatings;
RatingSummary fCachedRatingSummary;
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:
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<CategoryRef>
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;
@@ -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<CategoryRef> 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<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;
@@ -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.
*/
#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;
@@ -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());
+20 -19
View File
@@ -1,6 +1,6 @@
/*
* Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
* 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.
*/
@@ -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<BLocker> 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;
}
}
/*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 <superstippi@gmx.de>.
* 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.
*/
#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,
+54 -65
View File
@@ -18,10 +18,10 @@
#include <LayoutBuilder.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <PopUpMenu.h>
#include <ScrollView.h>
#include <StringView.h>
#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<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);
}
// 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<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
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;
+9 -3
View File
@@ -1,11 +1,14 @@
/*
* 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.
*/
#ifndef RATE_PACKAGE_WINDOW_H
#define RATE_PACKAGE_WINDOW_H
#include <vector>
#include <PopUpMenu.h>
#include <Window.h>
#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;
+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.
*/
@@ -9,15 +9,18 @@
#include <string.h>
#include <Application.h>
#include <MenuItem.h>
#include <String.h>
#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);
}
}
/*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.
*/
#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);
};
+2 -47
View File
@@ -10,6 +10,7 @@
#include <MenuItem.h>
#include <Messenger.h>
#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;
}
+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.
*/
#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);