HaikuDepot: Model package classification

This moves the categories, prominence and native
desktop (new) flag into a separate model.

Change-Id: I4c45004a3a38cc08bb610184f8d7ef786f0d1a08
Reviewed-on: https://review.haiku-os.org/c/haiku/+/8474
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
This commit is contained in:
Andrew Lindesay 2024-10-20 20:42:55 +13:00
parent f13cec8031
commit 8cc3ed34bc
12 changed files with 265 additions and 105 deletions

View File

@ -177,6 +177,7 @@ local applicationSources =
DepotInfo.cpp
Language.cpp
PackageCategory.cpp
PackageClassificationInfo.cpp
PackageFilter.cpp
PackageFilterModel.cpp
PackageInfo.cpp

View File

@ -19,12 +19,12 @@ enum {
PKG_CHANGED_STATE = 1 << 5,
PKG_CHANGED_ICON = 1 << 6,
PKG_CHANGED_CHANGELOG = 1 << 7,
PKG_CHANGED_CATEGORIES = 1 << 8,
PKG_CHANGED_PROMINENCE = 1 << 9,
PKG_CHANGED_SIZE = 1 << 10,
PKG_CHANGED_DEPOT = 1 << 11,
PKG_CHANGED_VERSION = 1 << 12,
PKG_CHANGED_VERSION_CREATE_TIMESTAMP = 1 << 13
PKG_CHANGED_CLASSIFICATION = 1 << 8,
// ^ This covers categories, prominence and is native desktop
PKG_CHANGED_SIZE = 1 << 9,
PKG_CHANGED_DEPOT = 1 << 10,
PKG_CHANGED_VERSION = 1 << 11,
PKG_CHANGED_VERSION_CREATE_TIMESTAMP = 1 << 12
// ...
};

View File

@ -199,8 +199,12 @@ DepotInfo::HasAnyProminentPackages() const
std::vector<PackageInfoRef>::const_iterator it;
for (it = fPackages.begin(); it != fPackages.end(); it++) {
const PackageInfoRef& package = *it;
if (package->IsProminent())
return true;
const PackageClassificationInfoRef& classification = package->PackageClassificationInfo();
if (classification.IsSet()) {
if (classification->IsProminent())
return true;
}
}
return false;
}

View File

@ -0,0 +1,133 @@
/*
* Copyright 2024, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "PackageClassificationInfo.h"
#include <algorithm>
#include "HaikuDepotConstants.h"
PackageClassificationInfo::PackageClassificationInfo()
:
fCategories(),
fProminence(-1L),
fIsNativeDesktop(false)
{
}
PackageClassificationInfo::PackageClassificationInfo(const PackageClassificationInfo& other)
:
fCategories(other.fCategories),
fProminence(other.Prominence()),
fIsNativeDesktop(other.IsNativeDesktop())
{
}
int32
PackageClassificationInfo::CountCategories() const
{
return fCategories.size();
}
CategoryRef
PackageClassificationInfo::CategoryAtIndex(int32 index) const
{
return fCategories[index];
}
void
PackageClassificationInfo::ClearCategories()
{
if (!fCategories.empty())
fCategories.clear();
}
bool
PackageClassificationInfo::AddCategory(const CategoryRef& category)
{
std::vector<CategoryRef>::const_iterator itInsertionPt = std::lower_bound(fCategories.begin(),
fCategories.end(), category, &IsPackageCategoryBefore);
if (itInsertionPt == fCategories.end()) {
fCategories.push_back(category);
return true;
}
return false;
}
bool
PackageClassificationInfo::HasCategoryByCode(const BString& code) const
{
for (int32 i = CountCategories() - 1; i >= 0; i--) {
if (CategoryAtIndex(i)->Code() == code)
return true;
}
return false;
}
void
PackageClassificationInfo::SetProminence(uint32 prominence)
{
fProminence = prominence;
}
bool
PackageClassificationInfo::IsProminent() const
{
return HasProminence() && Prominence() <= PROMINANCE_ORDERING_PROMINENT_MAX;
}
bool
PackageClassificationInfo::IsNativeDesktop() const
{
return fIsNativeDesktop;
}
void
PackageClassificationInfo::SetIsNativeDesktop(bool value)
{
fIsNativeDesktop = value;
}
bool
PackageClassificationInfo::operator==(const PackageClassificationInfo& other) const
{
if (fIsNativeDesktop != other.IsNativeDesktop())
return false;
if (fProminence != other.Prominence())
return false;
if (CountCategories() != other.CountCategories())
return false;
for (int32 i = CountCategories() - 1; i >= 0; i--) {
if (other.CategoryAtIndex(i) != CategoryAtIndex(i))
return false;
}
return true;
}
bool
PackageClassificationInfo::operator!=(const PackageClassificationInfo& other) const
{
return !(*this == other);
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2024, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_CLASSIFICATION_INFO_H
#define PACKAGE_CLASSIFICATION_INFO_H
#include <vector>
#include <Referenceable.h>
#include "PackageCategory.h"
class PackageClassificationInfo : public BReferenceable
{
public:
PackageClassificationInfo();
PackageClassificationInfo(const PackageClassificationInfo& other);
bool operator==(const PackageClassificationInfo& other) const;
bool operator!=(const PackageClassificationInfo& other) const;
void SetProminence(uint32 prominence);
uint32 Prominence() const
{ return fProminence; }
bool HasProminence() const
{ return fProminence != 0; }
bool IsProminent() const;
void ClearCategories();
bool AddCategory(const CategoryRef& category);
int32 CountCategories() const;
CategoryRef CategoryAtIndex(int32 index) const;
bool HasCategoryByCode(const BString& code) const;
bool IsNativeDesktop() const;
void SetIsNativeDesktop(bool value);
private:
std::vector<CategoryRef>
fCategories;
uint32 fProminence;
bool fIsNativeDesktop;
};
typedef BReference<PackageClassificationInfo> PackageClassificationInfoRef;
#endif // PACKAGE_CLASSIFICATION_INFO_H

View File

@ -72,9 +72,9 @@ private:
class CategoryFilter : public PackageFilter {
public:
CategoryFilter(const BString& category)
CategoryFilter(const BString& categoryCode)
:
fCategory(category)
fCategoryCode(categoryCode)
{
}
@ -83,23 +83,21 @@ public:
if (!package.IsSet())
return false;
for (int i = package->CountCategories() - 1; i >= 0; i--) {
const CategoryRef& category = package->CategoryAtIndex(i);
if (!category.IsSet())
continue;
if (category->Code() == fCategory)
return true;
}
return false;
PackageClassificationInfoRef classificationInfo = package->PackageClassificationInfo();
if (!classificationInfo.IsSet())
return false;
return classificationInfo->HasCategoryByCode(CategoryCode());
}
const BString& Category() const
const BString& CategoryCode() const
{
return fCategory;
return fCategoryCode;
}
private:
BString fCategory;
BString fCategoryCode;
};

View File

@ -30,7 +30,7 @@ PackageInfo::PackageInfo()
fFullDescription(),
fHasChangelog(false),
fChangelog(),
fProminence(0),
fPackageClassificationInfo(),
fScreenshotInfos(),
fUserRatingInfo(),
fState(NONE),
@ -60,7 +60,7 @@ PackageInfo::PackageInfo(const BPackageInfo& info)
fFullDescription(info.Description()),
fHasChangelog(false),
fChangelog(),
fProminence(0),
fPackageClassificationInfo(),
fScreenshotInfos(),
fUserRatingInfo(),
fState(NONE),
@ -111,8 +111,7 @@ PackageInfo::PackageInfo(const BString& name, const BPackageVersion& version,
fFullDescription(fullDescription),
fHasChangelog(false),
fChangelog(),
fCategories(),
fProminence(0),
fPackageClassificationInfo(),
fScreenshotInfos(),
fUserRatingInfo(),
fState(NONE),
@ -142,8 +141,7 @@ PackageInfo::PackageInfo(const PackageInfo& other)
fFullDescription(other.fFullDescription),
fHasChangelog(other.fHasChangelog),
fChangelog(other.fChangelog),
fCategories(other.fCategories),
fProminence(other.fProminence),
fPackageClassificationInfo(other.fPackageClassificationInfo),
fScreenshotInfos(other.fScreenshotInfos),
fUserRatingInfo(other.fUserRatingInfo),
fState(other.fState),
@ -175,8 +173,7 @@ PackageInfo::operator=(const PackageInfo& other)
fFullDescription = other.fFullDescription;
fHasChangelog = other.fHasChangelog;
fChangelog = other.fChangelog;
fCategories = other.fCategories;
fProminence = other.fProminence;
fPackageClassificationInfo = other.fPackageClassificationInfo;
fScreenshotInfos = other.fScreenshotInfos;
fUserRatingInfo = other.fUserRatingInfo;
fState = other.fState;
@ -207,8 +204,7 @@ PackageInfo::operator==(const PackageInfo& other) const
&& fFullDescription == other.fFullDescription
&& fHasChangelog == other.fHasChangelog
&& fChangelog == other.fChangelog
&& fCategories == other.fCategories
&& fProminence == other.fProminence
&& fPackageClassificationInfo == other.fPackageClassificationInfo
&& fScreenshotInfos == other.fScreenshotInfos
&& fUserRatingInfo == fUserRatingInfo
&& fState == other.fState
@ -291,49 +287,16 @@ PackageInfo::IsSystemPackage() const
}
int32
PackageInfo::CountCategories() const
{
return fCategories.size();
}
CategoryRef
PackageInfo::CategoryAtIndex(int32 index) const
{
return fCategories[index];
}
void
PackageInfo::ClearCategories()
PackageInfo::SetPackageClassificationInfo(PackageClassificationInfoRef value)
{
if (!fCategories.empty()) {
fCategories.clear();
_NotifyListeners(PKG_CHANGED_CATEGORIES);
if (value != fPackageClassificationInfo) {
fPackageClassificationInfo = value;
_NotifyListeners(PKG_CHANGED_CLASSIFICATION);
}
}
bool
PackageInfo::AddCategory(const CategoryRef& 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;
}
return false;
}
void
PackageInfo::SetSystemDependency(bool isDependency)
{
@ -409,22 +372,8 @@ PackageInfo::SetUserRatingInfo(UserRatingInfoRef value)
}
void
PackageInfo::SetProminence(int64 prominence)
{
if (fProminence != prominence) {
fProminence = prominence;
_NotifyListeners(PKG_CHANGED_PROMINENCE);
}
}
bool
PackageInfo::IsProminent() const
{
return HasProminence() && Prominence() <= PROMINANCE_ORDERING_PROMINENT_MAX;
}
void
PackageInfo::ClearScreenshotInfos()

View File

@ -15,7 +15,7 @@
#include "Language.h"
#include "List.h"
#include "PackageCategory.h"
#include "PackageClassificationInfo.h"
#include "PackageInfoListener.h"
#include "PublisherInfo.h"
#include "ScreenshotInfo.h"
@ -115,21 +115,15 @@ public:
const BString& FileName() const
{ return fFileName; }
void ClearCategories();
bool AddCategory(const CategoryRef& category);
int32 CountCategories() const;
CategoryRef CategoryAtIndex(int32 index) const;
void SetPackageClassificationInfo(
PackageClassificationInfoRef value);
PackageClassificationInfoRef
PackageClassificationInfo() const
{ return fPackageClassificationInfo; }
UserRatingInfoRef UserRatingInfo();
void SetUserRatingInfo(UserRatingInfoRef userRatingInfo);
void SetProminence(int64 prominence);
int64 Prominence() const
{ return fProminence; }
bool HasProminence() const
{ return fProminence != 0; }
bool IsProminent() const;
void ClearScreenshotInfos();
void AddScreenshotInfo(
const ScreenshotInfoRef& info);
@ -174,9 +168,8 @@ private:
BString fFullDescription;
bool fHasChangelog;
BString fChangelog;
std::vector<CategoryRef>
fCategories;
int64 fProminence;
PackageClassificationInfoRef
fPackageClassificationInfo;
std::vector<ScreenshotInfoRef>
fScreenshotInfos;
UserRatingInfoRef fUserRatingInfo;

View File

@ -109,6 +109,9 @@ UserRatingInfo::operator==(const UserRatingInfo& other) const
if (UserRatingsPopulated() != other.UserRatingsPopulated())
return false;
if (CountUserRatings() != other.CountUserRatings())
return false;
for (int32 i = CountUserRatings() - 1; i >= 0; i--) {
if (other.UserRatingAtIndex(i) != UserRatingAtIndex(i))
return false;

View File

@ -93,6 +93,8 @@ PackageFillingPkgListener::ConsumePackage(const PackageInfoRef& package,
package->StartCollatingChanges();
PackageClassificationInfoRef packageClassificationInfo(new PackageClassificationInfo(), true);
if (0 != pkg->CountPkgVersions()) {
// this makes the assumption that the only version will be the
@ -126,7 +128,7 @@ PackageFillingPkgListener::ConsumePackage(const PackageInfoRef& package,
HDERROR("unable to find the category for [%s]",
categoryCode->String());
} else
package->AddCategory(category);
packageClassificationInfo->AddCategory(category);
}
if (!pkg->DerivedRatingIsNull()) {
@ -142,7 +144,10 @@ PackageFillingPkgListener::ConsumePackage(const PackageInfoRef& package,
package->SetHasChangelog(pkg->HasChangelog());
if (!pkg->ProminenceOrderingIsNull())
package->SetProminence(pkg->ProminenceOrdering());
packageClassificationInfo->SetProminence(static_cast<uint32>(pkg->ProminenceOrdering()));
if (!pkg->IsNativeDesktopIsNull())
packageClassificationInfo->SetIsNativeDesktop(pkg->IsNativeDesktop());
int32 countPkgScreenshots = pkg->CountPkgScreenshots();
@ -161,6 +166,8 @@ PackageFillingPkgListener::ConsumePackage(const PackageInfoRef& package,
fCount++;
package->SetPackageClassificationInfo(packageClassificationInfo);
package->EndCollatingChanges();
return !fStoppable->WasStopped();

View File

@ -415,16 +415,31 @@ public:
packageB.
*/
static bool _IsPackageBefore(const PackageInfoRef& packageA,
const PackageInfoRef& packageB)
static bool _IsPackageBefore(const PackageInfoRef& packageA, const PackageInfoRef& packageB)
{
if (!packageA.IsSet() || !packageB.IsSet())
HDFATAL("unexpected NULL reference in a referencable");
int c = _CmpProminences(packageA->Prominence(), packageB->Prominence());
uint32 prominenceA = 0;
uint32 prominenceB = 0;
PackageClassificationInfoRef classificationInfoA = packageA->PackageClassificationInfo();
PackageClassificationInfoRef classificationInfoB = packageB->PackageClassificationInfo();
if (classificationInfoA.IsSet())
prominenceA = classificationInfoA->Prominence();
if (classificationInfoB.IsSet())
prominenceB = classificationInfoB->Prominence();
int c = static_cast<int>(prominenceA) - static_cast<int>(prominenceB);
if (c == 0)
c = packageA->Title().ICompare(packageB->Title());
if (c == 0)
c = packageA->Name().Compare(packageB->Name());
return c < 0;
}

View File

@ -720,7 +720,7 @@ MainWindow::Consume(ProcessCoordinator *item)
void
MainWindow::PackageChanged(const PackageInfoEvent& event)
{
uint32 watchedChanges = PKG_CHANGED_STATE | PKG_CHANGED_PROMINENCE;
uint32 watchedChanges = PKG_CHANGED_STATE | PKG_CHANGED_CLASSIFICATION;
if ((event.Changes() & watchedChanges) != 0) {
PackageInfoRef ref(event.Package());
BMessage message(MSG_PACKAGE_CHANGED);
@ -988,8 +988,13 @@ MainWindow::_AddRemovePackageFromLists(const PackageInfoRef& package)
}
if (matches) {
if (package->IsProminent())
fFeaturedPackagesView->AddPackage(package);
PackageClassificationInfoRef classification = package->PackageClassificationInfo();
if (classification.IsSet()) {
if (classification->IsProminent())
fFeaturedPackagesView->AddPackage(package);
}
fPackageListView->AddPackage(package);
} else {
fFeaturedPackagesView->RemovePackage(package);