HaikuDepot: Refactor for general performance
This commit is a large "big bang" commit of a composite of changes
that would have been challenging to put in place over a PR train.
The changes yield a significant performance improvement in general
but also lay the foundation for being able to make further smaller
gains over time. The changes should also improve stability of the
application. This commit is a high-risk change and would ideally
be coupled with testing.
The key things which have changed in this commit;
- Code reformatting has been applied at the same time.
- Data models are now largely immutable with builder-style
constructors.
- The code base was previously handling locking of data obtained
from the central model manually in many places which was
prone to mistakes. Now accessing data is, from the clients'
perspective, largely lock-free.
- The removal of locks now removes lock-contention in various
areas of the application including startup which helps with
improving performance.
- Repositories of data such as categories and languages are
now also immutable.
- To simplify data immutability, packages' data is stored in the
central model separately from depots' data.
- Large package data mutations are now done in chunks of packages
rather than package-by-package which means reduced messaging
within the application; especially around the GUI.
- The resolution of data / mutations' notifications is larger
so that changes are not being considered on each property of
a package which simplifies the processing logic in a number of
places.
- Package change-notification is driven out of the central model
rather than from each and every package. There is scope for
further simplification in this space.
- Where logic already knows what data is changed, it is able to
control the change-notification process rather than cause a
large number of object-comparisons to be required.
- The data-loaders from the local package manager and from HDS
have been re-written to work with immutable models.
- The icon repositories have been re-written to make a one-time
notification that icons have changed rather than notify for
every package.
- Data updates reflection in the UI has been changed to work in
chunks of packages rather than package by package which
reduces the quantity of UI window-invalidation / redraws and
also reduces the quantity of re-calculation of scrollbars and
other UI elements.
- Some UI elements have their metrics calculated lazily rather
than up-front which yields a significant performance gain.
Change-Id: Iefaf4a137411e379e4c461ebc8c783fd1646bcf4
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9093
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Andrew Lindesay <[email protected]>
This commit is contained in:
@@ -8,7 +8,7 @@ resource app_flags B_SINGLE_LAUNCH;
|
||||
resource app_version {
|
||||
major = 0,
|
||||
middle = 0,
|
||||
minor = 8,
|
||||
minor = 9,
|
||||
|
||||
variety = B_APPV_ALPHA,
|
||||
internal = 1,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2018-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef HAIKU_DEPOT_CONSTANTS_H
|
||||
@@ -118,9 +118,19 @@ enum UserUsageConditionsSelectionMode {
|
||||
// any prominence ordering value greater than this is not prominent.
|
||||
#define PROMINANCE_ORDERING_MAX 1000
|
||||
// this is the highest prominence value possible.
|
||||
#define PROMINANCE_ORDERING_NONE 0
|
||||
|
||||
#define SINGLE_PACKAGE_DEPOT_NAME "__hd_single_pkg_depot"
|
||||
// used as a fake depot name for the case where the application is looking
|
||||
// at a single package based on a file.
|
||||
|
||||
#define SINGLE_PACKAGE_DEPOT_IDENTIFIER "__hd_single_pkg_depot_id_c07fb16620f4"
|
||||
// used as a fake depot name for the case where the application is looking
|
||||
// at a single package based on a file.
|
||||
|
||||
#define LOCAL_DEPOT_IDENTIFIER "__hd_local_depot_id_008922773013"
|
||||
// used as a fake depot identifier that is a placeholder used to convey
|
||||
// packages that are only installed locally and do not exist in a remote
|
||||
// repository.
|
||||
|
||||
#endif // HAIKU_DEPOT_CONSTANTS_H
|
||||
|
||||
@@ -57,6 +57,7 @@ local dumpExportReferenceModelTargetFile =
|
||||
# source directories
|
||||
local sourceDirs =
|
||||
edits_generic
|
||||
icon
|
||||
model
|
||||
packagemanagement
|
||||
packagemodel
|
||||
@@ -124,21 +125,18 @@ local applicationSources =
|
||||
FeaturedPackagesView.cpp
|
||||
FilterView.cpp
|
||||
GeneralContentScrollView.cpp
|
||||
IconTarPtr.cpp
|
||||
IdentityAndAccessUtils.cpp
|
||||
IncrementViewCounterProcess.cpp
|
||||
JobStateListener.cpp
|
||||
JwtTokenHelper.cpp
|
||||
LanguageRepository.cpp
|
||||
LinkView.cpp
|
||||
LinkedBitmapView.cpp
|
||||
Logger.cpp
|
||||
main.cpp
|
||||
MainWindow.cpp
|
||||
MarkupTextView.cpp
|
||||
MessagePackageListener.cpp
|
||||
Model.cpp
|
||||
PackageContentsView.cpp
|
||||
PackageIconTarRepository.cpp
|
||||
PackageInfoListener.cpp
|
||||
PackageInfoView.cpp
|
||||
PackageListView.cpp
|
||||
@@ -165,6 +163,11 @@ local applicationSources =
|
||||
ValidationUtils.cpp
|
||||
WorkStatusView.cpp
|
||||
|
||||
# icon
|
||||
IconTarPtr.cpp
|
||||
PackageIconDefaultRepository.cpp
|
||||
PackageIconTarRepository.cpp
|
||||
|
||||
# packagemanagement
|
||||
AbstractPackageProcess.cpp
|
||||
InstallPackageProcess.cpp
|
||||
@@ -180,17 +183,17 @@ local applicationSources =
|
||||
PackageClassificationInfo.cpp
|
||||
PackageCoreInfo.cpp
|
||||
PackageFilter.cpp
|
||||
PackageFilterModel.cpp
|
||||
PackageFilterSpecification.cpp
|
||||
PackageInfo.cpp
|
||||
PackageLocalInfo.cpp
|
||||
PackageLocalizedText.cpp
|
||||
PackagePublisherInfo.cpp
|
||||
PackageScreenshotInfo.cpp
|
||||
PackageUserRatingInfo.cpp
|
||||
PackageVersion.cpp
|
||||
ScreenshotInfo.cpp
|
||||
UserInfo.cpp
|
||||
UserRating.cpp
|
||||
UserRatingInfo.cpp
|
||||
UserRatingSummary.cpp
|
||||
|
||||
# network + server / local processes
|
||||
@@ -231,7 +234,6 @@ local applicationSources =
|
||||
PackageUtils.cpp
|
||||
StorageUtils.cpp
|
||||
StringUtils.cpp
|
||||
LoggingUrlProtocolListener.cpp
|
||||
|
||||
# package_daemon
|
||||
ProblemWindow.cpp
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# =====================================
|
||||
# Copyright 2017-2023, Andrew Lindesay
|
||||
# Copyright 2017-2025, Andrew Lindesay
|
||||
# Distributed under the terms of the MIT License.
|
||||
# =====================================
|
||||
|
||||
@@ -38,21 +38,21 @@ public:
|
||||
|
||||
void Reset();
|
||||
{{#propertyarray}}{{#property.iscppscalartype}}
|
||||
{{property.cpptype}} {{property.cppname}}();
|
||||
{{property.cpptype}} {{property.cppname}}() const;
|
||||
void Set{{property.cppname}}({{property.cpptype}} value);
|
||||
void Set{{property.cppname}}Null();
|
||||
bool {{property.cppname}}IsNull();
|
||||
bool {{property.cppname}}IsNull() const;
|
||||
{{/property.iscppscalartype}}{{#property.isarray}}
|
||||
void AddTo{{property.cppname}}({{property.items.cpptype}}* value);
|
||||
void Set{{property.cppname}}({{property.cpptype}}* value);
|
||||
int32 Count{{property.cppname}}();
|
||||
{{property.items.cpptype}}* {{property.cppname}}ItemAt(int32 index);
|
||||
bool {{property.cppname}}IsNull();
|
||||
int32 Count{{property.cppname}}() const;
|
||||
{{property.items.cpptype}}* {{property.cppname}}ItemAt(int32 index) const;
|
||||
bool {{property.cppname}}IsNull() const;
|
||||
{{/property.isarray}}{{#property.iscppnonscalarnoncollectiontype}}
|
||||
{{property.cpptype}}* {{property.cppname}}();
|
||||
{{property.cpptype}}* {{property.cppname}}() const;
|
||||
void Set{{property.cppname}}({{property.cpptype}}* value);
|
||||
void Set{{property.cppname}}Null();
|
||||
bool {{property.cppname}}IsNull();
|
||||
bool {{property.cppname}}IsNull() const;
|
||||
{{/property.iscppnonscalarnoncollectiontype}}
|
||||
{{/propertyarray}}
|
||||
|
||||
@@ -112,7 +112,7 @@ void
|
||||
}
|
||||
|
||||
{{#propertyarray}}{{#property.iscppscalartype}}{{property.cpptype}}
|
||||
{{cppobjectname}}::{{property.cppname}}()
|
||||
{{cppobjectname}}::{{property.cppname}}() const
|
||||
{
|
||||
return {{property.cppmembername}};
|
||||
}
|
||||
@@ -135,7 +135,7 @@ void
|
||||
|
||||
|
||||
bool
|
||||
{{cppobjectname}}::{{property.cppname}}IsNull()
|
||||
{{cppobjectname}}::{{property.cppname}}IsNull() const
|
||||
{
|
||||
return 0 == (fHasValueBitmask & k{{property.cppname}}Bitmask);
|
||||
}
|
||||
@@ -160,7 +160,7 @@ void
|
||||
|
||||
|
||||
int32
|
||||
{{cppobjectname}}::Count{{property.cppname}}()
|
||||
{{cppobjectname}}::Count{{property.cppname}}() const
|
||||
{
|
||||
if ({{property.cppmembername}} == NULL)
|
||||
return 0;
|
||||
@@ -169,20 +169,20 @@ int32
|
||||
|
||||
|
||||
{{property.items.cpptype}}*
|
||||
{{cppobjectname}}::{{property.cppname}}ItemAt(int32 index)
|
||||
{{cppobjectname}}::{{property.cppname}}ItemAt(int32 index) const
|
||||
{
|
||||
return {{property.cppmembername}}->ItemAt(index);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
{{cppobjectname}}::{{property.cppname}}IsNull()
|
||||
{{cppobjectname}}::{{property.cppname}}IsNull() const
|
||||
{
|
||||
return {{property.cppmembername}} == NULL;
|
||||
}
|
||||
|
||||
{{/property.isarray}}{{#property.iscppnonscalarnoncollectiontype}}{{property.cpptype}}*
|
||||
{{cppobjectname}}::{{property.cppname}}()
|
||||
{{cppobjectname}}::{{property.cppname}}() const
|
||||
{
|
||||
return {{property.cppmembername}};
|
||||
}
|
||||
@@ -206,7 +206,7 @@ void
|
||||
|
||||
|
||||
bool
|
||||
{{cppobjectname}}::{{property.cppname}}IsNull()
|
||||
{{cppobjectname}}::{{property.cppname}}IsNull() const
|
||||
{
|
||||
return {{property.cppmembername}} == NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "PackageIconDefaultRepository.h"
|
||||
|
||||
|
||||
#include <IconUtils.h>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
static const int32 kCacheLimit = 50;
|
||||
|
||||
|
||||
PackageIconDefaultRepository::PackageIconDefaultRepository()
|
||||
:
|
||||
fVectorData(NULL),
|
||||
fVectorDataSize(0),
|
||||
fCache(kCacheLimit)
|
||||
{
|
||||
_InitDefaultVectorIcon();
|
||||
}
|
||||
|
||||
|
||||
PackageIconDefaultRepository::~PackageIconDefaultRepository()
|
||||
{
|
||||
delete fVectorData;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageIconDefaultRepository::GetIcon(const BString& pkgName, uint32 size,
|
||||
BitmapHolderRef& bitmapHolderRef)
|
||||
{
|
||||
|
||||
if (fVectorData == NULL)
|
||||
return B_NOT_INITIALIZED;
|
||||
|
||||
bitmapHolderRef.Unset();
|
||||
|
||||
status_t status = B_OK;
|
||||
HashString key(BString() << size);
|
||||
|
||||
if (!fCache.ContainsKey(key)) {
|
||||
BBitmap* bitmap = NULL;
|
||||
|
||||
if (status == B_OK) {
|
||||
bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0, B_RGBA32);
|
||||
status = bitmap->InitCheck();
|
||||
}
|
||||
|
||||
if (status == B_OK)
|
||||
status = BIconUtils::GetVectorIcon(fVectorData, fVectorDataSize, bitmap);
|
||||
|
||||
if (status == B_OK) {
|
||||
HDINFO("did create default package icon size %" B_PRId32, size);
|
||||
BitmapHolderRef bitmapHolder(new(std::nothrow) BitmapHolder(bitmap), true);
|
||||
fCache.Put(key, bitmapHolder);
|
||||
} else {
|
||||
delete bitmap;
|
||||
bitmap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == B_OK)
|
||||
bitmapHolderRef.SetTo(fCache.Get(key).Get());
|
||||
else
|
||||
HDERROR("failed to create default package icon size %" B_PRId32, size);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageIconDefaultRepository::_InitDefaultVectorIcon()
|
||||
{
|
||||
if (fVectorData != NULL) {
|
||||
delete fVectorData;
|
||||
fVectorData = NULL;
|
||||
}
|
||||
|
||||
fVectorDataSize = 0;
|
||||
|
||||
BMimeType mimeType("application/x-vnd.haiku-package");
|
||||
status_t status = mimeType.InitCheck();
|
||||
|
||||
if (status != B_OK)
|
||||
return;
|
||||
|
||||
uint8* data;
|
||||
size_t dataSize;
|
||||
|
||||
if (mimeType.GetIcon(&data, &dataSize) != B_OK)
|
||||
debugger("the default icon was unable to be acquired");
|
||||
|
||||
fVectorData = new(std::nothrow) uint8[dataSize];
|
||||
|
||||
if (fVectorData == NULL)
|
||||
HDFATAL("unable to allocate memory for the default icon");
|
||||
|
||||
memcpy(fVectorData, data, dataSize);
|
||||
fVectorDataSize = dataSize;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_ICON_DEFAULT_REPOSITORY_H
|
||||
#define PACKAGE_ICON_DEFAULT_REPOSITORY_H
|
||||
|
||||
|
||||
#include <HashMap.h>
|
||||
#include <HashString.h>
|
||||
|
||||
|
||||
#include "LRUCache.h"
|
||||
#include "PackageIconRepository.h"
|
||||
|
||||
|
||||
class PackageIconDefaultRepository : public PackageIconRepository {
|
||||
public:
|
||||
PackageIconDefaultRepository();
|
||||
virtual ~PackageIconDefaultRepository();
|
||||
|
||||
virtual status_t GetIcon(const BString& pkgName, uint32 size,
|
||||
BitmapHolderRef& bitmapHolderRef);
|
||||
|
||||
private:
|
||||
void _InitDefaultVectorIcon();
|
||||
|
||||
private:
|
||||
uint8* fVectorData;
|
||||
size_t fVectorDataSize;
|
||||
LRUCache<HashString, BitmapHolderRef>
|
||||
fCache;
|
||||
};
|
||||
|
||||
|
||||
#endif // PACKAGE_ICON_DEFAULT_REPOSITORY_H
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2024, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2020-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_ICON_REPOSITORY_H
|
||||
@@ -11,13 +11,14 @@
|
||||
#include "HaikuDepotConstants.h"
|
||||
|
||||
|
||||
class PackageIconRepository {
|
||||
class PackageIconRepository : public BReferenceable {
|
||||
public:
|
||||
virtual bool HasAnyIcon(const BString& pkgName) = 0;
|
||||
virtual status_t GetIcon(const BString& pkgName, uint32 size,
|
||||
BitmapHolderRef& bitmapHolderRef) = 0;
|
||||
virtual void Clear() = 0;
|
||||
};
|
||||
|
||||
|
||||
typedef BReference<PackageIconRepository> PackageIconRepositoryRef;
|
||||
|
||||
|
||||
#endif // PACKAGE_ICON_REPOSITORY_H
|
||||
+44
-144
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* Copyright 2020-2024, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2020-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "PackageIconTarRepository.h"
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <Autolock.h>
|
||||
#include <File.h>
|
||||
#include <IconUtils.h>
|
||||
#include <StopWatch.h>
|
||||
@@ -87,8 +86,7 @@ IconTarPtrEntryListener::Handle(const TarArchiveHeader& header,
|
||||
BString packageName;
|
||||
BString leafName;
|
||||
fileName.CopyInto(packageName, 5, secondSlashIdx - 5);
|
||||
fileName.CopyInto(leafName, secondSlashIdx + 1,
|
||||
fileName.Length() - (secondSlashIdx + 1));
|
||||
fileName.CopyInto(leafName, secondSlashIdx + 1, fileName.Length() - (secondSlashIdx + 1));
|
||||
BitmapSize storedSize;
|
||||
|
||||
if (_LeafNameToBitmapSize(leafName, &storedSize) == B_OK)
|
||||
@@ -121,31 +119,21 @@ IconTarPtrEntryListener::_LeafNameToBitmapSize(BString& leafName, BitmapSize* st
|
||||
}
|
||||
|
||||
|
||||
PackageIconTarRepository::PackageIconTarRepository()
|
||||
PackageIconTarRepository::PackageIconTarRepository(BPath& tarPath)
|
||||
:
|
||||
fTarPath(tarPath),
|
||||
fTarIo(NULL),
|
||||
fIconCache(LIMIT_ICON_CACHE),
|
||||
fDefaultIconVectorData(NULL),
|
||||
fDefaultIconVectorDataSize(0),
|
||||
fDefaultIconCache(LIMIT_ICON_CACHE),
|
||||
fIconDataBuffer(new BMallocIO())
|
||||
fIconDataBuffer(new BMallocIO()),
|
||||
fFallbackRepository(PackageIconDefaultRepository())
|
||||
{
|
||||
_InitDefaultVectorIcon();
|
||||
}
|
||||
|
||||
|
||||
PackageIconTarRepository::~PackageIconTarRepository()
|
||||
{
|
||||
_Close();
|
||||
delete fIconDataBuffer;
|
||||
delete fDefaultIconVectorData;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageIconTarRepository::Clear() {
|
||||
BAutolock locker(&fLock);
|
||||
fIconCache.Clear();
|
||||
fDefaultIconCache.Clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -155,27 +143,25 @@ PackageIconTarRepository::Clear() {
|
||||
*/
|
||||
|
||||
status_t
|
||||
PackageIconTarRepository::Init(BPath& tarPath)
|
||||
PackageIconTarRepository::Init()
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
|
||||
_Close();
|
||||
|
||||
status_t result = B_OK;
|
||||
|
||||
if (tarPath.Path() == NULL) {
|
||||
if (fTarPath.Path() == NULL) {
|
||||
HDINFO("empty path to tar-ball");
|
||||
result = B_BAD_VALUE;
|
||||
}
|
||||
|
||||
BFile *tarIo = NULL;
|
||||
BFile* tarIo = NULL;
|
||||
|
||||
if (result == B_OK) {
|
||||
HDINFO("will init icon model from tar [%s]", tarPath.Path());
|
||||
tarIo = new BFile(tarPath.Path(), O_RDONLY);
|
||||
HDINFO("will init icon model from tar [%s]", fTarPath.Path());
|
||||
tarIo = new BFile(fTarPath.Path(), O_RDONLY);
|
||||
|
||||
if (!tarIo->IsReadable()) {
|
||||
HDERROR("unable to read the tar [%s]", tarPath.Path());
|
||||
HDERROR("unable to read the tar [%s]", fTarPath.Path());
|
||||
result = B_IO_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -184,15 +170,14 @@ PackageIconTarRepository::Init(BPath& tarPath)
|
||||
|
||||
if (result == B_OK) {
|
||||
BStopWatch watch("PackageIconTarRepository::Init", true);
|
||||
HDINFO("will read [%s] and collect the tar pointers", tarPath.Path());
|
||||
HDINFO("will read [%s] and collect the tar pointers", fTarPath.Path());
|
||||
|
||||
IconTarPtrEntryListener* listener = new IconTarPtrEntryListener(this);
|
||||
ObjectDeleter<IconTarPtrEntryListener> listenerDeleter(listener);
|
||||
TarArchiveService::ForEachEntry(*tarIo, listener);
|
||||
|
||||
double secs = watch.ElapsedTime() / 1000000.0;
|
||||
HDINFO("did collect %" B_PRIi32 " tar pointers (%6.3g secs)",
|
||||
fIconTarPtrs.Size(), secs);
|
||||
HDINFO("did collect %" B_PRIi32 " tar pointers (%6.3g secs)", fIconTarPtrs.Size(), secs);
|
||||
}
|
||||
|
||||
if (result == B_OK)
|
||||
@@ -214,14 +199,13 @@ PackageIconTarRepository::_Close()
|
||||
delete fTarIo;
|
||||
fTarIo = NULL;
|
||||
fIconTarPtrs.Clear();
|
||||
fDefaultIconCache.Clear();
|
||||
}
|
||||
|
||||
|
||||
/*! This method should be treated private and only called from a situation
|
||||
in which the class's lock is acquired. It is used to populate data from
|
||||
the parsing of the tar headers. It is called from the listener above.
|
||||
/*! This method is used to populate data from the parsing of the tar headers.
|
||||
It is called from the listener above.
|
||||
*/
|
||||
// TODO; should be friend to the listener
|
||||
void
|
||||
PackageIconTarRepository::AddIconTarPtr(const BString& packageName, BitmapSize storedSize,
|
||||
off_t offset)
|
||||
@@ -231,15 +215,6 @@ PackageIconTarRepository::AddIconTarPtr(const BString& packageName, BitmapSize s
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageIconTarRepository::HasAnyIcon(const BString& pkgName)
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
HashString key(pkgName);
|
||||
return fIconTarPtrs.ContainsKey(key);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageIconTarRepository::GetIcon(const BString& pkgName, uint32 size,
|
||||
BitmapHolderRef& bitmapHolderRef)
|
||||
@@ -250,39 +225,44 @@ PackageIconTarRepository::GetIcon(const BString& pkgName, uint32 size,
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
status_t result = B_OK;
|
||||
bitmapHolderRef.Unset();
|
||||
|
||||
BAutolock locker(&fLock);
|
||||
status_t result = B_OK;
|
||||
off_t iconDataTarOffset = -1;
|
||||
const IconTarPtrRef tarPtrRef = _GetIconTarPtr(pkgName);
|
||||
BitmapSize storedSize;
|
||||
if (fTarIo == NULL) {
|
||||
// get the default icon in this case.
|
||||
HDDEBUG("the tar io was not configured indicating a possible initialization error");
|
||||
} else {
|
||||
off_t iconDataTarOffset = -1;
|
||||
const IconTarPtrRef tarPtrRef = _GetIconTarPtr(pkgName);
|
||||
BitmapSize storedSize;
|
||||
|
||||
if (tarPtrRef.IsSet()) {
|
||||
storedSize = _BestStoredSize(tarPtrRef, size);
|
||||
iconDataTarOffset = tarPtrRef->Offset(storedSize);
|
||||
}
|
||||
if (tarPtrRef.IsSet()) {
|
||||
storedSize = _BestStoredSize(tarPtrRef, size);
|
||||
iconDataTarOffset = tarPtrRef->Offset(storedSize);
|
||||
}
|
||||
|
||||
if (iconDataTarOffset >= 0) {
|
||||
HashString key = _ToIconCacheKey(pkgName, storedSize, size);
|
||||
if (iconDataTarOffset >= 0) {
|
||||
HashString key = _ToIconCacheKey(pkgName, storedSize, size);
|
||||
|
||||
if (fIconCache.ContainsKey(key)) {
|
||||
bitmapHolderRef.SetTo(fIconCache.Get(key).Get());
|
||||
} else {
|
||||
result = _CreateIconFromTarOffset(iconDataTarOffset, storedSize, size, bitmapHolderRef);
|
||||
if (result == B_OK) {
|
||||
HDTRACE("loaded package icon [%s] of size %" B_PRId32, pkgName.String(), size);
|
||||
fIconCache.Put(key, bitmapHolderRef);
|
||||
if (fIconCache.ContainsKey(key)) {
|
||||
bitmapHolderRef.SetTo(fIconCache.Get(key).Get());
|
||||
} else {
|
||||
HDERROR("failure to read image for package [%s] at offset %"
|
||||
B_PRIdOFF, pkgName.String(), iconDataTarOffset);
|
||||
result = _CreateIconFromTarOffset(iconDataTarOffset, storedSize, size,
|
||||
bitmapHolderRef);
|
||||
if (result == B_OK) {
|
||||
HDTRACE("loaded package icon [%s] of size %" B_PRId32, pkgName.String(), size);
|
||||
fIconCache.Put(key, bitmapHolderRef);
|
||||
bitmapHolderRef.SetTo(fIconCache.Get(key).Get());
|
||||
} else {
|
||||
HDERROR("failure to read image for package [%s] at offset %" B_PRIdOFF,
|
||||
pkgName.String(), iconDataTarOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bitmapHolderRef.IsSet())
|
||||
result = _GetDefaultIcon(size, bitmapHolderRef);
|
||||
result = fFallbackRepository.GetIcon(pkgName, size, bitmapHolderRef);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -324,8 +304,6 @@ PackageIconTarRepository::_ToIconCacheKey(const BString& pkgName, BitmapSize sto
|
||||
}
|
||||
|
||||
|
||||
/*! This method must only be invoked with the class locked.
|
||||
*/
|
||||
status_t
|
||||
PackageIconTarRepository::_CreateIconFromTarOffset(off_t offset, BitmapSize storedSize, uint32 size,
|
||||
BitmapHolderRef& bitmapHolderRef)
|
||||
@@ -409,7 +387,6 @@ PackageIconTarRepository::_BestStoredSize(const IconTarPtrRef iconTarPtrRef, int
|
||||
IconTarPtrRef
|
||||
PackageIconTarRepository::_GetOrCreateIconTarPtr(const BString& pkgName)
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
HashString key(pkgName);
|
||||
if (!fIconTarPtrs.ContainsKey(key)) {
|
||||
IconTarPtrRef value(new IconTarPtr(pkgName));
|
||||
@@ -418,80 +395,3 @@ PackageIconTarRepository::_GetOrCreateIconTarPtr(const BString& pkgName)
|
||||
}
|
||||
return fIconTarPtrs.Get(key);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageIconTarRepository::_GetDefaultIcon(uint32 size, BitmapHolderRef& bitmapHolderRef)
|
||||
{
|
||||
if (fDefaultIconVectorData == NULL)
|
||||
return B_NOT_INITIALIZED;
|
||||
|
||||
bitmapHolderRef.Unset();
|
||||
|
||||
status_t status = B_OK;
|
||||
HashString key(BString() << size);
|
||||
|
||||
if (!fDefaultIconCache.ContainsKey(key)) {
|
||||
BBitmap* bitmap = NULL;
|
||||
|
||||
if (status == B_OK) {
|
||||
bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0, B_RGBA32);
|
||||
status = bitmap->InitCheck();
|
||||
}
|
||||
|
||||
if (status == B_OK) {
|
||||
status = BIconUtils::GetVectorIcon(fDefaultIconVectorData, fDefaultIconVectorDataSize,
|
||||
bitmap);
|
||||
}
|
||||
|
||||
if (status == B_OK) {
|
||||
HDINFO("did create default package icon size %" B_PRId32, size);
|
||||
BitmapHolderRef bitmapHolder(new(std::nothrow) BitmapHolder(bitmap), true);
|
||||
fDefaultIconCache.Put(key, bitmapHolder);
|
||||
} else {
|
||||
delete bitmap;
|
||||
bitmap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == B_OK)
|
||||
bitmapHolderRef.SetTo(fDefaultIconCache.Get(key).Get());
|
||||
else
|
||||
HDERROR("failed to create default package icon size %" B_PRId32, size);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageIconTarRepository::_InitDefaultVectorIcon()
|
||||
{
|
||||
if (fDefaultIconVectorData != NULL) {
|
||||
delete fDefaultIconVectorData;
|
||||
fDefaultIconVectorData = NULL;
|
||||
}
|
||||
|
||||
fDefaultIconVectorDataSize = 0;
|
||||
|
||||
BMimeType mimeType("application/x-vnd.haiku-package");
|
||||
status_t status = mimeType.InitCheck();
|
||||
|
||||
uint8* data;
|
||||
size_t dataSize;
|
||||
|
||||
if (status == B_OK)
|
||||
status = mimeType.GetIcon(&data, &dataSize);
|
||||
|
||||
if (status == B_OK) {
|
||||
fDefaultIconVectorData = new(std::nothrow) uint8[dataSize];
|
||||
|
||||
if (fDefaultIconVectorData == NULL)
|
||||
HDFATAL("unable to allocate memory for the default icon");
|
||||
|
||||
memcpy(fDefaultIconVectorData, data, dataSize);
|
||||
fDefaultIconVectorDataSize = dataSize;
|
||||
} else {
|
||||
fDefaultIconVectorData = NULL;
|
||||
fDefaultIconVectorDataSize = 0;
|
||||
}
|
||||
}
|
||||
+8
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2024, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2020-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_ICON_TAR_REPOSITORY_H
|
||||
@@ -9,12 +9,12 @@
|
||||
#include <DataIO.h>
|
||||
#include <HashMap.h>
|
||||
#include <HashString.h>
|
||||
#include <Locker.h>
|
||||
#include <Path.h>
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "IconTarPtr.h"
|
||||
#include "LRUCache.h"
|
||||
#include "PackageIconDefaultRepository.h"
|
||||
#include "PackageIconRepository.h"
|
||||
|
||||
|
||||
@@ -23,17 +23,15 @@ typedef BReference<IconTarPtr> IconTarPtrRef;
|
||||
|
||||
class PackageIconTarRepository : public PackageIconRepository {
|
||||
public:
|
||||
PackageIconTarRepository();
|
||||
PackageIconTarRepository(BPath& tarPath);
|
||||
virtual ~PackageIconTarRepository();
|
||||
|
||||
status_t Init(BPath& tarPath);
|
||||
status_t Init();
|
||||
|
||||
void AddIconTarPtr(const BString& pkgName,
|
||||
BitmapSize size, off_t offset);
|
||||
virtual status_t GetIcon(const BString& pkgName, uint32 size,
|
||||
BitmapHolderRef& bitmapHolderRef);
|
||||
virtual bool HasAnyIcon(const BString& pkgName);
|
||||
virtual void Clear();
|
||||
|
||||
private:
|
||||
void _Close();
|
||||
@@ -48,27 +46,21 @@ private:
|
||||
status_t _CreateIconFromTarOffset(off_t offset, BitmapSize bitmapSize,
|
||||
uint32 size, BitmapHolderRef& bitmapHolderRef);
|
||||
|
||||
status_t _GetDefaultIcon(uint32 size, BitmapHolderRef& bitmapHolderRef);
|
||||
|
||||
static BitmapSize _BestStoredSize(const IconTarPtrRef iconTarPtrRef,
|
||||
int32 desiredSize);
|
||||
|
||||
void _InitDefaultVectorIcon();
|
||||
|
||||
private:
|
||||
BLocker fLock;
|
||||
BPath fTarPath;
|
||||
BPositionIO* fTarIo;
|
||||
LRUCache<HashString, BitmapHolderRef>
|
||||
fIconCache;
|
||||
HashMap<HashString, IconTarPtrRef>
|
||||
fIconTarPtrs;
|
||||
|
||||
uint8* fDefaultIconVectorData;
|
||||
size_t fDefaultIconVectorDataSize;
|
||||
LRUCache<HashString, BitmapHolderRef>
|
||||
fDefaultIconCache;
|
||||
|
||||
BMallocIO* fIconDataBuffer;
|
||||
|
||||
PackageIconDefaultRepository
|
||||
fFallbackRepository;
|
||||
};
|
||||
|
||||
#endif // PACKAGE_ICON_TAR_REPOSITORY_H
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "LanguageRepository.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "HaikuDepotConstants.h"
|
||||
#include "Logger.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
|
||||
LanguageRepository::LanguageRepository()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LanguageRepository::~LanguageRepository()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LanguageRepository::Clear()
|
||||
{
|
||||
fLanguages.clear();
|
||||
HDINFO("did clear the languages");
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
LanguageRepository::IsEmpty() const
|
||||
{
|
||||
return fLanguages.empty();
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
LanguageRepository::CountLanguages() const
|
||||
{
|
||||
return fLanguages.size();
|
||||
}
|
||||
|
||||
|
||||
const LanguageRef
|
||||
LanguageRepository::LanguageAtIndex(int32 index) const
|
||||
{
|
||||
return fLanguages[index];
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LanguageRepository::AddLanguage(const LanguageRef& value)
|
||||
{
|
||||
int32 index = IndexOfLanguage(value->Code(), value->CountryCode(), value->ScriptCode());
|
||||
|
||||
if (-1 == index) {
|
||||
std::vector<LanguageRef>::iterator itInsertionPt
|
||||
= std::lower_bound(fLanguages.begin(), fLanguages.end(), value, &IsLanguageBefore);
|
||||
fLanguages.insert(itInsertionPt, value);
|
||||
HDTRACE("did add the language [%s]", value->ID());
|
||||
} else {
|
||||
fLanguages[index] = value;
|
||||
HDTRACE("did replace the language [%s]", value->ID());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
LanguageRepository::IndexOfLanguage(const char* code, const char* countryCode,
|
||||
const char* scriptCode) const
|
||||
{
|
||||
size_t size = fLanguages.size();
|
||||
for (uint32 i = 0; i < size; i++) {
|
||||
const char* lCode = fLanguages[i]->Code();
|
||||
const char* lCountryCode = fLanguages[i]->CountryCode();
|
||||
const char* lScriptCode = fLanguages[i]->ScriptCode();
|
||||
|
||||
if (0 == StringUtils::NullSafeCompare(code, lCode)
|
||||
&& 0 == StringUtils::NullSafeCompare(countryCode, lCountryCode)
|
||||
&& 0 == StringUtils::NullSafeCompare(scriptCode, lScriptCode)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef LANGUAGE_REPOSITORY_H
|
||||
#define LANGUAGE_REPOSITORY_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Language.h"
|
||||
|
||||
|
||||
class LanguageRepository
|
||||
{
|
||||
public:
|
||||
LanguageRepository();
|
||||
virtual ~LanguageRepository();
|
||||
|
||||
void Clear();
|
||||
bool IsEmpty() const;
|
||||
int32 CountLanguages() const;
|
||||
const LanguageRef LanguageAtIndex(int32 index) const;
|
||||
void AddLanguage(const LanguageRef& value);
|
||||
|
||||
int32 IndexOfLanguage(const char* code, const char* countryCode,
|
||||
const char* scriptCode) const;
|
||||
|
||||
private:
|
||||
std::vector<LanguageRef>
|
||||
fLanguages;
|
||||
};
|
||||
|
||||
|
||||
#endif // LANGUAGE_REPOSITORY_H
|
||||
+415
-299
@@ -1,16 +1,16 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2014, Axel Dörfler <[email protected]>.
|
||||
* Copyright 2016-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "Model.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
#include <vector>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <Autolock.h>
|
||||
@@ -35,11 +35,8 @@
|
||||
#define B_TRANSLATION_CONTEXT "Model"
|
||||
|
||||
|
||||
#define KEY_STORE_IDENTIFIER_PREFIX "hds.password."
|
||||
// this prefix is added before the nickname in the keystore
|
||||
// so that HDS username/password pairs can be identified.
|
||||
|
||||
static const char* kHaikuDepotKeyring = "HaikuDepot";
|
||||
static const uint32 kChangeMaskAll = UINT32_MAX;
|
||||
// covers all of the possible values.
|
||||
|
||||
|
||||
ModelListener::~ModelListener()
|
||||
@@ -56,58 +53,107 @@ Model::Model()
|
||||
fDepots(),
|
||||
fCategories(),
|
||||
fPackageListViewMode(PROMINENT),
|
||||
fCanShareAnonymousUsageData(false)
|
||||
fCanShareAnonymousUsageData(false),
|
||||
fWebApp(WebAppInterfaceRef(new WebAppInterface(UserCredentials()), true)),
|
||||
fLanguages(LocaleUtils::WellKnownLanguages())
|
||||
{
|
||||
fIconRepository = PackageIconRepositoryRef(new PackageIconDefaultRepository(), true);
|
||||
|
||||
// setup the language into a default state with a hard-coded language so
|
||||
// that there is a language at all.
|
||||
fLanguageRepository = new LanguageRepository();
|
||||
fLanguageRepository->AddLanguage(fPreferredLanguage);
|
||||
fFilterSpecification = PackageFilterSpecificationBuilder().BuildRef();
|
||||
fFilter = PackageFilterFactory::CreateFilter(fFilterSpecification);
|
||||
|
||||
fPackageFilterModel = new PackageFilterModel();
|
||||
fPackageScreenshotRepository = new PackageScreenshotRepository(
|
||||
PackageScreenshotRepositoryListenerRef(this),
|
||||
&fWebAppInterface);
|
||||
fPackageScreenshotRepository
|
||||
= new PackageScreenshotRepository(PackageScreenshotRepositoryListenerRef(this), this);
|
||||
}
|
||||
|
||||
|
||||
Model::~Model()
|
||||
{
|
||||
delete fPackageFilterModel;
|
||||
delete fPackageScreenshotRepository;
|
||||
delete fLanguageRepository;
|
||||
}
|
||||
|
||||
|
||||
LanguageRepository*
|
||||
Model::Languages()
|
||||
const std::vector<LanguageRef>
|
||||
Model::Languages() const
|
||||
{
|
||||
return fLanguageRepository;
|
||||
BAutolock locker(&fLock);
|
||||
return fLanguages;
|
||||
}
|
||||
|
||||
|
||||
PackageFilterModel*
|
||||
Model::PackageFilter()
|
||||
void
|
||||
Model::SetLanguagesAndPreferred(const std::vector<LanguageRef>& value, const LanguageRef& preferred)
|
||||
{
|
||||
return fPackageFilterModel;
|
||||
if (value.empty())
|
||||
HDFATAL("unable to set the languages to an empty list");
|
||||
|
||||
if (std::find(value.begin(), value.end(), preferred) == value.end())
|
||||
HDFATAL("the preferred language is not in the list of languages");
|
||||
|
||||
BAutolock locker(&fLock);
|
||||
fLanguages = value;
|
||||
std::sort(fLanguages.begin(), fLanguages.end(), IsLanguageRefLess);
|
||||
SetPreferredLanguage(preferred);
|
||||
|
||||
HDINFO("did configure %" B_PRIu32 " languages with default [%s]",
|
||||
static_cast<uint32>(fLanguages.size()), preferred->ID());
|
||||
}
|
||||
|
||||
|
||||
PackageIconRepository&
|
||||
Model::GetPackageIconRepository()
|
||||
void
|
||||
Model::SetFilterSpecification(const PackageFilterSpecificationRef& value)
|
||||
{
|
||||
return fPackageIconRepository;
|
||||
BAutolock locker(&fLock);
|
||||
if (value != fFilterSpecification) {
|
||||
fFilterSpecification = value;
|
||||
fFilter = PackageFilterFactory::CreateFilter(value);
|
||||
_NotifyPackageFilterChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Model::InitPackageIconRepository()
|
||||
const PackageFilterSpecificationRef
|
||||
Model::FilterSpecification() const
|
||||
{
|
||||
BPath tarPath;
|
||||
status_t result = StorageUtils::IconTarPath(tarPath);
|
||||
if (result == B_OK)
|
||||
result = fPackageIconRepository.Init(tarPath);
|
||||
return result;
|
||||
BAutolock locker(&fLock);
|
||||
return fFilterSpecification;
|
||||
}
|
||||
|
||||
|
||||
PackageFilterRef
|
||||
Model::Filter() const
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
return fFilter;
|
||||
}
|
||||
|
||||
|
||||
PackageIconRepositoryRef
|
||||
Model::IconRepository()
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
return fIconRepository;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::SetIconRepository(PackageIconRepositoryRef value)
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
fIconRepository = value;
|
||||
_NotifyIconsChanged();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::_NotifyIconsChanged()
|
||||
{
|
||||
std::vector<ModelListenerRef>::const_iterator it;
|
||||
for (it = fListeners.begin(); it != fListeners.end(); it++) {
|
||||
const ModelListenerRef& listener = *it;
|
||||
if (listener.IsSet())
|
||||
listener->IconsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,101 +171,286 @@ Model::AddListener(const ModelListenerRef& listener)
|
||||
}
|
||||
|
||||
|
||||
LanguageRef
|
||||
void
|
||||
Model::AddPackageListener(const PackageInfoListenerRef& packageListener)
|
||||
{
|
||||
fPackageListeners.push_back(packageListener);
|
||||
}
|
||||
|
||||
|
||||
/*! This method will take the event info data stored in the supplied message
|
||||
and turn it back into an instance of `PackageInfoEvents`. It is done in
|
||||
this way because the lookup of the packages within each `PackageInfoEvent`
|
||||
has to come from the model.
|
||||
*/
|
||||
status_t
|
||||
Model::DearchiveInfoEvents(const BMessage* message, PackageInfoEvents& packageInfoEvents) const
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
int32 i = 0;
|
||||
BMessage eventMessage;
|
||||
BString packageName;
|
||||
uint32 changeMask;
|
||||
|
||||
while (message->FindMessage(kPackageInfoEventsKey, i, &eventMessage) == B_OK) {
|
||||
status_t result = B_OK;
|
||||
|
||||
if (result == B_OK)
|
||||
result = eventMessage.FindString(kPackageInfoPackageNameKey, &packageName);
|
||||
|
||||
if (result == B_OK)
|
||||
result = eventMessage.FindUInt32(kPackageInfoChangesKey, &changeMask);
|
||||
|
||||
if (result == B_OK) {
|
||||
PackageInfoRef package = PackageForName(packageName);
|
||||
|
||||
if (package.IsSet()) {
|
||||
PackageInfoEvent event(package, changeMask);
|
||||
packageInfoEvents.AddEvent(event);
|
||||
}
|
||||
} else {
|
||||
HDFATAL("broken event info found processing events");
|
||||
// should not occur as the data assembly is entirely inside the application
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
const LanguageRef
|
||||
Model::PreferredLanguage() const
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
return fPreferredLanguage;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::SetPreferredLanguage(LanguageRef value)
|
||||
Model::SetPreferredLanguage(const LanguageRef& value)
|
||||
{
|
||||
if (value.IsSet()) {
|
||||
if (fPreferredLanguage != value)
|
||||
fPreferredLanguage = value;
|
||||
BAutolock locker(&fLock);
|
||||
fPreferredLanguage = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO; part of a wider change; cope with the package being in more than one
|
||||
// depot
|
||||
PackageInfoRef
|
||||
Model::PackageForName(const BString& name)
|
||||
{
|
||||
std::vector<DepotInfoRef>::iterator it;
|
||||
for (it = fDepots.begin(); it != fDepots.end(); it++) {
|
||||
DepotInfoRef depotInfoRef = *it;
|
||||
PackageInfoRef packageInfoRef = depotInfoRef->PackageByName(name);
|
||||
if (packageInfoRef.Get() != NULL)
|
||||
return packageInfoRef;
|
||||
}
|
||||
return PackageInfoRef();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::MergeOrAddDepot(const DepotInfoRef& depot)
|
||||
Model::SetDepots(const DepotInfoRef& depot)
|
||||
{
|
||||
BString depotName = depot->Name();
|
||||
for(uint32 i = 0; i < fDepots.size(); i++) {
|
||||
if (fDepots[i]->Name() == depotName) {
|
||||
DepotInfoRef ersatzDepot(new DepotInfo(*(fDepots[i].Get())), true);
|
||||
ersatzDepot->SyncPackagesFromDepot(depot);
|
||||
fDepots[i] = ersatzDepot;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fDepots.push_back(depot);
|
||||
BAutolock locker(&fLock);
|
||||
std::vector<DepotInfoRef> depots;
|
||||
depots.push_back(depot);
|
||||
SetDepots(depots);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Model::HasDepot(const BString& name) const
|
||||
void
|
||||
Model::SetDepots(const std::vector<DepotInfoRef>& depots)
|
||||
{
|
||||
return NULL != DepotForName(name).Get();
|
||||
BAutolock locker(&fLock);
|
||||
fDepots.clear();
|
||||
|
||||
std::vector<DepotInfoRef>::const_iterator it;
|
||||
|
||||
for (it = depots.begin(); it != depots.end(); it++) {
|
||||
DepotInfoRef depot = *it;
|
||||
|
||||
if (!depot.IsSet()) {
|
||||
HDFATAL("attempt to add an unset depot");
|
||||
} else {
|
||||
if (depot->Name().IsEmpty())
|
||||
HDFATAL("depot has no name");
|
||||
|
||||
if (depot->Identifier().IsEmpty())
|
||||
HDFATAL("depot has no identifier");
|
||||
|
||||
fDepots[depot->Name()] = depot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const std::vector<DepotInfoRef>
|
||||
Model::Depots() const
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
std::vector<DepotInfoRef> result;
|
||||
std::map<BString, DepotInfoRef>::const_iterator it;
|
||||
|
||||
for (it = fDepots.begin(); it != fDepots.end(); it++)
|
||||
result.push_back(it->second);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const DepotInfoRef
|
||||
Model::DepotForName(const BString& name) const
|
||||
{
|
||||
if (name.IsEmpty())
|
||||
return DepotInfoRef();
|
||||
|
||||
std::vector<DepotInfoRef>::const_iterator it;
|
||||
for (it = fDepots.begin(); it != fDepots.end(); it++) {
|
||||
DepotInfoRef aDepot = *it;
|
||||
if (aDepot->Name() == name)
|
||||
return aDepot;
|
||||
}
|
||||
BAutolock locker(&fLock);
|
||||
std::map<BString, DepotInfoRef>::const_iterator it = fDepots.find(name);
|
||||
if (it != fDepots.end())
|
||||
return it->second;
|
||||
return DepotInfoRef();
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
Model::CountDepots() const
|
||||
const DepotInfoRef
|
||||
Model::DepotForIdentifier(const BString& identifier) const
|
||||
{
|
||||
return fDepots.size();
|
||||
BAutolock locker(&fLock);
|
||||
std::map<BString, DepotInfoRef>::const_iterator it;
|
||||
|
||||
for (it = fDepots.begin(); it != fDepots.end(); it++) {
|
||||
if (it->second->Identifier() == identifier)
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return DepotInfoRef();
|
||||
}
|
||||
|
||||
|
||||
DepotInfoRef
|
||||
Model::DepotAtIndex(int32 index) const
|
||||
const std::vector<PackageInfoRef>
|
||||
Model::FilteredPackages() const
|
||||
{
|
||||
return fDepots[index];
|
||||
BAutolock locker(&fLock);
|
||||
std::map<BString, PackageInfoRef>::const_iterator it;
|
||||
std::vector<PackageInfoRef> result;
|
||||
|
||||
for (it = fPackages.begin(); it != fPackages.end(); it++) {
|
||||
PackageInfoRef package = it->second;
|
||||
if (fFilter->AcceptsPackage(package))
|
||||
result.push_back(package);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<PackageInfoRef>
|
||||
Model::Packages() const
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
std::map<BString, PackageInfoRef>::const_iterator it;
|
||||
std::vector<PackageInfoRef> result;
|
||||
|
||||
for (it = fPackages.begin(); it != fPackages.end(); it++)
|
||||
result.push_back(it->second);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
Model::_ChangeDiff(const PackageInfoRef& package)
|
||||
{
|
||||
uint32 changeMask = kChangeMaskAll;
|
||||
const PackageInfoRef existingPackage = PackageForName(package->Name());
|
||||
|
||||
if (existingPackage.IsSet())
|
||||
changeMask = package->ChangeMask(*(existingPackage.Get()));
|
||||
|
||||
return changeMask;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::AddPackage(const PackageInfoRef& package)
|
||||
{
|
||||
if (!package.IsSet())
|
||||
HDFATAL("attempt to add an unset package");
|
||||
BAutolock locker(&fLock);
|
||||
uint32 changeMask = _ChangeDiff(package);
|
||||
fPackages[package->Name()] = package;
|
||||
_NotifyPackageChange(PackageInfoEvent(package, changeMask));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::AddPackages(const std::vector<PackageInfoRef>& packages)
|
||||
{
|
||||
if (packages.empty())
|
||||
return;
|
||||
|
||||
BAutolock locker(&fLock);
|
||||
PackageInfoEvents events;
|
||||
std::vector<PackageInfoRef>::const_iterator it;
|
||||
|
||||
for (it = packages.begin(); it != packages.end(); it++) {
|
||||
PackageInfoRef package = *it;
|
||||
events.AddEvent(PackageInfoEvent(package, _ChangeDiff(package)));
|
||||
fPackages[package->Name()] = package;
|
||||
}
|
||||
|
||||
_NotifyPackageChanges(events);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::AddPackagesWithChange(const std::vector<PackageInfoRef>& packages, uint32 changeMask)
|
||||
{
|
||||
if (packages.empty())
|
||||
return;
|
||||
|
||||
BAutolock locker(&fLock);
|
||||
PackageInfoEvents events;
|
||||
|
||||
std::vector<PackageInfoRef>::const_iterator it;
|
||||
for (it = packages.begin(); it != packages.end(); it++) {
|
||||
PackageInfoRef package = *it;
|
||||
events.AddEvent(PackageInfoEvent(package, changeMask));
|
||||
fPackages[package->Name()] = package;
|
||||
}
|
||||
|
||||
_NotifyPackageChanges(events);
|
||||
}
|
||||
|
||||
|
||||
const PackageInfoRef
|
||||
Model::PackageForName(const BString& name) const
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
std::map<BString, PackageInfoRef>::const_iterator it = fPackages.find(name);
|
||||
if (it != fPackages.end())
|
||||
return it->second;
|
||||
return PackageInfoRef();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Model::HasPackage(const BString& packageName) const
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
if (fPackages.find(packageName) != fPackages.end())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Model::HasAnyProminentPackages()
|
||||
{
|
||||
std::vector<DepotInfoRef>::iterator it;
|
||||
for (it = fDepots.begin(); it != fDepots.end(); it++) {
|
||||
DepotInfoRef aDepot = *it;
|
||||
if (aDepot->HasAnyProminentPackages())
|
||||
return true;
|
||||
BAutolock locker(&fLock);
|
||||
std::map<BString, PackageInfoRef>::iterator it;
|
||||
|
||||
for (it = fPackages.begin(); it != fPackages.end(); it++) {
|
||||
const PackageInfoRef package = it->second;
|
||||
|
||||
if (package.IsSet()) {
|
||||
const PackageClassificationInfoRef classificationInfo
|
||||
= package->PackageClassificationInfo();
|
||||
|
||||
if (classificationInfo.IsSet()) {
|
||||
if (classificationInfo->IsProminent())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -227,47 +458,41 @@ Model::HasAnyProminentPackages()
|
||||
void
|
||||
Model::Clear()
|
||||
{
|
||||
GetPackageIconRepository().Clear();
|
||||
BAutolock locker(&fLock);
|
||||
fIconRepository = PackageIconRepositoryRef(new PackageIconDefaultRepository(), true);
|
||||
fDepots.clear();
|
||||
fPopulatedPackageNames.MakeEmpty();
|
||||
fPackages.clear();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::SetStateForPackagesByName(BStringList& packageNames, PackageState state)
|
||||
package_list_view_mode
|
||||
Model::PackageListViewMode() const
|
||||
{
|
||||
for (int32 i = 0; i < packageNames.CountStrings(); i++) {
|
||||
BString packageName = packageNames.StringAt(i);
|
||||
PackageInfoRef packageInfo = PackageForName(packageName);
|
||||
|
||||
if (packageInfo.IsSet()) {
|
||||
// TODO; make this immutable
|
||||
|
||||
PackageLocalInfoRef localInfo = PackageUtils::NewLocalInfo(packageInfo);
|
||||
localInfo->SetState(state);
|
||||
packageInfo->SetLocalInfo(localInfo);
|
||||
|
||||
HDINFO("did update package [%s] with state [%s]", packageName.String(),
|
||||
PackageUtils::StateToString(state));
|
||||
}
|
||||
else {
|
||||
HDINFO("was unable to find package [%s] so was not possible to set the state to [%s]",
|
||||
packageName.String(), PackageUtils::StateToString(state));
|
||||
}
|
||||
}
|
||||
BAutolock locker(&fLock);
|
||||
return fPackageListViewMode;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::SetPackageListViewMode(package_list_view_mode mode)
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
fPackageListViewMode = mode;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Model::CanShareAnonymousUsageData() const
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
return fCanShareAnonymousUsageData;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::SetCanShareAnonymousUsageData(bool value)
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
fCanShareAnonymousUsageData = value;
|
||||
}
|
||||
|
||||
@@ -293,104 +518,29 @@ Model::CanPopulatePackage(const PackageInfoRef& package)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
model_remove_key_for_user(const BString& nickname)
|
||||
WebAppInterfaceRef
|
||||
Model::WebApp()
|
||||
{
|
||||
if (nickname.IsEmpty())
|
||||
return;
|
||||
BKeyStore keyStore;
|
||||
BPasswordKey key;
|
||||
BString passwordIdentifier = BString(KEY_STORE_IDENTIFIER_PREFIX)
|
||||
<< nickname;
|
||||
status_t result = keyStore.GetKey(kHaikuDepotKeyring, B_KEY_TYPE_PASSWORD,
|
||||
passwordIdentifier, key);
|
||||
|
||||
switch (result) {
|
||||
case B_OK:
|
||||
result = keyStore.RemoveKey(kHaikuDepotKeyring, key);
|
||||
if (result != B_OK) {
|
||||
HDERROR("error occurred when removing password for nickname "
|
||||
"[%s] : %s", nickname.String(), strerror(result));
|
||||
}
|
||||
break;
|
||||
case B_ENTRY_NOT_FOUND:
|
||||
return;
|
||||
default:
|
||||
HDERROR("error occurred when finding password for nickname "
|
||||
"[%s] : %s", nickname.String(), strerror(result));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::SetNickname(BString nickname)
|
||||
{
|
||||
BString password;
|
||||
BString existingNickname = Nickname();
|
||||
|
||||
// this happens when the user is logging out. Best to remove the password
|
||||
// stored for the existing user since it is no longer required.
|
||||
|
||||
if (!existingNickname.IsEmpty() && nickname.IsEmpty())
|
||||
model_remove_key_for_user(existingNickname);
|
||||
|
||||
if (nickname.Length() > 0) {
|
||||
BPasswordKey key;
|
||||
BKeyStore keyStore;
|
||||
BString passwordIdentifier = BString(KEY_STORE_IDENTIFIER_PREFIX)
|
||||
<< nickname;
|
||||
if (keyStore.GetKey(kHaikuDepotKeyring, B_KEY_TYPE_PASSWORD,
|
||||
passwordIdentifier, key) == B_OK) {
|
||||
password = key.Password();
|
||||
}
|
||||
if (password.IsEmpty())
|
||||
nickname = "";
|
||||
}
|
||||
|
||||
SetCredentials(nickname, password, false);
|
||||
BAutolock locker(&fLock);
|
||||
return fWebApp;
|
||||
}
|
||||
|
||||
|
||||
const BString&
|
||||
Model::Nickname()
|
||||
{
|
||||
return fWebAppInterface.Nickname();
|
||||
BAutolock locker(&fLock);
|
||||
return fWebApp->Nickname();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::SetCredentials(const BString& nickname, const BString& passwordClear,
|
||||
bool storePassword)
|
||||
Model::SetCredentials(const UserCredentials& credentials)
|
||||
{
|
||||
BString existingNickname = Nickname();
|
||||
|
||||
if (storePassword) {
|
||||
// no point continuing to store the password for the previous user.
|
||||
|
||||
if (!existingNickname.IsEmpty())
|
||||
model_remove_key_for_user(existingNickname);
|
||||
|
||||
// adding a key that is already there does not seem to override the
|
||||
// existing key so the old key needs to be removed first.
|
||||
|
||||
if (!nickname.IsEmpty())
|
||||
model_remove_key_for_user(nickname);
|
||||
|
||||
if (!nickname.IsEmpty() && !passwordClear.IsEmpty()) {
|
||||
BString keyIdentifier = BString(KEY_STORE_IDENTIFIER_PREFIX)
|
||||
<< nickname;
|
||||
BPasswordKey key(passwordClear, B_KEY_PURPOSE_WEB, keyIdentifier);
|
||||
BKeyStore keyStore;
|
||||
keyStore.AddKeyring(kHaikuDepotKeyring);
|
||||
keyStore.AddKey(kHaikuDepotKeyring, key);
|
||||
}
|
||||
}
|
||||
|
||||
BAutolock locker(&fLock);
|
||||
fWebAppInterface.SetCredentials(UserCredentials(nickname, passwordClear));
|
||||
|
||||
if (nickname != existingNickname)
|
||||
const BString existingNickname = Nickname();
|
||||
fWebApp = WebAppInterfaceRef(new WebAppInterface(credentials));
|
||||
if (credentials.Nickname() != existingNickname)
|
||||
_NotifyAuthorizationChanged();
|
||||
}
|
||||
|
||||
@@ -398,6 +548,22 @@ Model::SetCredentials(const BString& nickname, const BString& passwordClear,
|
||||
// #pragma mark - listener notification methods
|
||||
|
||||
|
||||
/*! Assumes that the class is locked.
|
||||
*/
|
||||
void
|
||||
Model::_NotifyPackageFilterChanged()
|
||||
{
|
||||
std::vector<ModelListenerRef>::const_iterator it;
|
||||
for (it = fListeners.begin(); it != fListeners.end(); it++) {
|
||||
const ModelListenerRef& listener = *it;
|
||||
if (listener.IsSet())
|
||||
listener->PackageFilterChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! Assumes that the class is locked.
|
||||
*/
|
||||
void
|
||||
Model::_NotifyAuthorizationChanged()
|
||||
{
|
||||
@@ -423,8 +589,35 @@ Model::_NotifyCategoryListChanged()
|
||||
|
||||
|
||||
void
|
||||
Model::_MaybeLogJsonRpcError(const BMessage &responsePayload,
|
||||
const char *sourceDescription) const
|
||||
Model::_NotifyPackageChange(const PackageInfoEvent& event)
|
||||
{
|
||||
std::vector<PackageInfoListenerRef>::const_iterator it;
|
||||
for (it = fPackageListeners.begin(); it != fPackageListeners.end(); it++) {
|
||||
const PackageInfoListenerRef& listener = *it;
|
||||
if (listener.IsSet())
|
||||
listener->PackagesChanged(PackageInfoEvents(event));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: future work to optimize how this is conveyed to the listener in one go.
|
||||
void
|
||||
Model::_NotifyPackageChanges(const PackageInfoEvents& events)
|
||||
{
|
||||
if (events.IsEmpty())
|
||||
return;
|
||||
|
||||
std::vector<PackageInfoListenerRef>::const_iterator it;
|
||||
for (it = fPackageListeners.begin(); it != fPackageListeners.end(); it++) {
|
||||
const PackageInfoListenerRef& listener = *it;
|
||||
if (listener.IsSet())
|
||||
listener->PackagesChanged(events);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::_MaybeLogJsonRpcError(const BMessage& responsePayload, const char* sourceDescription) const
|
||||
{
|
||||
BMessage error;
|
||||
BString errorMessage;
|
||||
@@ -433,143 +626,66 @@ Model::_MaybeLogJsonRpcError(const BMessage &responsePayload,
|
||||
if (responsePayload.FindMessage("error", &error) == B_OK
|
||||
&& error.FindString("message", &errorMessage) == B_OK
|
||||
&& error.FindDouble("code", &errorCode) == B_OK) {
|
||||
HDERROR("[%s] --> error : [%s] (%f)", sourceDescription,
|
||||
errorMessage.String(), errorCode);
|
||||
} else
|
||||
HDERROR("[%s] --> error : [%s] (%f)", sourceDescription, errorMessage.String(), errorCode);
|
||||
} else {
|
||||
HDERROR("[%s] --> an undefined error has occurred", sourceDescription);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Rating Stabilities
|
||||
|
||||
|
||||
int32
|
||||
Model::CountRatingStabilities() const
|
||||
const std::vector<RatingStabilityRef>
|
||||
Model::RatingStabilities() const
|
||||
{
|
||||
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];
|
||||
BAutolock locker(&fLock);
|
||||
return fRatingStabilities;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::AddRatingStabilities(std::vector<RatingStabilityRef>& values)
|
||||
Model::SetRatingStabilities(const std::vector<RatingStabilityRef> value)
|
||||
{
|
||||
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 itInsertionPtConst
|
||||
= std::lower_bound(
|
||||
fRatingStabilities.begin(),
|
||||
fRatingStabilities.end(),
|
||||
value,
|
||||
&IsRatingStabilityBefore);
|
||||
std::vector<RatingStabilityRef>::iterator itInsertionPt =
|
||||
fRatingStabilities.begin()
|
||||
+ (itInsertionPtConst - fRatingStabilities.begin());
|
||||
|
||||
if (itInsertionPt != fRatingStabilities.end()
|
||||
&& (*itInsertionPt)->Code() == value->Code()) {
|
||||
itInsertionPt = fRatingStabilities.erase(itInsertionPt);
|
||||
// replace the one with the same code.
|
||||
}
|
||||
|
||||
fRatingStabilities.insert(itInsertionPt, value);
|
||||
BAutolock locker(&fLock);
|
||||
fRatingStabilities = value;
|
||||
std::sort(fRatingStabilities.begin(), fRatingStabilities.end(), IsRatingStabilityRefLess);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Categories
|
||||
|
||||
|
||||
int32
|
||||
Model::CountCategories() const
|
||||
bool
|
||||
Model::HasCategories()
|
||||
{
|
||||
return fCategories.size();
|
||||
BAutolock locker(&fLock);
|
||||
return !fCategories.empty();
|
||||
}
|
||||
|
||||
|
||||
CategoryRef
|
||||
Model::CategoryByCode(BString& code) const
|
||||
const std::vector<CategoryRef>
|
||||
Model::Categories() 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];
|
||||
BAutolock locker(&fLock);
|
||||
return fCategories;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::AddCategories(std::vector<CategoryRef>& values)
|
||||
Model::SetCategories(const std::vector<CategoryRef> value)
|
||||
{
|
||||
std::vector<CategoryRef>::iterator it;
|
||||
for (it = values.begin(); it != values.end(); it++)
|
||||
_AddCategory(*it);
|
||||
BAutolock locker(&fLock);
|
||||
fCategories = value;
|
||||
std::sort(fCategories.begin(), fCategories.end(), IsPackageCategoryRefLess);
|
||||
_NotifyCategoryListChanged();
|
||||
}
|
||||
|
||||
/*! This will insert the category in order.
|
||||
*/
|
||||
|
||||
void
|
||||
Model::_AddCategory(const CategoryRef& category)
|
||||
{
|
||||
std::vector<CategoryRef>::const_iterator itInsertionPtConst
|
||||
= std::lower_bound(
|
||||
fCategories.begin(),
|
||||
fCategories.end(),
|
||||
category,
|
||||
&IsPackageCategoryBefore);
|
||||
std::vector<CategoryRef>::iterator itInsertionPt =
|
||||
fCategories.begin() + (itInsertionPtConst - fCategories.begin());
|
||||
|
||||
if (itInsertionPt != fCategories.end()
|
||||
&& (*itInsertionPt)->Code() == category->Code()) {
|
||||
itInsertionPt = fCategories.erase(itInsertionPt);
|
||||
// replace the one with the same code.
|
||||
}
|
||||
|
||||
fCategories.insert(itInsertionPt, category);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::ScreenshotCached(const ScreenshotCoordinate& coord)
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
std::vector<ModelListenerRef>::const_iterator it;
|
||||
for (it = fListeners.begin(); it != fListeners.end(); it++) {
|
||||
const ModelListenerRef& listener = *it;
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2016-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef MODEL_H
|
||||
#define MODEL_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <Locker.h>
|
||||
|
||||
#include "AbstractProcess.h"
|
||||
#include "DepotInfo.h"
|
||||
#include "LanguageRepository.h"
|
||||
#include "PackageFilterModel.h"
|
||||
#include "PackageIconTarRepository.h"
|
||||
#include "PackageFilter.h"
|
||||
#include "PackageFilterSpecification.h"
|
||||
#include "PackageIconDefaultRepository.h"
|
||||
#include "PackageInfo.h"
|
||||
#include "PackageInfoListener.h"
|
||||
#include "PackageScreenshotRepository.h"
|
||||
#include "RatingStability.h"
|
||||
#include "ScreenshotCoordinate.h"
|
||||
@@ -40,6 +42,8 @@ public:
|
||||
virtual void AuthorizationChanged() = 0;
|
||||
virtual void CategoryListChanged() = 0;
|
||||
virtual void ScreenshotCached(const ScreenshotCoordinate& coordinate) = 0;
|
||||
virtual void IconsChanged() = 0;
|
||||
virtual void PackageFilterChanged() = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -59,77 +63,82 @@ public:
|
||||
Model();
|
||||
virtual ~Model();
|
||||
|
||||
PackageFilterModel* PackageFilter();
|
||||
PackageIconRepository&
|
||||
GetPackageIconRepository();
|
||||
status_t InitPackageIconRepository();
|
||||
void Clear();
|
||||
|
||||
void AddListener(const ModelListenerRef& listener);
|
||||
void AddPackageListener(const PackageInfoListenerRef& packageListener);
|
||||
|
||||
status_t DearchiveInfoEvents(const BMessage* message,
|
||||
PackageInfoEvents& packageInfoEvents) const;
|
||||
|
||||
PackageScreenshotRepository*
|
||||
GetPackageScreenshotRepository();
|
||||
|
||||
BLocker* Lock()
|
||||
{ return &fLock; }
|
||||
void SetFilterSpecification(const PackageFilterSpecificationRef& value);
|
||||
const PackageFilterSpecificationRef
|
||||
FilterSpecification() const;
|
||||
PackageFilterRef Filter() const;
|
||||
|
||||
void AddListener(const ModelListenerRef& listener);
|
||||
PackageIconRepositoryRef
|
||||
IconRepository();
|
||||
void SetIconRepository(PackageIconRepositoryRef value);
|
||||
|
||||
LanguageRef PreferredLanguage() const;
|
||||
void SetPreferredLanguage(LanguageRef value);
|
||||
LanguageRepository* Languages();
|
||||
|
||||
PackageInfoRef PackageForName(const BString& name);
|
||||
|
||||
void MergeOrAddDepot(const DepotInfoRef& depot);
|
||||
bool HasDepot(const BString& name) const;
|
||||
int32 CountDepots() const;
|
||||
DepotInfoRef DepotAtIndex(int32 index) const;
|
||||
const DepotInfoRef DepotForName(const BString& name) const;
|
||||
const std::vector<PackageInfoRef>
|
||||
Packages() const;
|
||||
const std::vector<PackageInfoRef>
|
||||
FilteredPackages() const;
|
||||
void AddPackage(const PackageInfoRef& package);
|
||||
void AddPackages(const std::vector<PackageInfoRef>& packages);
|
||||
void AddPackagesWithChange(const std::vector<PackageInfoRef>& packages,
|
||||
uint32 changesMask);
|
||||
const PackageInfoRef
|
||||
PackageForName(const BString& name) const;
|
||||
bool HasPackage(const BString& packageName) const;
|
||||
bool HasAnyProminentPackages();
|
||||
|
||||
void Clear();
|
||||
const LanguageRef PreferredLanguage() const;
|
||||
void SetPreferredLanguage(const LanguageRef& value);
|
||||
const std::vector<LanguageRef>
|
||||
Languages() const;
|
||||
void SetLanguagesAndPreferred(const std::vector<LanguageRef>& value,
|
||||
const LanguageRef& preferred);
|
||||
|
||||
int32 CountCategories() const;
|
||||
CategoryRef CategoryByCode(BString& code) const;
|
||||
CategoryRef CategoryAtIndex(int32 index) const;
|
||||
void AddCategories(
|
||||
std::vector<CategoryRef>& values);
|
||||
void SetDepots(const DepotInfoRef& depot);
|
||||
void SetDepots(const std::vector<DepotInfoRef>& depots);
|
||||
const std::vector<DepotInfoRef>
|
||||
Depots() const;
|
||||
const DepotInfoRef DepotForName(const BString& name) const;
|
||||
const DepotInfoRef DepotForIdentifier(const BString& identifier) const;
|
||||
|
||||
int32 CountRatingStabilities() const;
|
||||
RatingStabilityRef RatingStabilityByCode(BString& code) const;
|
||||
RatingStabilityRef RatingStabilityAtIndex(int32 index) const;
|
||||
void AddRatingStabilities(
|
||||
std::vector<RatingStabilityRef>& values);
|
||||
|
||||
void SetStateForPackagesByName(
|
||||
BStringList& packageNames,
|
||||
PackageState state);
|
||||
const std::vector<CategoryRef>
|
||||
Categories() const;
|
||||
void SetCategories(const std::vector<CategoryRef> value);
|
||||
bool HasCategories();
|
||||
|
||||
const std::vector<RatingStabilityRef>
|
||||
RatingStabilities() const;
|
||||
void SetRatingStabilities(const std::vector<RatingStabilityRef> value);
|
||||
|
||||
void SetPackageListViewMode(
|
||||
package_list_view_mode mode);
|
||||
package_list_view_mode
|
||||
PackageListViewMode() const
|
||||
{ return fPackageListViewMode; }
|
||||
PackageListViewMode() const;
|
||||
|
||||
void SetCanShareAnonymousUsageData(bool value);
|
||||
bool CanShareAnonymousUsageData() const
|
||||
{ return fCanShareAnonymousUsageData; }
|
||||
bool CanShareAnonymousUsageData() const;
|
||||
|
||||
bool CanPopulatePackage(
|
||||
const PackageInfoRef& package);
|
||||
bool CanPopulatePackage(const PackageInfoRef& package);
|
||||
|
||||
void SetNickname(BString nickname);
|
||||
const BString& Nickname();
|
||||
void SetCredentials(const BString& nickname,
|
||||
const BString& passwordClear,
|
||||
bool storePassword);
|
||||
|
||||
WebAppInterface* GetWebAppInterface()
|
||||
{ return &fWebAppInterface; }
|
||||
void SetCredentials(const UserCredentials& credentials);
|
||||
const BString& Nickname();
|
||||
WebAppInterfaceRef WebApp();
|
||||
|
||||
// PackageScreenshotRepositoryListener
|
||||
virtual void ScreenshotCached(const ScreenshotCoordinate& coord);
|
||||
|
||||
|
||||
private:
|
||||
void _AddCategory(const CategoryRef& category);
|
||||
uint32 _ChangeDiff(const PackageInfoRef& package);
|
||||
|
||||
void _AddRatingStability(
|
||||
const RatingStabilityRef& value);
|
||||
@@ -138,41 +147,52 @@ private:
|
||||
const BMessage &responsePayload,
|
||||
const char *sourceDescription) const;
|
||||
|
||||
void _NotifyPackageFilterChanged();
|
||||
void _NotifyIconsChanged();
|
||||
void _NotifyAuthorizationChanged();
|
||||
void _NotifyCategoryListChanged();
|
||||
void _NotifyPackageChange(const PackageInfoEvent& event);
|
||||
void _NotifyPackageChanges(const PackageInfoEvents& events);
|
||||
|
||||
private:
|
||||
BLocker fLock;
|
||||
mutable BLocker fLock;
|
||||
|
||||
LanguageRef fPreferredLanguage;
|
||||
|
||||
std::vector<DepotInfoRef>
|
||||
std::map<BString, DepotInfoRef>
|
||||
fDepots;
|
||||
std::map<BString, PackageInfoRef>
|
||||
fPackages;
|
||||
|
||||
std::vector<CategoryRef>
|
||||
fCategories;
|
||||
std::vector<RatingStabilityRef>
|
||||
fRatingStabilities;
|
||||
|
||||
BStringList fPopulatedPackageNames;
|
||||
|
||||
package_list_view_mode
|
||||
fPackageListViewMode;
|
||||
|
||||
bool fCanShareAnonymousUsageData;
|
||||
|
||||
WebAppInterface fWebAppInterface;
|
||||
WebAppInterfaceRef fWebApp;
|
||||
|
||||
PackageFilterModel* fPackageFilterModel;
|
||||
PackageFilterSpecificationRef
|
||||
fFilterSpecification;
|
||||
PackageFilterRef fFilter;
|
||||
|
||||
LanguageRepository* fLanguageRepository;
|
||||
PackageIconTarRepository
|
||||
fPackageIconRepository;
|
||||
std::vector<LanguageRef>
|
||||
fLanguages;
|
||||
PackageIconRepositoryRef
|
||||
fIconRepository;
|
||||
PackageScreenshotRepository*
|
||||
fPackageScreenshotRepository;
|
||||
|
||||
std::vector<ModelListenerRef>
|
||||
fListeners;
|
||||
|
||||
std::vector<PackageInfoListenerRef>
|
||||
fPackageListeners;
|
||||
};
|
||||
|
||||
|
||||
#endif // PACKAGE_INFO_H
|
||||
#endif // MODEL_H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2013-2025, Stephan Aßmus <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "PackageInfoListener.h"
|
||||
@@ -9,6 +9,11 @@
|
||||
#include "PackageInfo.h"
|
||||
|
||||
|
||||
const char* kPackageInfoChangesKey = "change";
|
||||
const char* kPackageInfoPackageNameKey = "packageName";
|
||||
const char* kPackageInfoEventsKey = "events";
|
||||
|
||||
|
||||
// #pragma mark - PackageInfoEvent
|
||||
|
||||
|
||||
@@ -20,8 +25,7 @@ PackageInfoEvent::PackageInfoEvent()
|
||||
}
|
||||
|
||||
|
||||
PackageInfoEvent::PackageInfoEvent(const PackageInfoRef& package,
|
||||
uint32 changes)
|
||||
PackageInfoEvent::PackageInfoEvent(const PackageInfoRef& package, uint32 changes)
|
||||
:
|
||||
fPackage(package),
|
||||
fChanges(changes)
|
||||
@@ -47,9 +51,7 @@ PackageInfoEvent::operator==(const PackageInfoEvent& other)
|
||||
{
|
||||
if (this == &other)
|
||||
return true;
|
||||
|
||||
return fPackage == other.fPackage
|
||||
&& fChanges == other.fChanges;
|
||||
return fPackage == other.fPackage && fChanges == other.fChanges;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +74,85 @@ PackageInfoEvent::operator=(const PackageInfoEvent& other)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageInfoEvent::Archive(BMessage* into, bool deep) const
|
||||
{
|
||||
status_t result = B_OK;
|
||||
if (result == B_OK)
|
||||
result = into->AddUInt32(kPackageInfoChangesKey, fChanges);
|
||||
if (result == B_OK)
|
||||
result = into->AddString(kPackageInfoPackageNameKey, fPackage->Name());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - PackageInfoEvents
|
||||
|
||||
|
||||
PackageInfoEvents::PackageInfoEvents()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageInfoEvents::PackageInfoEvents(const PackageInfoEvent& event)
|
||||
{
|
||||
fEvents.push_back(event);
|
||||
}
|
||||
|
||||
|
||||
PackageInfoEvents::PackageInfoEvents(const PackageInfoEvents& other)
|
||||
{
|
||||
for (int32 i = other.CountEvents() - 1; i >= 0; i--)
|
||||
fEvents.push_back(other.EventAtIndex(i));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInfoEvents::AddEvent(const PackageInfoEvent event)
|
||||
{
|
||||
fEvents.push_back(event);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageInfoEvents::IsEmpty() const
|
||||
{
|
||||
return fEvents.empty();
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
PackageInfoEvents::CountEvents() const
|
||||
{
|
||||
return fEvents.size();
|
||||
}
|
||||
|
||||
|
||||
const PackageInfoEvent&
|
||||
PackageInfoEvents::EventAtIndex(int32 index) const
|
||||
{
|
||||
return fEvents[index];
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageInfoEvents::Archive(BMessage* into, bool deep) const
|
||||
{
|
||||
status_t result = B_OK;
|
||||
BString indexString;
|
||||
std::vector<PackageInfoEvent>::const_iterator it;
|
||||
|
||||
for (it = fEvents.begin(); it != fEvents.end(); it++) {
|
||||
BMessage eventMessage;
|
||||
result = (*it).Archive(&eventMessage);
|
||||
if (result == B_OK)
|
||||
result = into->AddMessage(kPackageInfoEventsKey, &eventMessage);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - PackageInfoListener
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
/*
|
||||
* Copyright 2013, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2022, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2022-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_INFO_LISTENER_H
|
||||
#define PACKAGE_INFO_LISTENER_H
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <Archivable.h>
|
||||
#include <String.h>
|
||||
#include <Referenceable.h>
|
||||
|
||||
|
||||
extern const char* kPackageInfoChangesKey;
|
||||
extern const char* kPackageInfoPackageNameKey;
|
||||
extern const char* kPackageInfoEventsKey;
|
||||
|
||||
|
||||
enum {
|
||||
PKG_CHANGED_LOCALIZED_TEXT = 1 << 0,
|
||||
// ^ Covers title, summary, description and changelog.
|
||||
@@ -17,13 +26,10 @@ enum {
|
||||
PKG_CHANGED_SCREENSHOTS = 1 << 2,
|
||||
PKG_CHANGED_LOCAL_INFO = 1 << 3,
|
||||
// ^ Covers state, download and size.
|
||||
PKG_CHANGED_ICON = 1 << 4,
|
||||
// ^ Handled slightly differently.
|
||||
PKG_CHANGED_CLASSIFICATION = 1 << 5,
|
||||
PKG_CHANGED_CLASSIFICATION = 1 << 4,
|
||||
// ^ This covers categories, prominence and is native desktop
|
||||
PKG_CHANGED_CORE_INFO = 1 << 6
|
||||
PKG_CHANGED_CORE_INFO = 1 << 5
|
||||
// ^ covers the version change timestamp
|
||||
// ...
|
||||
};
|
||||
|
||||
|
||||
@@ -31,11 +37,10 @@ class PackageInfo;
|
||||
typedef BReference<PackageInfo> PackageInfoRef;
|
||||
|
||||
|
||||
class PackageInfoEvent {
|
||||
class PackageInfoEvent : public BArchivable {
|
||||
public:
|
||||
PackageInfoEvent();
|
||||
PackageInfoEvent(const PackageInfoRef& package,
|
||||
uint32 changes);
|
||||
PackageInfoEvent(const PackageInfoRef& package, uint32 changes);
|
||||
PackageInfoEvent(const PackageInfoEvent& other);
|
||||
virtual ~PackageInfoEvent();
|
||||
|
||||
@@ -43,25 +48,47 @@ public:
|
||||
bool operator!=(const PackageInfoEvent& other);
|
||||
PackageInfoEvent& operator=(const PackageInfoEvent& other);
|
||||
|
||||
inline const PackageInfoRef& Package() const
|
||||
inline const PackageInfoRef&
|
||||
Package() const
|
||||
{ return fPackage; }
|
||||
|
||||
inline uint32 Changes() const
|
||||
{ return fChanges; }
|
||||
|
||||
status_t Archive(BMessage* into, bool deep = true) const;
|
||||
|
||||
private:
|
||||
PackageInfoRef fPackage;
|
||||
uint32 fChanges;
|
||||
};
|
||||
|
||||
|
||||
class PackageInfoEvents : public BArchivable {
|
||||
public:
|
||||
PackageInfoEvents();
|
||||
PackageInfoEvents(const PackageInfoEvent& event);
|
||||
PackageInfoEvents(const PackageInfoEvents& other);
|
||||
|
||||
bool IsEmpty() const;
|
||||
void AddEvent(const PackageInfoEvent event);
|
||||
int32 CountEvents() const;
|
||||
const PackageInfoEvent&
|
||||
EventAtIndex(int32 index) const;
|
||||
|
||||
status_t Archive(BMessage* into, bool deep = true) const;
|
||||
|
||||
private:
|
||||
std::vector<PackageInfoEvent>
|
||||
fEvents;
|
||||
};
|
||||
|
||||
|
||||
class PackageInfoListener : public BReferenceable {
|
||||
public:
|
||||
PackageInfoListener();
|
||||
virtual ~PackageInfoListener();
|
||||
|
||||
virtual void PackageChanged(
|
||||
const PackageInfoEvent& event) = 0;
|
||||
virtual void PackagesChanged(const PackageInfoEvents& events) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "PackageScreenshotRepository.h"
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "FileIO.h"
|
||||
#include "Logger.h"
|
||||
#include "Model.h"
|
||||
#include "StorageUtils.h"
|
||||
#include "WebAppInterface.h"
|
||||
|
||||
@@ -19,11 +20,10 @@ static const uint32 kMaxRetainedCachedScreenshots = 25;
|
||||
|
||||
|
||||
PackageScreenshotRepository::PackageScreenshotRepository(
|
||||
PackageScreenshotRepositoryListenerRef listener,
|
||||
WebAppInterface* webAppInterface)
|
||||
PackageScreenshotRepositoryListenerRef listener, Model* model)
|
||||
:
|
||||
fListener(listener),
|
||||
fWebAppInterface(webAppInterface)
|
||||
fModel(model)
|
||||
{
|
||||
_Init();
|
||||
}
|
||||
@@ -162,8 +162,7 @@ PackageScreenshotRepository::_Init()
|
||||
{
|
||||
fBaseDirectory.Unset();
|
||||
|
||||
status_t result = StorageUtils::LocalWorkingDirectoryPath(
|
||||
"screenshot_cache", fBaseDirectory);
|
||||
status_t result = StorageUtils::LocalWorkingDirectoryPath("screenshot_cache", fBaseDirectory);
|
||||
|
||||
if (B_OK != result)
|
||||
HDERROR("unable to setup the cache directory");
|
||||
@@ -202,8 +201,8 @@ PackageScreenshotRepository::_DownloadToLocalFile(const ScreenshotCoordinate& co
|
||||
}
|
||||
|
||||
BFileIO outputDataStream(file, true); // takes ownership
|
||||
status_t result = fWebAppInterface->RetrieveScreenshot(
|
||||
coord.Code(), coord.Width(), coord.Height(), &outputDataStream);
|
||||
status_t result = _WebApp()->RetrieveScreenshot(coord.Code(), coord.Width(), coord.Height(),
|
||||
&outputDataStream);
|
||||
|
||||
if (result == B_OK)
|
||||
result = outputDataStream.Flush();
|
||||
@@ -225,7 +224,8 @@ PackageScreenshotRepository::_DeriveCachePath(const ScreenshotCoordinate& coord)
|
||||
|
||||
|
||||
status_t
|
||||
PackageScreenshotRepository::_CreateCachedData(const ScreenshotCoordinate& coord, BPositionIO** data)
|
||||
PackageScreenshotRepository::_CreateCachedData(const ScreenshotCoordinate& coord,
|
||||
BPositionIO** data)
|
||||
{
|
||||
status_t result = B_OK;
|
||||
BPath path = _DeriveCachePath(coord);
|
||||
@@ -243,3 +243,10 @@ PackageScreenshotRepository::_CreateCachedData(const ScreenshotCoordinate& coord
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
WebAppInterfaceRef
|
||||
PackageScreenshotRepository::_WebApp()
|
||||
{
|
||||
return fModel->WebApp();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef SCREENSHOT_REPOSITORY_H
|
||||
@@ -12,9 +12,10 @@
|
||||
|
||||
#include "BitmapHolder.h"
|
||||
#include "ScreenshotCoordinate.h"
|
||||
#include "WebAppInterface.h"
|
||||
|
||||
|
||||
class WebAppInterface;
|
||||
class Model;
|
||||
|
||||
|
||||
class PackageScreenshotRepositoryListener : public BReferenceable {
|
||||
@@ -36,7 +37,7 @@ public:
|
||||
|
||||
PackageScreenshotRepository(
|
||||
PackageScreenshotRepositoryListenerRef listener,
|
||||
WebAppInterface* webAppInterface);
|
||||
Model* model);
|
||||
~PackageScreenshotRepository();
|
||||
|
||||
status_t LoadScreenshot(const ScreenshotCoordinate& coord,
|
||||
@@ -48,6 +49,8 @@ public:
|
||||
status_t CacheScreenshot(const ScreenshotCoordinate& coord);
|
||||
|
||||
private:
|
||||
WebAppInterfaceRef _WebApp();
|
||||
|
||||
status_t _Init();
|
||||
|
||||
status_t _CleanCache();
|
||||
@@ -61,7 +64,7 @@ private:
|
||||
private:
|
||||
PackageScreenshotRepositoryListenerRef
|
||||
fListener;
|
||||
WebAppInterface* fWebAppInterface;
|
||||
Model* fModel;
|
||||
BPath fBaseDirectory;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2020-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
bool IsRatingStabilityBefore(const RatingStabilityRef& rs1,
|
||||
const RatingStabilityRef& rs2)
|
||||
bool
|
||||
IsRatingStabilityRefLess(const RatingStabilityRef& rs1, const RatingStabilityRef& rs2)
|
||||
{
|
||||
if (!rs1.IsSet() || !rs2.IsSet())
|
||||
HDFATAL("unexpected NULL reference in a referencable");
|
||||
return rs1->Compare(*rs2) < 0;
|
||||
debugger("illegal state in rating stability less");
|
||||
return *(rs1.Get()) < *(rs2.Get());
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,7 @@ RatingStability::RatingStability()
|
||||
}
|
||||
|
||||
|
||||
RatingStability::RatingStability(const BString& code,
|
||||
const BString& name, int64 ordering)
|
||||
RatingStability::RatingStability(const BString& code, const BString& name, int64 ordering)
|
||||
:
|
||||
fCode(code),
|
||||
fName(name),
|
||||
@@ -49,21 +48,17 @@ RatingStability::RatingStability(const RatingStability& other)
|
||||
}
|
||||
|
||||
|
||||
RatingStability&
|
||||
RatingStability::operator=(const RatingStability& other)
|
||||
bool
|
||||
RatingStability::operator<(const RatingStability& other) const
|
||||
{
|
||||
fCode = other.fCode;
|
||||
fName = other.fName;
|
||||
fOrdering = other.fOrdering;
|
||||
return *this;
|
||||
return Compare(other) < 0;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
RatingStability::operator==(const RatingStability& other) const
|
||||
{
|
||||
return fCode == other.fCode && fName == other.fName
|
||||
&& fOrdering == other.fOrdering;
|
||||
return fCode == other.fCode && fName == other.fName && fOrdering == other.fOrdering;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2020-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef RATING_STABILITY_H
|
||||
@@ -20,12 +20,9 @@ public:
|
||||
RatingStability(
|
||||
const RatingStability& other);
|
||||
|
||||
RatingStability&
|
||||
operator=(const RatingStability& other);
|
||||
bool operator==(const RatingStability& other)
|
||||
const;
|
||||
bool operator!=(const RatingStability& other)
|
||||
const;
|
||||
bool operator<(const RatingStability& other) const;
|
||||
bool operator==(const RatingStability& other) const;
|
||||
bool operator!=(const RatingStability& other) const;
|
||||
|
||||
const BString& Code() const
|
||||
{ return fCode; }
|
||||
@@ -46,7 +43,7 @@ private:
|
||||
typedef BReference<RatingStability> RatingStabilityRef;
|
||||
|
||||
|
||||
extern bool IsRatingStabilityBefore(const RatingStabilityRef& rs1,
|
||||
extern bool IsRatingStabilityRefLess(const RatingStabilityRef& rs1,
|
||||
const RatingStabilityRef& rs2);
|
||||
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@ UserCredentials::UserCredentials(BMessage* from)
|
||||
}
|
||||
|
||||
|
||||
UserCredentials::UserCredentials(const BString& nickname,
|
||||
const BString& passwordClear)
|
||||
UserCredentials::UserCredentials(const BString& nickname, const BString& passwordClear)
|
||||
:
|
||||
fNickname(nickname),
|
||||
fPasswordClear(passwordClear),
|
||||
@@ -140,4 +139,4 @@ UserCredentials::Archive(BMessage* into, bool deep) const
|
||||
if (result == B_OK)
|
||||
result = into->AddBool(KEY_IS_SUCCESSFUL, fIsSuccessful);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
class UserCredentials : public BArchivable {
|
||||
public:
|
||||
UserCredentials();
|
||||
UserCredentials(BMessage* from);
|
||||
UserCredentials(const BString& nickname,
|
||||
const BString& passwordClear);
|
||||
UserCredentials(const UserCredentials& other);
|
||||
UserCredentials();
|
||||
virtual ~UserCredentials();
|
||||
|
||||
UserCredentials& operator=(const UserCredentials& other);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright 2013, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2013, Rene Gollent, <[email protected]>
|
||||
* Copyright 2020-2024, Andrew Lindesay <[email protected]>
|
||||
* Copyright 2020-2025, Andrew Lindesay <[email protected]>
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include "AbstractPackageProcess.h"
|
||||
|
||||
#include <Autolock.h>
|
||||
|
||||
#include "Logger.h"
|
||||
#include "Model.h"
|
||||
#include "PackageKitUtils.h"
|
||||
@@ -18,78 +20,93 @@
|
||||
|
||||
using namespace BPackageKit;
|
||||
|
||||
// #pragma mark - PackageAction
|
||||
|
||||
|
||||
AbstractPackageProcess::AbstractPackageProcess(
|
||||
PackageInfoRef package, Model* model)
|
||||
AbstractPackageProcess::AbstractPackageProcess(const BString& packageName, Model* model)
|
||||
:
|
||||
fPackage(package),
|
||||
fPackageName(packageName),
|
||||
fModel(model)
|
||||
{
|
||||
if (package.IsSet())
|
||||
fInstallLocation = PackageKitUtils::DeriveInstallLocation(package.Get());
|
||||
else
|
||||
fInstallLocation = B_PACKAGE_INSTALLATION_LOCATION_SYSTEM;
|
||||
|
||||
// TODO: ideally if the package is installed at multiple locations,
|
||||
// the user should be able to pick which one to remove.
|
||||
// TODO: allow configuring the installation location
|
||||
fPackageManager = new(std::nothrow) PackageManager(
|
||||
(BPackageInstallationLocation)fInstallLocation);
|
||||
}
|
||||
|
||||
|
||||
AbstractPackageProcess::~AbstractPackageProcess()
|
||||
{
|
||||
delete fPackageManager;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
AbstractPackageProcess::InstallLocation() const
|
||||
{
|
||||
PackageInfoRef package = FindPackageByName(fPackageName);
|
||||
if (package.IsSet())
|
||||
return PackageKitUtils::DeriveInstallLocation(package.Get());
|
||||
return B_PACKAGE_INSTALLATION_LOCATION_SYSTEM;
|
||||
}
|
||||
|
||||
|
||||
PackageInfoRef
|
||||
AbstractPackageProcess::FindPackageByName(const BString& name)
|
||||
AbstractPackageProcess::FindPackageByName(const BString& packageName) const
|
||||
{
|
||||
return fModel->PackageForName(name);
|
||||
return fModel->PackageForName(packageName);
|
||||
}
|
||||
|
||||
|
||||
// TODO; will refactor once the models go immutable.
|
||||
void
|
||||
AbstractPackageProcess::SetPackageState(PackageInfoRef& package, PackageState state)
|
||||
AbstractPackageProcess::SetPackageState(const BString& packageName, PackageState state)
|
||||
{
|
||||
PackageInfoRef package = fModel->PackageForName(packageName);
|
||||
|
||||
if (package.IsSet()) {
|
||||
PackageLocalInfoRef localInfo = PackageUtils::NewLocalInfo(package);
|
||||
localInfo->SetState(state);
|
||||
package->SetLocalInfo(localInfo);
|
||||
PackageLocalInfoRef localInfo
|
||||
= PackageLocalInfoBuilder(package->LocalInfo()).WithState(state).BuildRef();
|
||||
|
||||
PackageInfoRef updatedPackage
|
||||
= PackageInfoBuilder(package).WithLocalInfo(localInfo).BuildRef();
|
||||
|
||||
fModel->AddPackage(updatedPackage);
|
||||
|
||||
} else {
|
||||
HDERROR("setting state, but the package is not set");
|
||||
HDERROR("setting state, but the package [%s] is not present", packageName.String());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO; will refactor once the models go immutable.
|
||||
void
|
||||
AbstractPackageProcess::SetPackageDownloadProgress(PackageInfoRef& package, float value)
|
||||
AbstractPackageProcess::SetPackageDownloadProgress(const BString& packageName, float value)
|
||||
{
|
||||
PackageInfoRef package = fModel->PackageForName(packageName);
|
||||
|
||||
if (package.IsSet()) {
|
||||
PackageLocalInfoRef localInfo = PackageUtils::NewLocalInfo(package);
|
||||
localInfo->SetDownloadProgress(value);
|
||||
package->SetLocalInfo(localInfo);
|
||||
PackageLocalInfoRef localInfo
|
||||
= PackageLocalInfoBuilder(package->LocalInfo()).WithDownloadProgress(value).BuildRef();
|
||||
|
||||
PackageInfoRef updatedPackage
|
||||
= PackageInfoBuilder(package).WithLocalInfo(localInfo).BuildRef();
|
||||
|
||||
fModel->AddPackage(updatedPackage);
|
||||
|
||||
} else {
|
||||
HDERROR("setting progress, but the package is not set");
|
||||
HDERROR("setting progress, but the package [%s] is not present", packageName.String());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO; will refactor once the models go immutable.
|
||||
void
|
||||
AbstractPackageProcess::ClearPackageInstallationLocations(PackageInfoRef& package)
|
||||
AbstractPackageProcess::ClearPackageInstallationLocations(const BString& packageName)
|
||||
{
|
||||
PackageInfoRef package = fModel->PackageForName(packageName);
|
||||
|
||||
if (package.IsSet()) {
|
||||
PackageLocalInfoRef localInfo = PackageUtils::NewLocalInfo(package);
|
||||
localInfo->ClearInstallationLocations();
|
||||
package->SetLocalInfo(localInfo);
|
||||
PackageLocalInfoRef localInfo
|
||||
= PackageLocalInfoBuilder(package->LocalInfo()).ClearInstallationLocations().BuildRef();
|
||||
|
||||
PackageInfoRef updatedPackage
|
||||
= PackageInfoBuilder(package).WithLocalInfo(localInfo).BuildRef();
|
||||
|
||||
fModel->AddPackage(updatedPackage);
|
||||
|
||||
} else {
|
||||
HDERROR("clearing installation locations, but the package is not set");
|
||||
HDERROR("clearing installation locations, but the package [%s] is not present",
|
||||
packageName.String());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022, Andrew Lindesay <[email protected]>
|
||||
* Copyright 2022-2025, Andrew Lindesay <[email protected]>
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef ABSTRACT_PACKAGE_PROCESS_H
|
||||
@@ -18,27 +18,23 @@ class Model;
|
||||
|
||||
class AbstractPackageProcess : public BReferenceable, public AbstractProcess {
|
||||
public:
|
||||
AbstractPackageProcess(PackageInfoRef package,
|
||||
Model* model);
|
||||
AbstractPackageProcess(const BString& packageName, Model* model);
|
||||
virtual ~AbstractPackageProcess();
|
||||
|
||||
int32 InstallLocation() const
|
||||
{ return fInstallLocation; }
|
||||
|
||||
protected:
|
||||
PackageInfoRef FindPackageByName(const BString& name);
|
||||
int32 InstallLocation() const;
|
||||
PackageInfoRef FindPackageByName(const BString& packageName) const;
|
||||
|
||||
void SetPackageState(PackageInfoRef& package, PackageState state);
|
||||
void SetPackageDownloadProgress(PackageInfoRef& package, float value);
|
||||
void ClearPackageInstallationLocations(PackageInfoRef& package);
|
||||
void SetPackageState(const BString& packageName, PackageState state);
|
||||
void SetPackageDownloadProgress(const BString& packageName, float value);
|
||||
void ClearPackageInstallationLocations(const BString& packageName);
|
||||
|
||||
protected:
|
||||
PackageManager* fPackageManager;
|
||||
PackageInfoRef fPackage;
|
||||
BString fPackageName;
|
||||
|
||||
private:
|
||||
Model* fModel;
|
||||
int32 fInstallLocation;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2024, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2013-2025, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@@ -18,16 +18,17 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <AutoLocker.h>
|
||||
#include <Catalog.h>
|
||||
#include <Locker.h>
|
||||
|
||||
#include <package/manager/Exceptions.h>
|
||||
#include <package/hpkg/NoErrorOutput.h>
|
||||
#include <package/hpkg/PackageContentHandler.h>
|
||||
#include <package/hpkg/PackageEntry.h>
|
||||
#include <package/hpkg/PackageEntryAttribute.h>
|
||||
#include <package/hpkg/PackageReader.h>
|
||||
#include <package/manager/Exceptions.h>
|
||||
#include <package/solver/SolverPackage.h>
|
||||
|
||||
#include "AppUtils.h"
|
||||
@@ -57,6 +58,13 @@ using BPackageKit::BHPKG::BPackageReader;
|
||||
|
||||
class DownloadProgress {
|
||||
public:
|
||||
DownloadProgress()
|
||||
:
|
||||
fPackageName(),
|
||||
fProgress(0)
|
||||
{
|
||||
}
|
||||
|
||||
DownloadProgress(BString packageName, float progress)
|
||||
:
|
||||
fPackageName(packageName),
|
||||
@@ -84,14 +92,13 @@ private:
|
||||
};
|
||||
|
||||
|
||||
InstallPackageProcess::InstallPackageProcess(
|
||||
PackageInfoRef package, Model* model)
|
||||
InstallPackageProcess::InstallPackageProcess(const BString& packageName, Model* model)
|
||||
:
|
||||
AbstractPackageProcess(package, model),
|
||||
AbstractPackageProcess(packageName, model),
|
||||
fLastDownloadUpdate(0)
|
||||
{
|
||||
fDescription = B_TRANSLATE("Installing \"%PackageName%\"");
|
||||
fDescription.ReplaceAll("%PackageName%", package->Name());
|
||||
fDescription.ReplaceAll("%PackageName%", packageName);
|
||||
}
|
||||
|
||||
|
||||
@@ -120,14 +127,20 @@ InstallPackageProcess::Progress()
|
||||
if (ProcessState() == PROCESS_RUNNING && !fDownloadProgresses.empty()) {
|
||||
AutoLocker<BLocker> locker(&fLock);
|
||||
float sum = 0.0;
|
||||
std::vector<DownloadProgress>::const_iterator it;
|
||||
for (it = fDownloadProgresses.begin();
|
||||
it != fDownloadProgresses.end(); it++) {
|
||||
DownloadProgress downloadProgress = *it;
|
||||
sum += downloadProgress.Progress();
|
||||
int32 count = 0;
|
||||
|
||||
std::map<BString, DownloadProgress>::const_iterator it;
|
||||
|
||||
for (it = fDownloadProgresses.begin(); it != fDownloadProgresses.end(); it++) {
|
||||
DownloadProgress downloadProgress = it->second;
|
||||
|
||||
if (!downloadProgress.PackageName().IsEmpty()) {
|
||||
sum += downloadProgress.Progress();
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (sum > 0.0)
|
||||
return sum / (float) fDownloadProgresses.size();
|
||||
return sum / static_cast<float>(count);
|
||||
}
|
||||
return kProgressIndeterminate;
|
||||
}
|
||||
@@ -136,57 +149,61 @@ InstallPackageProcess::Progress()
|
||||
status_t
|
||||
InstallPackageProcess::RunInternal()
|
||||
{
|
||||
PackageInfoRef ref(fPackage);
|
||||
SetPackageState(ref, PENDING);
|
||||
// TODO: allow configuring the installation location
|
||||
|
||||
fPackageManager->Init(BPackageManager::B_ADD_INSTALLED_REPOSITORIES
|
||||
| BPackageManager::B_ADD_REMOTE_REPOSITORIES
|
||||
| BPackageManager::B_REFRESH_REPOSITORIES);
|
||||
PackageManager* packageManager = new(std::nothrow)
|
||||
PackageManager(static_cast<BPackageInstallationLocation>(InstallLocation()));
|
||||
ObjectDeleter<PackageManager> solverDeleter(packageManager);
|
||||
|
||||
PackageState state = PackageUtils::State(ref);
|
||||
SetPackageState(fPackageName, PENDING);
|
||||
|
||||
fPackageManager->SetCurrentActionPackage(ref, true);
|
||||
fPackageManager->AddProgressListener(this);
|
||||
packageManager->Init(BPackageManager::B_ADD_INSTALLED_REPOSITORIES
|
||||
| BPackageManager::B_ADD_REMOTE_REPOSITORIES | BPackageManager::B_REFRESH_REPOSITORIES);
|
||||
|
||||
BString packageName = ref->Name();
|
||||
PackageLocalInfoRef localInfo = ref->LocalInfo();
|
||||
|
||||
PackageInfoRef package = FindPackageByName(fPackageName);
|
||||
PackageState state = PackageUtils::State(package);
|
||||
|
||||
packageManager->SetCurrentActionPackage(package, true);
|
||||
packageManager->AddProgressListener(this);
|
||||
|
||||
BString packageName = fPackageName;
|
||||
PackageLocalInfoRef localInfo = package->LocalInfo();
|
||||
|
||||
if (localInfo.IsSet() && localInfo->IsLocalFile())
|
||||
packageName = localInfo->LocalFilePath();
|
||||
|
||||
const char* packageNameString = packageName.String();
|
||||
|
||||
try {
|
||||
fPackageManager->Install(&packageNameString, 1);
|
||||
packageManager->Install(&packageNameString, 1);
|
||||
} catch (BFatalErrorException& ex) {
|
||||
BString errorString;
|
||||
errorString.SetToFormat(
|
||||
"Fatal error occurred while installing package %s: "
|
||||
"%s (%s)\n", packageNameString, ex.Message().String(),
|
||||
ex.Details().String());
|
||||
AppUtils::NotifySimpleError(B_TRANSLATE("Fatal error"), errorString,
|
||||
B_STOP_ALERT);
|
||||
errorString.SetToFormat("Fatal error occurred while installing package %s: %s (%s)\n",
|
||||
packageNameString, ex.Message().String(), ex.Details().String());
|
||||
AppUtils::NotifySimpleError(B_TRANSLATE("Fatal error"), errorString, B_STOP_ALERT);
|
||||
_SetDownloadedPackagesState(NONE);
|
||||
SetPackageState(ref, state);
|
||||
SetPackageState(fPackageName, state);
|
||||
return ex.Error();
|
||||
} catch (BAbortedByUserException& ex) {
|
||||
HDINFO("Installation of package %s is aborted by user: %s",
|
||||
packageNameString, ex.Message().String());
|
||||
HDINFO("Installation of package %s is aborted by user: %s", packageNameString,
|
||||
ex.Message().String());
|
||||
_SetDownloadedPackagesState(NONE);
|
||||
SetPackageState(ref, state);
|
||||
SetPackageState(fPackageName, state);
|
||||
return B_OK;
|
||||
} catch (BNothingToDoException& ex) {
|
||||
HDINFO("Nothing to do while installing package %s: %s",
|
||||
packageNameString, ex.Message().String());
|
||||
HDINFO("Nothing to do while installing package %s: %s", packageNameString,
|
||||
ex.Message().String());
|
||||
return B_OK;
|
||||
} catch (BException& ex) {
|
||||
HDERROR("Exception occurred while installing package %s: %s",
|
||||
packageNameString, ex.Message().String());
|
||||
HDERROR("Exception occurred while installing package %s: %s", packageNameString,
|
||||
ex.Message().String());
|
||||
_SetDownloadedPackagesState(NONE);
|
||||
SetPackageState(ref, state);
|
||||
SetPackageState(fPackageName, state);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
fPackageManager->RemoveProgressListener(this);
|
||||
packageManager->RemoveProgressListener(this);
|
||||
|
||||
_SetDownloadedPackagesState(ACTIVATED);
|
||||
|
||||
@@ -198,26 +215,20 @@ InstallPackageProcess::RunInternal()
|
||||
|
||||
|
||||
void
|
||||
InstallPackageProcess::DownloadProgressChanged(
|
||||
const char* packageName, float progress)
|
||||
InstallPackageProcess::DownloadProgressChanged(const char* packageName, float progress)
|
||||
{
|
||||
bigtime_t now = system_time();
|
||||
if (now - fLastDownloadUpdate < 250000 && progress != 1.0)
|
||||
if (!_ShouldProcessProgress() && progress != 1.0)
|
||||
return;
|
||||
fLastDownloadUpdate = now;
|
||||
|
||||
BString simplePackageName;
|
||||
|
||||
if (_DeriveSimplePackageName(packageName, simplePackageName) != B_OK) {
|
||||
HDERROR("malformed canonical package name [%s]", packageName);
|
||||
return;
|
||||
}
|
||||
PackageInfoRef ref(FindPackageByName(simplePackageName));
|
||||
if (ref.IsSet()) {
|
||||
SetPackageDownloadProgress(ref, progress);
|
||||
_SetDownloadProgress(simplePackageName, progress);
|
||||
} else {
|
||||
HDERROR("unable to find the package info for simple package name [%s]",
|
||||
simplePackageName.String());
|
||||
}
|
||||
|
||||
SetPackageDownloadProgress(simplePackageName, progress);
|
||||
_SetDownloadProgress(simplePackageName, progress);
|
||||
}
|
||||
|
||||
|
||||
@@ -230,29 +241,21 @@ InstallPackageProcess::DownloadProgressComplete(const char* packageName)
|
||||
return;
|
||||
}
|
||||
_SetDownloadProgress(simplePackageName, 1.0);
|
||||
PackageInfoRef ref(FindPackageByName(simplePackageName));
|
||||
if (!ref.IsSet()) {
|
||||
HDERROR("unable to find the package info for simple package name [%s]",
|
||||
simplePackageName.String());
|
||||
return;
|
||||
}
|
||||
SetPackageDownloadProgress(ref, 1.0);
|
||||
fDownloadedPackages.insert(ref);
|
||||
SetPackageDownloadProgress(simplePackageName, 1.0);
|
||||
fDownloadedPackageNames.insert(simplePackageName);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InstallPackageProcess::ConfirmedChanges(
|
||||
BPackageManager::InstalledRepository& repository)
|
||||
InstallPackageProcess::ConfirmedChanges(BPackageManager::InstalledRepository& repository)
|
||||
{
|
||||
BPackageManager::InstalledRepository::PackageList& activationList =
|
||||
repository.PackagesToActivate();
|
||||
BPackageManager::InstalledRepository::PackageList& activationList
|
||||
= repository.PackagesToActivate();
|
||||
|
||||
BSolverPackage* package = NULL;
|
||||
for (int32 i = 0; (package = activationList.ItemAt(i)); i++) {
|
||||
PackageInfoRef ref(FindPackageByName(package->Info().Name()));
|
||||
if (ref.IsSet())
|
||||
SetPackageState(ref, PENDING);
|
||||
BString packageName = package->Info().Name();
|
||||
SetPackageState(packageName, PENDING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,22 +263,14 @@ InstallPackageProcess::ConfirmedChanges(
|
||||
void
|
||||
InstallPackageProcess::_SetDownloadedPackagesState(PackageState state)
|
||||
{
|
||||
for (PackageInfoSet::iterator it = fDownloadedPackages.begin();
|
||||
it != fDownloadedPackages.end(); ++it) {
|
||||
PackageInfoRef ref = (*it);
|
||||
SetPackageState(ref, state);
|
||||
std::set<BString>::const_iterator it;
|
||||
for (it = fDownloadedPackageNames.begin(); it != fDownloadedPackageNames.end(); ++it) {
|
||||
BString packageName = *it;
|
||||
SetPackageState(packageName, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
_IsDownloadProgressBefore(const DownloadProgress& dp1,
|
||||
const DownloadProgress& dp2)
|
||||
{
|
||||
return dp1.PackageName().Compare(dp2.PackageName()) < 0;
|
||||
}
|
||||
|
||||
|
||||
/*! This method will extract the plain package name from the canonical
|
||||
*/
|
||||
|
||||
@@ -293,22 +288,9 @@ InstallPackageProcess::_DeriveSimplePackageName(const BString& canonicalForm,
|
||||
|
||||
|
||||
void
|
||||
InstallPackageProcess::_SetDownloadProgress(const BString& simplePackageName,
|
||||
float progress)
|
||||
InstallPackageProcess::_SetDownloadProgress(const BString& simplePackageName, float progress)
|
||||
{
|
||||
AutoLocker<BLocker> locker(&fLock);
|
||||
DownloadProgress downloadProgress(simplePackageName, progress);
|
||||
std::vector<DownloadProgress>::iterator itInsertionPt
|
||||
= std::lower_bound(
|
||||
fDownloadProgresses.begin(), fDownloadProgresses.end(),
|
||||
downloadProgress, &_IsDownloadProgressBefore);
|
||||
|
||||
if (itInsertionPt != fDownloadProgresses.end()) {
|
||||
if ((*itInsertionPt).PackageName() == simplePackageName) {
|
||||
itInsertionPt = fDownloadProgresses.erase(itInsertionPt);
|
||||
}
|
||||
}
|
||||
|
||||
fDownloadProgresses.insert(itInsertionPt, downloadProgress);
|
||||
fDownloadProgresses[simplePackageName] = downloadProgress;
|
||||
_NotifyChanged();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright 2011, Ingo Weinhold, <[email protected]>
|
||||
* Copyright 2013, Rene Gollent, <[email protected]>
|
||||
* Copyright 2017, Julian Harnath <[email protected]>.
|
||||
* Copyright 2021, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2021-2025, Andrew Lindesay <[email protected]>.
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
@@ -30,7 +30,7 @@ class InstallPackageProcess
|
||||
private PackageProgressListener {
|
||||
public:
|
||||
InstallPackageProcess(
|
||||
PackageInfoRef package, Model* model);
|
||||
const BString& packageName, Model* model);
|
||||
virtual ~InstallPackageProcess();
|
||||
|
||||
virtual const char* Name() const;
|
||||
@@ -63,11 +63,11 @@ private:
|
||||
float progress);
|
||||
|
||||
private:
|
||||
std::vector<DownloadProgress>
|
||||
std::map<BString, DownloadProgress>
|
||||
fDownloadProgresses;
|
||||
BString fDescription;
|
||||
bigtime_t fLastDownloadUpdate;
|
||||
PackageInfoSet fDownloadedPackages;
|
||||
std::set<BString> fDownloadedPackageNames;
|
||||
};
|
||||
|
||||
#endif // INSTALL_PACKAGE_PROCESS_H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2022, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2013-2025, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@@ -64,8 +64,7 @@ public:
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
virtual status_t HandleEntryAttribute(BPackageEntry* entry,
|
||||
BPackageEntryAttribute* attribute)
|
||||
virtual status_t HandleEntryAttribute(BPackageEntry* entry, BPackageEntryAttribute* attribute)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
@@ -75,8 +74,7 @@ public:
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
virtual status_t HandlePackageAttribute(
|
||||
const BPackageInfoAttributeValue& value)
|
||||
virtual status_t HandlePackageAttribute(const BPackageInfoAttributeValue& value)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
@@ -105,10 +103,10 @@ private:
|
||||
// #pragma mark - OpenPackageProcess
|
||||
|
||||
|
||||
OpenPackageProcess::OpenPackageProcess(PackageInfoRef package, Model* model,
|
||||
const DeskbarLink& link)
|
||||
OpenPackageProcess::OpenPackageProcess(const BString& packageName, Model* model,
|
||||
const DeskbarLink& link)
|
||||
:
|
||||
AbstractPackageProcess(package, model),
|
||||
AbstractPackageProcess(packageName, model),
|
||||
fDeskbarLink(link)
|
||||
{
|
||||
fDescription = _DeriveDescription();
|
||||
@@ -192,7 +190,7 @@ OpenPackageProcess::_DeriveDescription()
|
||||
|
||||
/*static*/ bool
|
||||
OpenPackageProcess::FindAppToLaunch(const PackageInfoRef& package,
|
||||
std::vector<DeskbarLink>& foundLinks)
|
||||
std::vector<DeskbarLink>& foundLinks)
|
||||
{
|
||||
if (!package.IsSet())
|
||||
return false;
|
||||
@@ -208,8 +206,7 @@ OpenPackageProcess::FindAppToLaunch(const PackageInfoRef& package,
|
||||
|
||||
status_t status = reader.Init(packagePath.Path());
|
||||
if (status != B_OK) {
|
||||
HDINFO("OpenPackageAction::FindAppToLaunch(): "
|
||||
"failed to init BPackageReader(%s): %s",
|
||||
HDINFO("OpenPackageAction::FindAppToLaunch(): failed to init BPackageReader(%s): %s",
|
||||
packagePath.Path(), strerror(status));
|
||||
return false;
|
||||
}
|
||||
@@ -218,8 +215,7 @@ OpenPackageProcess::FindAppToLaunch(const PackageInfoRef& package,
|
||||
DeskbarLinkFinder contentHandler(foundLinks);
|
||||
status = reader.ParseContent(&contentHandler);
|
||||
if (status != B_OK) {
|
||||
HDINFO("OpenPackageAction::FindAppToLaunch(): "
|
||||
"failed parse package contents (%s): %s",
|
||||
HDINFO("OpenPackageAction::FindAppToLaunch(): failed parse package contents (%s): %s",
|
||||
packagePath.Path(), strerror(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright 2011, Ingo Weinhold, <[email protected]>
|
||||
* Copyright 2013, Rene Gollent, <[email protected]>
|
||||
* Copyright 2017, Julian Harnath <[email protected]>
|
||||
* Copyright 2021, Andrew Lindesay <[email protected]>
|
||||
* Copyright 2021-2025, Andrew Lindesay <[email protected]>
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
@@ -24,7 +24,7 @@ class OpenPackageProcess
|
||||
private PackageProgressListener {
|
||||
public:
|
||||
OpenPackageProcess(
|
||||
PackageInfoRef package, Model* model,
|
||||
const BString& packageName, Model* model,
|
||||
const DeskbarLink& link);
|
||||
virtual ~OpenPackageProcess();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2021, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2013-2025, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <package/manager/Exceptions.h>
|
||||
#include <package/solver/SolverPackage.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <Catalog.h>
|
||||
|
||||
#include "Alert.h"
|
||||
@@ -38,13 +39,12 @@ using namespace BPackageKit::BManager::BPrivate;
|
||||
using BPackageKit::BSolverPackage;
|
||||
|
||||
|
||||
UninstallPackageProcess::UninstallPackageProcess(PackageInfoRef package,
|
||||
Model* model)
|
||||
UninstallPackageProcess::UninstallPackageProcess(const BString& packageName, Model* model)
|
||||
:
|
||||
AbstractPackageProcess(package, model)
|
||||
AbstractPackageProcess(packageName, model)
|
||||
{
|
||||
fDescription = B_TRANSLATE("Uninstalling \"%PackageName%\"");
|
||||
fDescription.ReplaceAll("%PackageName%", fPackage->Name());
|
||||
fDescription.ReplaceAll("%PackageName%", packageName);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,67 +70,68 @@ UninstallPackageProcess::Description() const
|
||||
status_t
|
||||
UninstallPackageProcess::RunInternal()
|
||||
{
|
||||
fPackageManager->Init(BPackageManager::B_ADD_INSTALLED_REPOSITORIES);
|
||||
// TODO: ideally if the package is installed at multiple locations,
|
||||
// the user should be able to pick which one to remove.
|
||||
|
||||
PackageInfoRef ref(fPackage);
|
||||
PackageState state = PackageUtils::State(fPackage);
|
||||
const char* packageName = ref->Name().String();
|
||||
PackageManager* packageManager = new(std::nothrow)
|
||||
PackageManager(static_cast<BPackageInstallationLocation>(InstallLocation()));
|
||||
ObjectDeleter<PackageManager> solverDeleter(packageManager);
|
||||
|
||||
fPackageManager->SetCurrentActionPackage(ref, false);
|
||||
fPackageManager->AddProgressListener(this);
|
||||
packageManager->Init(BPackageManager::B_ADD_INSTALLED_REPOSITORIES);
|
||||
|
||||
PackageInfoRef package = FindPackageByName(fPackageName);
|
||||
PackageState state = PackageUtils::State(package);
|
||||
|
||||
packageManager->SetCurrentActionPackage(package, false);
|
||||
packageManager->AddProgressListener(this);
|
||||
|
||||
const char* packageNameString = package->Name().String();
|
||||
|
||||
try {
|
||||
fPackageManager->Uninstall(&packageName, 1);
|
||||
packageManager->Uninstall(&packageNameString, 1);
|
||||
} catch (BFatalErrorException& ex) {
|
||||
BString errorString;
|
||||
errorString.SetToFormat(
|
||||
"Fatal error occurred while uninstalling package %s: "
|
||||
"%s (%s)\n", packageName, ex.Message().String(),
|
||||
ex.Details().String());
|
||||
AppUtils::NotifySimpleError(B_TRANSLATE("Fatal error"), errorString,
|
||||
B_STOP_ALERT);
|
||||
SetPackageState(ref, state);
|
||||
errorString.SetToFormat("Fatal error occurred while uninstalling package %s: %s (%s)\n",
|
||||
fPackageName.String(), ex.Message().String(), ex.Details().String());
|
||||
AppUtils::NotifySimpleError(B_TRANSLATE("Fatal error"), errorString, B_STOP_ALERT);
|
||||
SetPackageState(fPackageName, state);
|
||||
return ex.Error();
|
||||
} catch (BAbortedByUserException& ex) {
|
||||
return B_OK;
|
||||
} catch (BNothingToDoException& ex) {
|
||||
return B_OK;
|
||||
} catch (BException& ex) {
|
||||
HDERROR("Exception occurred while uninstalling package %s: %s",
|
||||
packageName, ex.Message().String());
|
||||
SetPackageState(ref, state);
|
||||
HDERROR("Exception occurred while uninstalling package %s: %s", fPackageName.String(),
|
||||
ex.Message().String());
|
||||
SetPackageState(fPackageName, state);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
fPackageManager->RemoveProgressListener(this);
|
||||
packageManager->RemoveProgressListener(this);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UninstallPackageProcess::StartApplyingChanges(
|
||||
BPackageManager::InstalledRepository& repository)
|
||||
UninstallPackageProcess::StartApplyingChanges(BPackageManager::InstalledRepository& repository)
|
||||
{
|
||||
BPackageManager::InstalledRepository::PackageList& packages
|
||||
= repository.PackagesToDeactivate();
|
||||
BPackageManager::InstalledRepository::PackageList& packages = repository.PackagesToDeactivate();
|
||||
|
||||
for (int32 i = 0; i < packages.CountItems(); i++) {
|
||||
PackageInfoRef ref(FindPackageByName(packages.ItemAt(i)
|
||||
->Name()));
|
||||
if (ref.IsSet())
|
||||
fRemovedPackages.push_back(ref);
|
||||
BString packageName = packages.ItemAt(i)->Name();
|
||||
fRemovedPackageNames.insert(packageName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UninstallPackageProcess::ApplyingChangesDone(
|
||||
BPackageManager::InstalledRepository& repository)
|
||||
UninstallPackageProcess::ApplyingChangesDone(BPackageManager::InstalledRepository& repository)
|
||||
{
|
||||
std::vector<PackageInfoRef>::iterator it;
|
||||
for (it = fRemovedPackages.begin(); it != fRemovedPackages.end(); it++) {
|
||||
PackageInfoRef packageInfoRef = *it;
|
||||
SetPackageState(packageInfoRef, NONE);
|
||||
ClearPackageInstallationLocations(packageInfoRef);
|
||||
std::set<BString>::const_iterator it;
|
||||
for (it = fRemovedPackageNames.begin(); it != fRemovedPackageNames.end(); it++) {
|
||||
BString packageName = *it;
|
||||
SetPackageState(packageName, NONE);
|
||||
ClearPackageInstallationLocations(packageName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright 2011, Ingo Weinhold, <[email protected]>
|
||||
* Copyright 2013, Rene Gollent, <[email protected]>
|
||||
* Copyright 2017, Julian Harnath <[email protected]>
|
||||
* Copyright 2021, Andrew Lindesay <[email protected]>
|
||||
* Copyright 2021-2025, Andrew Lindesay <[email protected]>
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
@@ -23,7 +23,7 @@ class UninstallPackageProcess
|
||||
private PackageProgressListener {
|
||||
public:
|
||||
UninstallPackageProcess(
|
||||
PackageInfoRef package, Model* model);
|
||||
const BString& packageName, Model* model);
|
||||
virtual ~UninstallPackageProcess();
|
||||
|
||||
virtual const char* Name() const;
|
||||
@@ -41,8 +41,7 @@ protected:
|
||||
|
||||
private:
|
||||
BString fDescription;
|
||||
std::vector<PackageInfoRef>
|
||||
fRemovedPackages;
|
||||
std::set<BString> fRemovedPackageNames;
|
||||
};
|
||||
|
||||
#endif // INSTALL_PACKAGE_PROCESS_H
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2013, Rene Gollent <[email protected]>.
|
||||
* Copyright 2016-2023, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -14,27 +14,6 @@
|
||||
#include "PackageUtils.h"
|
||||
|
||||
|
||||
// #pragma mark - Sorting Functions
|
||||
|
||||
|
||||
static bool
|
||||
_IsPackageBeforeByName(const PackageInfoRef& p1, const BString& packageName)
|
||||
{
|
||||
return p1->Name().Compare(packageName) < 0;
|
||||
}
|
||||
|
||||
|
||||
/*! This function is used in order to provide an ordering on the packages
|
||||
that are stored on a Depot.
|
||||
*/
|
||||
|
||||
static bool
|
||||
_IsPackageBefore(const PackageInfoRef& p1, const PackageInfoRef& p2)
|
||||
{
|
||||
return _IsPackageBeforeByName(p1, p2->Name());
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Class implementation
|
||||
|
||||
|
||||
@@ -61,31 +40,16 @@ DepotInfo::DepotInfo(const DepotInfo& other)
|
||||
:
|
||||
fName(other.fName),
|
||||
fIdentifier(other.fIdentifier),
|
||||
fPackages(other.fPackages),
|
||||
fWebAppRepositoryCode(other.fWebAppRepositoryCode),
|
||||
fWebAppRepositorySourceCode(other.fWebAppRepositorySourceCode)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
DepotInfo&
|
||||
DepotInfo::operator=(const DepotInfo& other)
|
||||
{
|
||||
fName = other.fName;
|
||||
fIdentifier = other.fIdentifier;
|
||||
fPackages = other.fPackages;
|
||||
fWebAppRepositoryCode = other.fWebAppRepositoryCode;
|
||||
fWebAppRepositorySourceCode = other.fWebAppRepositorySourceCode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DepotInfo::operator==(const DepotInfo& other) const
|
||||
{
|
||||
return fName == other.fName
|
||||
&& fIdentifier == fIdentifier
|
||||
&& fPackages == other.fPackages;
|
||||
return fName == other.fName && fIdentifier == fIdentifier;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,127 +60,31 @@ DepotInfo::operator!=(const DepotInfo& other) const
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
DepotInfo::CountPackages() const
|
||||
const BString&
|
||||
DepotInfo::Name() const
|
||||
{
|
||||
return fPackages.size();
|
||||
return fName;
|
||||
}
|
||||
|
||||
|
||||
PackageInfoRef
|
||||
DepotInfo::PackageAtIndex(int32 index)
|
||||
const BString&
|
||||
DepotInfo::Identifier() const
|
||||
{
|
||||
return fPackages[index];
|
||||
return fIdentifier;
|
||||
}
|
||||
|
||||
|
||||
/*! This method will insert the package into the list of packages
|
||||
in order so that the list of packages remains in order.
|
||||
*/
|
||||
|
||||
void
|
||||
DepotInfo::AddPackage(PackageInfoRef& package)
|
||||
const BString&
|
||||
DepotInfo::WebAppRepositoryCode() const
|
||||
{
|
||||
std::vector<PackageInfoRef>::iterator itInsertionPt
|
||||
= std::lower_bound(
|
||||
fPackages.begin(),
|
||||
fPackages.end(),
|
||||
package,
|
||||
&_IsPackageBefore);
|
||||
if (fPackages.end() != itInsertionPt && (*itInsertionPt)->Name() == package->Name())
|
||||
*itInsertionPt = package;
|
||||
else
|
||||
fPackages.insert(itInsertionPt, package);
|
||||
return fWebAppRepositoryCode;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DepotInfo::HasPackage(const BString& packageName)
|
||||
const BString&
|
||||
DepotInfo::WebAppRepositorySourceCode() const
|
||||
{
|
||||
std::vector<PackageInfoRef>::const_iterator it
|
||||
= std::lower_bound(
|
||||
fPackages.begin(),
|
||||
fPackages.end(),
|
||||
packageName,
|
||||
&_IsPackageBeforeByName);
|
||||
if (it != fPackages.end()) {
|
||||
PackageInfoRef candidate = *it;
|
||||
return (candidate.Get() != NULL
|
||||
&& candidate.Get()->Name() == packageName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PackageInfoRef
|
||||
DepotInfo::PackageByName(const BString& packageName)
|
||||
{
|
||||
std::vector<PackageInfoRef>::const_iterator it
|
||||
= std::lower_bound(
|
||||
fPackages.begin(),
|
||||
fPackages.end(),
|
||||
packageName,
|
||||
&_IsPackageBeforeByName);
|
||||
|
||||
if (it != fPackages.end()) {
|
||||
PackageInfoRef candidate = *it;
|
||||
if (candidate.Get() != NULL && candidate.Get()->Name() == packageName)
|
||||
return candidate;
|
||||
}
|
||||
return PackageInfoRef();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DepotInfo::SyncPackagesFromDepot(const DepotInfoRef& other)
|
||||
{
|
||||
for (int32 i = other->CountPackages() - 1; i >= 0; i--) {
|
||||
PackageInfoRef otherPackage = other->PackageAtIndex(i);
|
||||
PackageInfoRef myPackage = PackageByName(otherPackage->Name());
|
||||
|
||||
if (myPackage.IsSet()) {
|
||||
PackageLocalInfoRef localInfo = PackageUtils::NewLocalInfo(myPackage);
|
||||
PackageLocalInfoRef otherLocalInfo = otherPackage->LocalInfo();
|
||||
|
||||
if (otherLocalInfo.IsSet()) {
|
||||
localInfo->SetState(otherLocalInfo->State());
|
||||
localInfo->SetLocalFilePath(otherLocalInfo->LocalFilePath());
|
||||
localInfo->SetSystemDependency(otherLocalInfo->IsSystemDependency());
|
||||
}
|
||||
|
||||
myPackage->SetLocalInfo(localInfo);
|
||||
} else {
|
||||
HDINFO("%s: new package: '%s'", fName.String(),
|
||||
otherPackage->Name().String());
|
||||
AddPackage(otherPackage);
|
||||
}
|
||||
}
|
||||
|
||||
for (int32 i = CountPackages() - 1; i >= 0; i--) {
|
||||
PackageInfoRef myPackage = PackageAtIndex(i);
|
||||
if (!other->HasPackage(myPackage->Name())) {
|
||||
HDINFO("%s: removing package: '%s'", fName.String(),
|
||||
myPackage->Name().String());
|
||||
fPackages.erase(fPackages.begin() + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DepotInfo::HasAnyProminentPackages() const
|
||||
{
|
||||
std::vector<PackageInfoRef>::const_iterator it;
|
||||
for (it = fPackages.begin(); it != fPackages.end(); it++) {
|
||||
const PackageInfoRef& package = *it;
|
||||
const PackageClassificationInfoRef& classification = package->PackageClassificationInfo();
|
||||
|
||||
if (classification.IsSet()) {
|
||||
if (classification->IsProminent())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return fWebAppRepositorySourceCode;
|
||||
}
|
||||
|
||||
|
||||
@@ -239,3 +107,110 @@ DepotInfo::SetWebAppRepositorySourceCode(const BString& code)
|
||||
{
|
||||
fWebAppRepositorySourceCode = code;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - DepotInfoBuilder
|
||||
|
||||
|
||||
DepotInfoBuilder::DepotInfoBuilder()
|
||||
:
|
||||
fName(),
|
||||
fIdentifier(),
|
||||
fWebAppRepositoryCode(),
|
||||
fWebAppRepositorySourceCode()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
DepotInfoBuilder::DepotInfoBuilder(const DepotInfoRef& value)
|
||||
:
|
||||
fName(),
|
||||
fIdentifier(),
|
||||
fWebAppRepositoryCode(),
|
||||
fWebAppRepositorySourceCode()
|
||||
{
|
||||
fSource = value;
|
||||
}
|
||||
|
||||
|
||||
DepotInfoBuilder::~DepotInfoBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DepotInfoBuilder::_InitFromSource()
|
||||
{
|
||||
if (fSource.IsSet()) {
|
||||
_Init(fSource.Get());
|
||||
fSource.Unset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DepotInfoBuilder::_Init(const DepotInfo* value)
|
||||
{
|
||||
fName = value->Name();
|
||||
fIdentifier = value->Identifier();
|
||||
fWebAppRepositoryCode = value->WebAppRepositoryCode();
|
||||
fWebAppRepositorySourceCode = value->WebAppRepositorySourceCode();
|
||||
}
|
||||
|
||||
|
||||
DepotInfoRef
|
||||
DepotInfoBuilder::BuildRef() const
|
||||
{
|
||||
if (fSource.IsSet())
|
||||
return fSource;
|
||||
|
||||
DepotInfo* depotInfo = new DepotInfo(fName);
|
||||
depotInfo->SetIdentifier(fIdentifier);
|
||||
depotInfo->SetWebAppRepositoryCode(fWebAppRepositoryCode);
|
||||
depotInfo->SetWebAppRepositorySourceCode(fWebAppRepositorySourceCode);
|
||||
return DepotInfoRef(depotInfo, true);
|
||||
}
|
||||
|
||||
|
||||
DepotInfoBuilder&
|
||||
DepotInfoBuilder::WithName(const BString& value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Name() != value) {
|
||||
_InitFromSource();
|
||||
fName = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
DepotInfoBuilder&
|
||||
DepotInfoBuilder::WithIdentifier(const BString& value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Identifier() != value) {
|
||||
_InitFromSource();
|
||||
fIdentifier = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
DepotInfoBuilder&
|
||||
DepotInfoBuilder::WithWebAppRepositoryCode(const BString& value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->WebAppRepositoryCode() != value) {
|
||||
_InitFromSource();
|
||||
fWebAppRepositoryCode = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
DepotInfoBuilder&
|
||||
DepotInfoBuilder::WithWebAppRepositorySourceCode(const BString& value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->WebAppRepositorySourceCode() != value) {
|
||||
_InitFromSource();
|
||||
fWebAppRepositorySourceCode = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2016-2023, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef DEPOT_INFO_H
|
||||
@@ -14,48 +14,36 @@
|
||||
#include "PackageInfo.h"
|
||||
|
||||
|
||||
class DepotInfoBuilder;
|
||||
|
||||
|
||||
/*! Instances of this class should not be created directly; instead use the
|
||||
DepotInfoBuilder class as a builder-constructor.
|
||||
*/
|
||||
class DepotInfo : public BReferenceable {
|
||||
friend class DepotInfoBuilder;
|
||||
|
||||
public:
|
||||
DepotInfo();
|
||||
DepotInfo(const BString& name);
|
||||
DepotInfo(const DepotInfo& other);
|
||||
|
||||
DepotInfo& operator=(const DepotInfo& other);
|
||||
bool operator==(const DepotInfo& other) const;
|
||||
bool operator!=(const DepotInfo& other) const;
|
||||
|
||||
const BString& Name() const
|
||||
{ return fName; }
|
||||
const BString& Name() const;
|
||||
const BString& Identifier() const;
|
||||
const BString& WebAppRepositoryCode() const;
|
||||
const BString& WebAppRepositorySourceCode() const;
|
||||
|
||||
private:
|
||||
void SetIdentifier(const BString& value);
|
||||
const BString& Identifier() const
|
||||
{ return fIdentifier; }
|
||||
|
||||
int32 CountPackages() const;
|
||||
PackageInfoRef PackageAtIndex(int32 index);
|
||||
void AddPackage(PackageInfoRef& package);
|
||||
PackageInfoRef PackageByName(const BString& packageName);
|
||||
bool HasPackage(const BString& packageName);
|
||||
|
||||
void SyncPackagesFromDepot(
|
||||
const BReference<DepotInfo>& other);
|
||||
|
||||
bool HasAnyProminentPackages() const;
|
||||
|
||||
void SetWebAppRepositoryCode(const BString& code);
|
||||
const BString& WebAppRepositoryCode() const
|
||||
{ return fWebAppRepositoryCode; }
|
||||
|
||||
void SetWebAppRepositorySourceCode(
|
||||
const BString& code);
|
||||
const BString& WebAppRepositorySourceCode() const
|
||||
{ return fWebAppRepositorySourceCode; }
|
||||
void SetWebAppRepositorySourceCode(const BString& code);
|
||||
|
||||
private:
|
||||
BString fName;
|
||||
BString fIdentifier;
|
||||
std::vector<PackageInfoRef>
|
||||
fPackages;
|
||||
BString fWebAppRepositoryCode;
|
||||
BString fWebAppRepositorySourceCode;
|
||||
};
|
||||
@@ -64,4 +52,31 @@ private:
|
||||
typedef BReference<DepotInfo> DepotInfoRef;
|
||||
|
||||
|
||||
class DepotInfoBuilder
|
||||
{
|
||||
public:
|
||||
DepotInfoBuilder();
|
||||
DepotInfoBuilder(const DepotInfoRef& value);
|
||||
virtual ~DepotInfoBuilder();
|
||||
|
||||
DepotInfoRef BuildRef() const;
|
||||
|
||||
DepotInfoBuilder& WithName(const BString& value);
|
||||
DepotInfoBuilder& WithIdentifier(const BString& value);
|
||||
DepotInfoBuilder& WithWebAppRepositoryCode(const BString& value);
|
||||
DepotInfoBuilder& WithWebAppRepositorySourceCode(const BString& value);
|
||||
|
||||
private:
|
||||
void _InitFromSource();
|
||||
void _Init(const DepotInfo* value);
|
||||
|
||||
private:
|
||||
DepotInfoRef fSource;
|
||||
BString fName;
|
||||
BString fIdentifier;
|
||||
BString fWebAppRepositoryCode;
|
||||
BString fWebAppRepositorySourceCode;
|
||||
};
|
||||
|
||||
|
||||
#endif // DEPOT_INFO_H
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2013, Rene Gollent <[email protected]>.
|
||||
* Copyright 2016-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -13,11 +13,10 @@
|
||||
#include "StringUtils.h"
|
||||
|
||||
|
||||
/*! serverName is the name of the language on the server.
|
||||
/*! @param serverName is the name of the language on the server.
|
||||
*/
|
||||
|
||||
Language::Language(const char* language, const BString& serverName,
|
||||
bool isPopular)
|
||||
Language::Language(const char* language, const BString& serverName, bool isPopular)
|
||||
:
|
||||
BLanguage(language),
|
||||
fServerName(serverName),
|
||||
@@ -35,6 +34,27 @@ Language::Language(const Language& other)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Language::operator==(const Language& other) const
|
||||
{
|
||||
return Compare(other) == 0;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Language::operator!=(const Language& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Language::operator<(const Language& other) const
|
||||
{
|
||||
return Compare(other) < 0;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Language::GetName(BString& name, const BLanguage* displayLanguage) const
|
||||
{
|
||||
@@ -60,9 +80,9 @@ Language::Compare(const Language& other) const
|
||||
|
||||
|
||||
bool
|
||||
IsLanguageBefore(const LanguageRef& l1, const LanguageRef& l2)
|
||||
IsLanguageRefLess(const LanguageRef& l1, const LanguageRef& l2)
|
||||
{
|
||||
if (!l1.IsSet() || !l2.IsSet())
|
||||
HDFATAL("unexpected NULL reference in a referencable");
|
||||
return l1.Get()->Compare(*(l2.Get())) < 0;
|
||||
debugger("illegal state in language less");
|
||||
return *(l1.Get()) < *(l2.Get());
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2016-2023, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef LANGUAGE_H
|
||||
@@ -14,6 +14,10 @@
|
||||
/*! This class represents a language that is supported by the Haiku
|
||||
Depot Server system. This may differ from the set of languages
|
||||
that are supported in the platform itself.
|
||||
|
||||
No builder is provided for this class because it sub-classes from
|
||||
a Haiku type. Instead always create new instances with the constructor
|
||||
and do not use any mutating functions offered by the superclass.
|
||||
*/
|
||||
|
||||
class Language : public BReferenceable, public BLanguage {
|
||||
@@ -23,6 +27,10 @@ public:
|
||||
bool isPopular);
|
||||
Language(const Language& other);
|
||||
|
||||
bool operator<(const Language& other) const;
|
||||
bool operator==(const Language& other) const;
|
||||
bool operator!=(const Language& other) const;
|
||||
|
||||
status_t GetName(BString& name,
|
||||
const BLanguage* displayLanguage = NULL
|
||||
) const;
|
||||
@@ -40,7 +48,7 @@ private:
|
||||
typedef BReference<Language> LanguageRef;
|
||||
|
||||
|
||||
extern bool IsLanguageBefore(const LanguageRef& l1, const LanguageRef& l2);
|
||||
extern bool IsLanguageRefLess(const LanguageRef& l1, const LanguageRef& l2);
|
||||
|
||||
|
||||
#endif // LANGUAGE_H
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2013, Rene Gollent <[email protected]>.
|
||||
* Copyright 2016-2023, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -41,12 +41,10 @@ PackageCategory::PackageCategory(const PackageCategory& other)
|
||||
}
|
||||
|
||||
|
||||
PackageCategory&
|
||||
PackageCategory::operator=(const PackageCategory& other)
|
||||
bool
|
||||
PackageCategory::operator<(const PackageCategory& other) const
|
||||
{
|
||||
fCode = other.fCode;
|
||||
fName = other.fName;
|
||||
return *this;
|
||||
return Compare(other) < 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,18 +66,17 @@ int
|
||||
PackageCategory::Compare(const PackageCategory& other) const
|
||||
{
|
||||
BCollator* collator = LocaleUtils::GetSharedCollator();
|
||||
int32 result = collator->Compare(Name().String(),
|
||||
other.Name().String());
|
||||
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)
|
||||
bool
|
||||
IsPackageCategoryRefLess(const CategoryRef& c1, const CategoryRef& c2)
|
||||
{
|
||||
if (!c1.IsSet() || !c2.IsSet())
|
||||
HDFATAL("unexpected NULL reference in a referencable");
|
||||
return c1->Compare(*c2) < 0;
|
||||
HDFATAL("illegal state in package category less");
|
||||
return *(c1.Get()) < *(c2.Get());
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2016-2023, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_CATEGORY_H
|
||||
@@ -11,6 +11,13 @@
|
||||
#include <String.h>
|
||||
|
||||
|
||||
/*! This class represents a category into which a package may be assigned. The
|
||||
`code` corresponds to a code on the server.
|
||||
|
||||
No builder is provided for this class; always create new instances using
|
||||
the constructor.
|
||||
*/
|
||||
|
||||
class PackageCategory : public BReferenceable {
|
||||
public:
|
||||
PackageCategory();
|
||||
@@ -18,7 +25,7 @@ public:
|
||||
const BString& name);
|
||||
PackageCategory(const PackageCategory& other);
|
||||
|
||||
PackageCategory& operator=(const PackageCategory& other);
|
||||
bool operator<(const PackageCategory& other) const;
|
||||
bool operator==(const PackageCategory& other) const;
|
||||
bool operator!=(const PackageCategory& other) const;
|
||||
|
||||
@@ -38,7 +45,7 @@ private:
|
||||
typedef BReference<PackageCategory> CategoryRef;
|
||||
|
||||
|
||||
extern bool IsPackageCategoryBefore(const CategoryRef& c1, const CategoryRef& c2);
|
||||
extern bool IsPackageCategoryRefLess(const CategoryRef& c1, const CategoryRef& c2);
|
||||
|
||||
|
||||
#endif // PACKAGE_CATEGORY_H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
PackageClassificationInfo::PackageClassificationInfo()
|
||||
:
|
||||
fCategories(),
|
||||
fProminence(-1L),
|
||||
fProminence(PROMINANCE_ORDERING_NONE),
|
||||
fIsNativeDesktop(false)
|
||||
{
|
||||
}
|
||||
@@ -29,6 +29,20 @@ PackageClassificationInfo::PackageClassificationInfo(const PackageClassification
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
PackageClassificationInfo::Prominence() const
|
||||
{
|
||||
return fProminence;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageClassificationInfo::HasProminence() const
|
||||
{
|
||||
return fProminence != 0;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
PackageClassificationInfo::CountCategories() const
|
||||
{
|
||||
@@ -36,26 +50,18 @@ PackageClassificationInfo::CountCategories() const
|
||||
}
|
||||
|
||||
|
||||
CategoryRef
|
||||
const 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);
|
||||
fCategories.end(), category, &IsPackageCategoryRefLess);
|
||||
|
||||
if (itInsertionPt == fCategories.end()) {
|
||||
fCategories.push_back(category);
|
||||
@@ -131,3 +137,104 @@ PackageClassificationInfo::operator!=(const PackageClassificationInfo& other) co
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - PackageClassificationInfoBuilder
|
||||
|
||||
|
||||
PackageClassificationInfoBuilder::PackageClassificationInfoBuilder()
|
||||
:
|
||||
fCategories(),
|
||||
fProminence(-1L),
|
||||
fIsNativeDesktop(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageClassificationInfoBuilder::PackageClassificationInfoBuilder(
|
||||
const PackageClassificationInfoRef& value)
|
||||
:
|
||||
fCategories(),
|
||||
fProminence(PROMINANCE_ORDERING_NONE),
|
||||
fIsNativeDesktop(false)
|
||||
{
|
||||
fSource = value;
|
||||
}
|
||||
|
||||
|
||||
PackageClassificationInfoBuilder::~PackageClassificationInfoBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageClassificationInfoBuilder::_InitFromSource()
|
||||
{
|
||||
if (fSource.IsSet()) {
|
||||
_Init(fSource.Get());
|
||||
fSource.Unset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageClassificationInfoBuilder::_Init(const PackageClassificationInfo* value)
|
||||
{
|
||||
for (int32 i = value->CountCategories() - 1; i >= 0; i--)
|
||||
fCategories.push_back(value->CategoryAtIndex(i));
|
||||
fProminence = value->Prominence();
|
||||
fIsNativeDesktop = value->IsNativeDesktop();
|
||||
}
|
||||
|
||||
|
||||
PackageClassificationInfoRef
|
||||
PackageClassificationInfoBuilder::BuildRef() const
|
||||
{
|
||||
if (fSource.IsSet())
|
||||
return fSource;
|
||||
|
||||
PackageClassificationInfo* classificationInfo = new PackageClassificationInfo();
|
||||
|
||||
classificationInfo->SetProminence(fProminence);
|
||||
classificationInfo->SetIsNativeDesktop(fIsNativeDesktop);
|
||||
|
||||
std::vector<CategoryRef>::const_iterator it;
|
||||
|
||||
for (it = fCategories.begin(); it != fCategories.end(); it++)
|
||||
classificationInfo->AddCategory(*it);
|
||||
|
||||
return PackageClassificationInfoRef(classificationInfo, true);
|
||||
}
|
||||
|
||||
|
||||
PackageClassificationInfoBuilder&
|
||||
PackageClassificationInfoBuilder::WithProminence(uint32 prominence)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Prominence() != prominence) {
|
||||
_InitFromSource();
|
||||
fProminence = prominence;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageClassificationInfoBuilder&
|
||||
PackageClassificationInfoBuilder::WithIsNativeDesktop(bool value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->IsNativeDesktop() != value) {
|
||||
_InitFromSource();
|
||||
fIsNativeDesktop = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageClassificationInfoBuilder&
|
||||
PackageClassificationInfoBuilder::AddCategory(const CategoryRef& category)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->HasCategoryByCode(category->Code())) {
|
||||
_InitFromSource();
|
||||
fCategories.push_back(category);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_CLASSIFICATION_INFO_H
|
||||
@@ -13,8 +13,16 @@
|
||||
#include "PackageCategory.h"
|
||||
|
||||
|
||||
class PackageClassificationInfoBuilder;
|
||||
|
||||
|
||||
/*! Instances of this class should not be created directly; instead use the
|
||||
PackageClassificationInfoBuilder class as a builder-constructor.
|
||||
*/
|
||||
class PackageClassificationInfo : public BReferenceable
|
||||
{
|
||||
friend class PackageClassificationInfoBuilder;
|
||||
|
||||
public:
|
||||
PackageClassificationInfo();
|
||||
PackageClassificationInfo(const PackageClassificationInfo& other);
|
||||
@@ -22,20 +30,20 @@ public:
|
||||
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; }
|
||||
uint32 Prominence() const;
|
||||
bool HasProminence() const;
|
||||
bool IsProminent() const;
|
||||
|
||||
void ClearCategories();
|
||||
bool AddCategory(const CategoryRef& category);
|
||||
int32 CountCategories() const;
|
||||
CategoryRef CategoryAtIndex(int32 index) const;
|
||||
const CategoryRef CategoryAtIndex(int32 index) const;
|
||||
bool HasCategoryByCode(const BString& code) const;
|
||||
|
||||
bool IsNativeDesktop() const;
|
||||
|
||||
private:
|
||||
void SetProminence(uint32 prominence);
|
||||
void ClearCategories();
|
||||
bool AddCategory(const CategoryRef& category);
|
||||
void SetIsNativeDesktop(bool value);
|
||||
|
||||
private:
|
||||
@@ -49,4 +57,37 @@ private:
|
||||
typedef BReference<PackageClassificationInfo> PackageClassificationInfoRef;
|
||||
|
||||
|
||||
class PackageClassificationInfoBuilder
|
||||
{
|
||||
public:
|
||||
PackageClassificationInfoBuilder();
|
||||
PackageClassificationInfoBuilder(
|
||||
const PackageClassificationInfoRef& value);
|
||||
virtual ~PackageClassificationInfoBuilder();
|
||||
|
||||
PackageClassificationInfoRef
|
||||
BuildRef() const;
|
||||
|
||||
PackageClassificationInfoBuilder&
|
||||
WithProminence(uint32 prominence);
|
||||
PackageClassificationInfoBuilder&
|
||||
WithIsNativeDesktop(bool value);
|
||||
|
||||
PackageClassificationInfoBuilder&
|
||||
AddCategory(const CategoryRef& category);
|
||||
|
||||
private:
|
||||
void _InitFromSource();
|
||||
void _Init(const PackageClassificationInfo* value);
|
||||
|
||||
private:
|
||||
PackageClassificationInfoRef
|
||||
fSource;
|
||||
std::vector<CategoryRef>
|
||||
fCategories;
|
||||
uint32 fProminence;
|
||||
bool fIsNativeDesktop;
|
||||
};
|
||||
|
||||
|
||||
#endif // PACKAGE_CLASSIFICATION_INFO_H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -34,18 +34,6 @@ PackageCoreInfo::~PackageCoreInfo()
|
||||
}
|
||||
|
||||
|
||||
PackageCoreInfo&
|
||||
PackageCoreInfo::operator=(const PackageCoreInfo& other)
|
||||
{
|
||||
fVersion = other.fVersion;
|
||||
fPublisher = other.fPublisher;
|
||||
fArchitecture = other.fArchitecture;
|
||||
fDepotName = other.fDepotName;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageCoreInfo::operator==(const PackageCoreInfo& other) const
|
||||
{
|
||||
@@ -63,6 +51,34 @@ PackageCoreInfo::operator!=(const PackageCoreInfo& other) const
|
||||
}
|
||||
|
||||
|
||||
const PackageVersionRef&
|
||||
PackageCoreInfo::Version() const
|
||||
{
|
||||
return fVersion;
|
||||
}
|
||||
|
||||
|
||||
const PackagePublisherInfoRef&
|
||||
PackageCoreInfo::Publisher() const
|
||||
{
|
||||
return fPublisher;
|
||||
}
|
||||
|
||||
|
||||
const BString
|
||||
PackageCoreInfo::Architecture() const
|
||||
{
|
||||
return fArchitecture;
|
||||
}
|
||||
|
||||
|
||||
const BString&
|
||||
PackageCoreInfo::DepotName() const
|
||||
{
|
||||
return fDepotName;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageCoreInfo::SetVersion(PackageVersionRef value)
|
||||
{
|
||||
@@ -89,3 +105,112 @@ PackageCoreInfo::SetDepotName(const BString& value)
|
||||
{
|
||||
fDepotName = value;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - PackageCoreInfoBuilder
|
||||
|
||||
|
||||
PackageCoreInfoBuilder::PackageCoreInfoBuilder()
|
||||
:
|
||||
fVersion(),
|
||||
fPublisher(),
|
||||
fArchitecture(),
|
||||
fDepotName()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageCoreInfoBuilder::PackageCoreInfoBuilder(const PackageCoreInfoRef& other)
|
||||
:
|
||||
fVersion(),
|
||||
fPublisher(),
|
||||
fArchitecture(),
|
||||
fDepotName()
|
||||
{
|
||||
fSource = other;
|
||||
}
|
||||
|
||||
|
||||
PackageCoreInfoBuilder::~PackageCoreInfoBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageCoreInfoBuilder::_InitFromSource()
|
||||
{
|
||||
if (fSource.IsSet()) {
|
||||
_Init(fSource.Get());
|
||||
fSource.Unset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageCoreInfoBuilder::_Init(const PackageCoreInfo* other)
|
||||
{
|
||||
fVersion = other->Version();
|
||||
fPublisher = other->Publisher();
|
||||
fArchitecture = other->Architecture();
|
||||
fDepotName = other->DepotName();
|
||||
}
|
||||
|
||||
|
||||
PackageCoreInfoRef
|
||||
PackageCoreInfoBuilder::BuildRef()
|
||||
{
|
||||
if (fSource.IsSet())
|
||||
return fSource;
|
||||
|
||||
PackageCoreInfo* coreInfo = new PackageCoreInfo();
|
||||
coreInfo->SetVersion(fVersion);
|
||||
coreInfo->SetPublisher(fPublisher);
|
||||
coreInfo->SetArchitecture(fArchitecture);
|
||||
coreInfo->SetDepotName(fDepotName);
|
||||
|
||||
return PackageCoreInfoRef(coreInfo, true);
|
||||
}
|
||||
|
||||
|
||||
PackageCoreInfoBuilder&
|
||||
PackageCoreInfoBuilder::WithVersion(PackageVersionRef value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Version() != value) {
|
||||
_InitFromSource();
|
||||
fVersion = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageCoreInfoBuilder&
|
||||
PackageCoreInfoBuilder::WithPublisher(PackagePublisherInfoRef value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Publisher() != value) {
|
||||
_InitFromSource();
|
||||
fPublisher = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageCoreInfoBuilder&
|
||||
PackageCoreInfoBuilder::WithArchitecture(const BString& value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Architecture() != value) {
|
||||
_InitFromSource();
|
||||
fArchitecture = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageCoreInfoBuilder&
|
||||
PackageCoreInfoBuilder::WithDepotName(const BString& value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->DepotName() != value) {
|
||||
_InitFromSource();
|
||||
fDepotName = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_CORE_INFO_H
|
||||
@@ -15,38 +15,79 @@
|
||||
using BPackageKit::BPackageVersion;
|
||||
|
||||
|
||||
class PackageCoreInfoBuilder;
|
||||
|
||||
|
||||
/*! This class models the core data for the package.
|
||||
|
||||
Instances of this class should not be created directly; instead use the
|
||||
PackageCoreInfoBuilder class as a builder-constructor.
|
||||
*/
|
||||
class PackageCoreInfo : public BReferenceable
|
||||
{
|
||||
friend class PackageCoreInfoBuilder;
|
||||
|
||||
public:
|
||||
PackageCoreInfo();
|
||||
PackageCoreInfo(const PackageCoreInfo& other);
|
||||
virtual ~PackageCoreInfo();
|
||||
|
||||
PackageCoreInfo& operator=(const PackageCoreInfo& other);
|
||||
bool operator==(const PackageCoreInfo& other) const;
|
||||
bool operator!=(const PackageCoreInfo& other) const;
|
||||
|
||||
const PackageVersionRef&
|
||||
Version() const
|
||||
{ return fVersion; }
|
||||
void SetVersion(PackageVersionRef value);
|
||||
|
||||
Version() const;
|
||||
const PackagePublisherInfoRef&
|
||||
Publisher() const
|
||||
{ return fPublisher; }
|
||||
void SetPublisher(PackagePublisherInfoRef value);
|
||||
|
||||
const BString Architecture() const
|
||||
{ return fArchitecture; }
|
||||
void SetArchitecture(const BString& value);
|
||||
|
||||
void SetDepotName(const BString& value);
|
||||
const BString& DepotName() const
|
||||
{ return fDepotName; }
|
||||
Publisher() const;
|
||||
const BString Architecture() const;
|
||||
const BString& DepotName() const;
|
||||
|
||||
private:
|
||||
void SetVersion(PackageVersionRef value);
|
||||
void SetPublisher(PackagePublisherInfoRef value);
|
||||
void SetArchitecture(const BString& value);
|
||||
void SetDepotName(const BString& value);
|
||||
|
||||
private:
|
||||
PackageVersionRef
|
||||
fVersion;
|
||||
PackagePublisherInfoRef
|
||||
fPublisher;
|
||||
BString fArchitecture;
|
||||
BString fDepotName;
|
||||
// The name and not the identifier are used here because the
|
||||
// identifier is not readily available in all API situations.
|
||||
};
|
||||
|
||||
|
||||
typedef BReference<PackageCoreInfo> PackageCoreInfoRef;
|
||||
|
||||
|
||||
class PackageCoreInfoBuilder
|
||||
{
|
||||
public:
|
||||
PackageCoreInfoBuilder();
|
||||
PackageCoreInfoBuilder(const PackageCoreInfoRef& other);
|
||||
virtual ~PackageCoreInfoBuilder();
|
||||
|
||||
PackageCoreInfoRef BuildRef();
|
||||
|
||||
PackageCoreInfoBuilder&
|
||||
WithVersion(PackageVersionRef value);
|
||||
PackageCoreInfoBuilder&
|
||||
WithPublisher(PackagePublisherInfoRef value);
|
||||
PackageCoreInfoBuilder&
|
||||
WithArchitecture(const BString& value);
|
||||
PackageCoreInfoBuilder&
|
||||
WithDepotName(const BString& value);
|
||||
|
||||
private:
|
||||
void _InitFromSource();
|
||||
void _Init(const PackageCoreInfo* value);
|
||||
|
||||
private:
|
||||
PackageCoreInfoRef
|
||||
fSource;
|
||||
PackageVersionRef
|
||||
fVersion;
|
||||
PackagePublisherInfoRef
|
||||
@@ -56,7 +97,4 @@ private:
|
||||
};
|
||||
|
||||
|
||||
typedef BReference<PackageCoreInfo> PackageCoreInfoRef;
|
||||
|
||||
|
||||
#endif // PACKAGE_CORE_INFO_H
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2014, Axel Dörfler <[email protected]>.
|
||||
* Copyright 2016-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Note that this file included code earlier from `Model.cpp` and
|
||||
* copyrights have been latterly been carried across in 2024.
|
||||
*/
|
||||
|
||||
|
||||
#include "PackageFilter.h"
|
||||
|
||||
#include "Logger.h"
|
||||
#include "PackageFilterSpecification.h"
|
||||
#include "PackageUtils.h"
|
||||
|
||||
|
||||
@@ -52,6 +53,20 @@ AndFilter::AcceptsPackage(const PackageInfoRef& package) const
|
||||
}
|
||||
|
||||
|
||||
class FalseFilter : public PackageFilter
|
||||
{
|
||||
public:
|
||||
FalseFilter()
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool AcceptsPackage(const PackageInfoRef& package) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class StateFilter : public PackageFilter
|
||||
{
|
||||
public:
|
||||
@@ -138,16 +153,14 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class DevelopmentFilter : public PackageFilter
|
||||
{
|
||||
class DevelopmentFilter : public PackageFilter {
|
||||
public:
|
||||
virtual bool AcceptsPackage(const PackageInfoRef& package) const
|
||||
{
|
||||
if (!package.IsSet())
|
||||
return false;
|
||||
const BString& packageName = package->Name();
|
||||
return packageName.EndsWith("_devel")
|
||||
|| packageName.EndsWith("_debuginfo");
|
||||
return packageName.EndsWith("_devel") || packageName.EndsWith("_debuginfo");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -179,8 +192,7 @@ public:
|
||||
// Every search term must be found in one of the package texts
|
||||
for (int32 i = fSearchTerms.CountStrings() - 1; i >= 0; i--) {
|
||||
const BString& term = fSearchTerms.StringAt(i);
|
||||
if (package->Name().FindFirst(term) < 0
|
||||
&& !_AcceptsPackageFromPublisher(package, term)
|
||||
if (package->Name().FindFirst(term) < 0 && !_AcceptsPackageFromPublisher(package, term)
|
||||
&& !_AcceptsPackageFromLocalizedText(package, term)) {
|
||||
return false;
|
||||
}
|
||||
@@ -199,15 +211,15 @@ public:
|
||||
searchTerms.Append(" ");
|
||||
searchTerms.Append(term);
|
||||
}
|
||||
return searchTerms;
|
||||
return searchTerms;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _TextContains(BString text, const BString& string) const
|
||||
{
|
||||
bool _TextContains(BString text, const BString& string) const
|
||||
{
|
||||
int32 index = text.IFindFirst(string);
|
||||
return index >= 0;
|
||||
}
|
||||
return index >= 0;
|
||||
}
|
||||
|
||||
bool _AcceptsPackageFromPublisher(const PackageInfoRef& package,
|
||||
const BString& searchTerm) const
|
||||
@@ -228,12 +240,12 @@ private:
|
||||
return false;
|
||||
|
||||
return _TextContains(localizedText->Title(), searchTerm)
|
||||
|| _TextContains(localizedText->Summary(), searchTerm)
|
||||
|| _TextContains(localizedText->Description(), searchTerm);
|
||||
|| _TextContains(localizedText->Summary(), searchTerm)
|
||||
|| _TextContains(localizedText->Description(), searchTerm);
|
||||
}
|
||||
|
||||
private:
|
||||
BStringList fSearchTerms;
|
||||
BStringList fSearchTerms;
|
||||
};
|
||||
|
||||
|
||||
@@ -280,3 +292,43 @@ PackageFilterFactory::CreateDevelopmentFilter()
|
||||
{
|
||||
return PackageFilterRef(new DevelopmentFilter(), true);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ PackageFilterRef
|
||||
PackageFilterFactory::CreateFalseFilter()
|
||||
{
|
||||
return PackageFilterRef(new FalseFilter(), true);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ PackageFilterRef
|
||||
PackageFilterFactory::CreateFilter(const PackageFilterSpecificationRef specification)
|
||||
{
|
||||
if (!specification.IsSet())
|
||||
return CreateFalseFilter();
|
||||
|
||||
AndFilter* andFilter = new AndFilter();
|
||||
|
||||
if (!specification->SearchTerms().IsEmpty())
|
||||
andFilter->AddFilter(CreateSearchTermsFilter(specification->SearchTerms()));
|
||||
|
||||
if (!specification->DepotName().IsEmpty())
|
||||
andFilter->AddFilter(CreateDepotFilter(specification->DepotName()));
|
||||
|
||||
if (!specification->Category().IsEmpty())
|
||||
andFilter->AddFilter(CreateCategoryFilter(specification->Category()));
|
||||
|
||||
if (!specification->ShowAvailablePackages())
|
||||
andFilter->AddFilter(PackageFilterRef(new NotFilter(CreateStateFilter(NONE)), true));
|
||||
|
||||
if (!specification->ShowInstalledPackages())
|
||||
andFilter->AddFilter(PackageFilterRef(new NotFilter(CreateStateFilter(ACTIVATED)), true));
|
||||
|
||||
if (!specification->ShowSourcePackages())
|
||||
andFilter->AddFilter(PackageFilterRef(new NotFilter(CreateSourceFilter()), true));
|
||||
|
||||
if (!specification->ShowDevelopPackages())
|
||||
andFilter->AddFilter(PackageFilterRef(new NotFilter(CreateDevelopmentFilter()), true));
|
||||
|
||||
return PackageFilterRef(andFilter, true);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2016-2023, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Note that this file included code earlier from `Model.cpp` and
|
||||
@@ -14,9 +14,13 @@
|
||||
#include <Referenceable.h>
|
||||
#include <String.h>
|
||||
|
||||
#include "PackageFilterSpecification.h"
|
||||
#include "PackageInfo.h"
|
||||
|
||||
|
||||
/*! See the class PackageFilterFactory for static factory methods that will
|
||||
create concrete instances of this abstract superclass.
|
||||
*/
|
||||
class PackageFilter : public BReferenceable
|
||||
{
|
||||
public:
|
||||
@@ -61,6 +65,8 @@ public:
|
||||
static PackageFilterRef CreateStateFilter(PackageState state);
|
||||
static PackageFilterRef CreateSourceFilter();
|
||||
static PackageFilterRef CreateDevelopmentFilter();
|
||||
static PackageFilterRef CreateFalseFilter();
|
||||
static PackageFilterRef CreateFilter(const PackageFilterSpecificationRef specification);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "PackageFilterModel.h"
|
||||
|
||||
|
||||
PackageFilterModel::PackageFilterModel()
|
||||
:
|
||||
fSearchTerms(""),
|
||||
fDepotName(""),
|
||||
fCategory(""),
|
||||
fShowAvailablePackages(true),
|
||||
fShowInstalledPackages(true),
|
||||
fShowSourcePackages(false),
|
||||
fShowDevelopPackages(false)
|
||||
{
|
||||
fFilter = _CreateFilter();
|
||||
}
|
||||
|
||||
|
||||
PackageFilterModel::~PackageFilterModel()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
PackageFilterModel::SearchTerms() const
|
||||
{
|
||||
return fSearchTerms;
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
PackageFilterModel::DepotName() const
|
||||
{
|
||||
return fDepotName;
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
PackageFilterModel::Category() const
|
||||
{
|
||||
return fCategory;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageFilterModel::ShowAvailablePackages() const
|
||||
{
|
||||
return fShowAvailablePackages;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageFilterModel::ShowInstalledPackages() const
|
||||
{
|
||||
return fShowInstalledPackages;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageFilterModel::ShowSourcePackages() const
|
||||
{
|
||||
return fShowSourcePackages;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageFilterModel::ShowDevelopPackages() const
|
||||
{
|
||||
return fShowDevelopPackages;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterModel::SetSearchTerms(BString value)
|
||||
{
|
||||
if (fSearchTerms != value) {
|
||||
fSearchTerms = value;
|
||||
fFilter = _CreateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterModel::SetDepotName(BString value)
|
||||
{
|
||||
if (fDepotName != value) {
|
||||
fDepotName = value;
|
||||
fFilter = _CreateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterModel::SetCategory(BString value)
|
||||
{
|
||||
if (fCategory != value) {
|
||||
fCategory = value;
|
||||
fFilter = _CreateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterModel::SetShowAvailablePackages(bool value)
|
||||
{
|
||||
if (fShowAvailablePackages != value) {
|
||||
fShowAvailablePackages = value;
|
||||
fFilter = _CreateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterModel::SetShowInstalledPackages(bool value)
|
||||
{
|
||||
if (fShowInstalledPackages != value) {
|
||||
fShowInstalledPackages = value;
|
||||
fFilter = _CreateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterModel::SetShowSourcePackages(bool value)
|
||||
{
|
||||
if (fShowSourcePackages != value) {
|
||||
fShowSourcePackages = value;
|
||||
fFilter = _CreateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterModel::SetShowDevelopPackages(bool value)
|
||||
{
|
||||
if (fShowDevelopPackages != value) {
|
||||
fShowDevelopPackages = value;
|
||||
fFilter = _CreateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PackageFilterRef
|
||||
PackageFilterModel::Filter()
|
||||
{
|
||||
return fFilter;
|
||||
}
|
||||
|
||||
|
||||
PackageFilterRef
|
||||
PackageFilterModel::_CreateFilter() const
|
||||
{
|
||||
AndFilter* andFilter = new AndFilter();
|
||||
if (!fSearchTerms.IsEmpty())
|
||||
andFilter->AddFilter(PackageFilterFactory::CreateSearchTermsFilter(fSearchTerms));
|
||||
if (!fDepotName.IsEmpty())
|
||||
andFilter->AddFilter(PackageFilterFactory::CreateDepotFilter(fDepotName));
|
||||
if (!fCategory.IsEmpty())
|
||||
andFilter->AddFilter(PackageFilterFactory::CreateCategoryFilter(fCategory));
|
||||
if (!fShowAvailablePackages) {
|
||||
andFilter->AddFilter(
|
||||
PackageFilterRef(new NotFilter(PackageFilterFactory::CreateStateFilter(NONE)), true));
|
||||
}
|
||||
if (!fShowInstalledPackages) {
|
||||
andFilter->AddFilter(PackageFilterRef(
|
||||
new NotFilter(PackageFilterFactory::CreateStateFilter(ACTIVATED)), true));
|
||||
}
|
||||
if (!fShowSourcePackages) {
|
||||
andFilter->AddFilter(
|
||||
PackageFilterRef(new NotFilter(PackageFilterFactory::CreateSourceFilter()), true));
|
||||
}
|
||||
if (!fShowDevelopPackages) {
|
||||
andFilter->AddFilter(
|
||||
PackageFilterRef(new NotFilter(PackageFilterFactory::CreateDevelopmentFilter()), true));
|
||||
}
|
||||
return PackageFilterRef(andFilter, true);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_FILTER_MODEL_H
|
||||
#define PACKAGE_FILTER_MODEL_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include "PackageFilter.h"
|
||||
|
||||
|
||||
class PackageFilterModel
|
||||
{
|
||||
public:
|
||||
PackageFilterModel();
|
||||
virtual ~PackageFilterModel();
|
||||
|
||||
BString SearchTerms() const;
|
||||
BString DepotName() const;
|
||||
BString Category() const;
|
||||
bool ShowAvailablePackages() const;
|
||||
bool ShowInstalledPackages() const;
|
||||
bool ShowSourcePackages() const;
|
||||
bool ShowDevelopPackages() const;
|
||||
|
||||
void SetSearchTerms(BString value);
|
||||
void SetDepotName(BString value);
|
||||
void SetCategory(BString value);
|
||||
void SetShowAvailablePackages(bool value);
|
||||
void SetShowInstalledPackages(bool value);
|
||||
void SetShowSourcePackages(bool value);
|
||||
void SetShowDevelopPackages(bool value);
|
||||
|
||||
PackageFilterRef Filter();
|
||||
|
||||
private:
|
||||
PackageFilterRef _CreateFilter() const;
|
||||
|
||||
private:
|
||||
BString fSearchTerms;
|
||||
BString fDepotName;
|
||||
BString fCategory;
|
||||
bool fShowAvailablePackages;
|
||||
bool fShowInstalledPackages;
|
||||
bool fShowSourcePackages;
|
||||
bool fShowDevelopPackages;
|
||||
|
||||
PackageFilterRef fFilter;
|
||||
};
|
||||
|
||||
|
||||
#endif // PACKAGE_FILTER_MODEL_H
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright 2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "PackageFilterSpecification.h"
|
||||
|
||||
|
||||
PackageFilterSpecification::PackageFilterSpecification()
|
||||
:
|
||||
fSearchTerms(""),
|
||||
fDepotName(""),
|
||||
fCategory(""),
|
||||
fShowAvailablePackages(true),
|
||||
fShowInstalledPackages(true),
|
||||
fShowSourcePackages(false),
|
||||
fShowDevelopPackages(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageFilterSpecification::~PackageFilterSpecification()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageFilterSpecification::operator==(const PackageFilterSpecification& other) const
|
||||
{
|
||||
return fSearchTerms == other.SearchTerms() && fDepotName == other.DepotName()
|
||||
&& fCategory == other.Category() && fShowAvailablePackages == other.ShowAvailablePackages()
|
||||
&& fShowInstalledPackages == other.ShowInstalledPackages()
|
||||
&& fShowDevelopPackages == other.ShowDevelopPackages();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageFilterSpecification::operator!=(const PackageFilterSpecification& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
PackageFilterSpecification::SearchTerms() const
|
||||
{
|
||||
return fSearchTerms;
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
PackageFilterSpecification::DepotName() const
|
||||
{
|
||||
return fDepotName;
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
PackageFilterSpecification::Category() const
|
||||
{
|
||||
return fCategory;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageFilterSpecification::ShowAvailablePackages() const
|
||||
{
|
||||
return fShowAvailablePackages;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageFilterSpecification::ShowInstalledPackages() const
|
||||
{
|
||||
return fShowInstalledPackages;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageFilterSpecification::ShowSourcePackages() const
|
||||
{
|
||||
return fShowSourcePackages;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageFilterSpecification::ShowDevelopPackages() const
|
||||
{
|
||||
return fShowDevelopPackages;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterSpecification::SetSearchTerms(BString value)
|
||||
{
|
||||
fSearchTerms = value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterSpecification::SetDepotName(BString value)
|
||||
{
|
||||
fDepotName = value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterSpecification::SetCategory(BString value)
|
||||
{
|
||||
fCategory = value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterSpecification::SetShowAvailablePackages(bool value)
|
||||
{
|
||||
fShowAvailablePackages = value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterSpecification::SetShowInstalledPackages(bool value)
|
||||
{
|
||||
fShowInstalledPackages = value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterSpecification::SetShowSourcePackages(bool value)
|
||||
{
|
||||
fShowSourcePackages = value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterSpecification::SetShowDevelopPackages(bool value)
|
||||
{
|
||||
fShowDevelopPackages = value;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - PackageClassificationInfoBuilder
|
||||
|
||||
|
||||
PackageFilterSpecificationBuilder::PackageFilterSpecificationBuilder()
|
||||
:
|
||||
fSearchTerms(""),
|
||||
fDepotName(""),
|
||||
fCategory(""),
|
||||
fShowAvailablePackages(true),
|
||||
fShowInstalledPackages(true),
|
||||
fShowSourcePackages(false),
|
||||
fShowDevelopPackages(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageFilterSpecificationBuilder::PackageFilterSpecificationBuilder(
|
||||
const PackageFilterSpecificationRef& value)
|
||||
:
|
||||
fSource(value),
|
||||
fSearchTerms(""),
|
||||
fDepotName(""),
|
||||
fCategory(""),
|
||||
fShowAvailablePackages(true),
|
||||
fShowInstalledPackages(true),
|
||||
fShowSourcePackages(false),
|
||||
fShowDevelopPackages(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageFilterSpecificationBuilder::~PackageFilterSpecificationBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterSpecificationBuilder::_InitFromSource()
|
||||
{
|
||||
if (fSource.IsSet()) {
|
||||
_Init(fSource);
|
||||
fSource.Unset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFilterSpecificationBuilder::_Init(const PackageFilterSpecification* value)
|
||||
{
|
||||
fSearchTerms = value->SearchTerms();
|
||||
fDepotName = value->DepotName();
|
||||
fCategory = value->Category();
|
||||
fShowAvailablePackages = value->ShowAvailablePackages();
|
||||
fShowInstalledPackages = value->ShowInstalledPackages();
|
||||
fShowSourcePackages = value->ShowSourcePackages();
|
||||
fShowDevelopPackages = value->ShowDevelopPackages();
|
||||
}
|
||||
|
||||
|
||||
PackageFilterSpecificationRef
|
||||
PackageFilterSpecificationBuilder::BuildRef()
|
||||
{
|
||||
if (fSource.IsSet())
|
||||
return fSource;
|
||||
|
||||
PackageFilterSpecification* info = new PackageFilterSpecification();
|
||||
info->SetSearchTerms(fSearchTerms);
|
||||
info->SetDepotName(fDepotName);
|
||||
info->SetCategory(fCategory);
|
||||
info->SetShowAvailablePackages(fShowAvailablePackages);
|
||||
info->SetShowInstalledPackages(fShowInstalledPackages);
|
||||
info->SetShowSourcePackages(fShowSourcePackages);
|
||||
info->SetShowDevelopPackages(fShowDevelopPackages);
|
||||
return PackageFilterSpecificationRef(info, true);
|
||||
}
|
||||
|
||||
|
||||
PackageFilterSpecificationBuilder
|
||||
PackageFilterSpecificationBuilder::WithSearchTerms(BString value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->SearchTerms() != value) {
|
||||
_InitFromSource();
|
||||
fSearchTerms = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageFilterSpecificationBuilder
|
||||
PackageFilterSpecificationBuilder::WithDepotName(BString value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->DepotName() != value) {
|
||||
_InitFromSource();
|
||||
fDepotName = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageFilterSpecificationBuilder
|
||||
PackageFilterSpecificationBuilder::WithCategory(BString value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Category() != value) {
|
||||
_InitFromSource();
|
||||
fCategory = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageFilterSpecificationBuilder
|
||||
PackageFilterSpecificationBuilder::WithShowAvailablePackages(bool value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->ShowAvailablePackages() != value) {
|
||||
_InitFromSource();
|
||||
fShowAvailablePackages = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageFilterSpecificationBuilder
|
||||
PackageFilterSpecificationBuilder::WithShowInstalledPackages(bool value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->ShowInstalledPackages() != value) {
|
||||
_InitFromSource();
|
||||
fShowInstalledPackages = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageFilterSpecificationBuilder
|
||||
PackageFilterSpecificationBuilder::WithShowSourcePackages(bool value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->ShowSourcePackages() != value) {
|
||||
_InitFromSource();
|
||||
fShowSourcePackages = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageFilterSpecificationBuilder
|
||||
PackageFilterSpecificationBuilder::WithShowDevelopPackages(bool value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->ShowDevelopPackages() != value) {
|
||||
_InitFromSource();
|
||||
fShowDevelopPackages = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_FILTER_SPECIFICATION_H
|
||||
#define PACKAGE_FILTER_SPECIFICATION_H
|
||||
|
||||
#include <Referenceable.h>
|
||||
#include <String.h>
|
||||
|
||||
|
||||
/*! Instances of this class should not be created directly; instead use the
|
||||
PackageFilterSpecificationBuilder class as a builder-constructor.
|
||||
*/
|
||||
class PackageFilterSpecification : public BReferenceable
|
||||
{
|
||||
friend class PackageFilterSpecificationBuilder;
|
||||
|
||||
public:
|
||||
PackageFilterSpecification();
|
||||
virtual ~PackageFilterSpecification();
|
||||
|
||||
bool operator==(const PackageFilterSpecification& other) const;
|
||||
bool operator!=(const PackageFilterSpecification& other) const;
|
||||
|
||||
BString SearchTerms() const;
|
||||
BString DepotName() const;
|
||||
BString Category() const;
|
||||
bool ShowAvailablePackages() const;
|
||||
bool ShowInstalledPackages() const;
|
||||
bool ShowSourcePackages() const;
|
||||
bool ShowDevelopPackages() const;
|
||||
|
||||
private:
|
||||
void SetSearchTerms(BString value);
|
||||
void SetDepotName(BString value);
|
||||
void SetCategory(BString value);
|
||||
void SetShowAvailablePackages(bool value);
|
||||
void SetShowInstalledPackages(bool value);
|
||||
void SetShowSourcePackages(bool value);
|
||||
void SetShowDevelopPackages(bool value);
|
||||
|
||||
private:
|
||||
BString fSearchTerms;
|
||||
BString fDepotName;
|
||||
BString fCategory;
|
||||
bool fShowAvailablePackages;
|
||||
bool fShowInstalledPackages;
|
||||
bool fShowSourcePackages;
|
||||
bool fShowDevelopPackages;
|
||||
};
|
||||
|
||||
|
||||
typedef BReference<PackageFilterSpecification> PackageFilterSpecificationRef;
|
||||
|
||||
|
||||
class PackageFilterSpecificationBuilder
|
||||
{
|
||||
public:
|
||||
PackageFilterSpecificationBuilder();
|
||||
PackageFilterSpecificationBuilder(
|
||||
const PackageFilterSpecificationRef& other);
|
||||
virtual ~PackageFilterSpecificationBuilder();
|
||||
|
||||
PackageFilterSpecificationRef
|
||||
BuildRef();
|
||||
|
||||
PackageFilterSpecificationBuilder
|
||||
WithSearchTerms(BString value);
|
||||
PackageFilterSpecificationBuilder
|
||||
WithDepotName(BString value);
|
||||
PackageFilterSpecificationBuilder
|
||||
WithCategory(BString value);
|
||||
PackageFilterSpecificationBuilder
|
||||
WithShowAvailablePackages(bool value);
|
||||
PackageFilterSpecificationBuilder
|
||||
WithShowInstalledPackages(bool value);
|
||||
PackageFilterSpecificationBuilder
|
||||
WithShowSourcePackages(bool value);
|
||||
PackageFilterSpecificationBuilder
|
||||
WithShowDevelopPackages(bool value);
|
||||
|
||||
private:
|
||||
void _InitFromSource();
|
||||
void _Init(const PackageFilterSpecification* value);
|
||||
|
||||
private:
|
||||
PackageFilterSpecificationRef
|
||||
fSource;
|
||||
BString fSearchTerms;
|
||||
BString fDepotName;
|
||||
BString fCategory;
|
||||
bool fShowAvailablePackages;
|
||||
bool fShowInstalledPackages;
|
||||
bool fShowSourcePackages;
|
||||
bool fShowDevelopPackages;
|
||||
};
|
||||
|
||||
|
||||
#endif // PACKAGE_FILTER_SPECIFICATION_H
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2013, Rene Gollent <[email protected]>.
|
||||
* Copyright 2016-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "HaikuDepotConstants.h"
|
||||
#include "Logger.h"
|
||||
#include "PackageInfoListener.h"
|
||||
|
||||
|
||||
// #pragma mark - PackageInfo
|
||||
@@ -29,66 +30,11 @@ PackageInfo::PackageInfo()
|
||||
fClassificationInfo(),
|
||||
fScreenshotInfo(),
|
||||
fUserRatingInfo(),
|
||||
fLocalInfo(),
|
||||
|
||||
fListeners(),
|
||||
fIsCollatingChanges(false),
|
||||
fCollatedChanges(0)
|
||||
fLocalInfo()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageInfo::PackageInfo(const BPackageInfo& info)
|
||||
:
|
||||
fName(info.Name()),
|
||||
|
||||
fClassificationInfo(),
|
||||
fScreenshotInfo(),
|
||||
fUserRatingInfo(),
|
||||
|
||||
fListeners(),
|
||||
fIsCollatingChanges(false),
|
||||
fCollatedChanges(0)
|
||||
{
|
||||
|
||||
// TODO; factor this material out.
|
||||
|
||||
BString publisherURL;
|
||||
if (info.URLList().CountStrings() > 0)
|
||||
publisherURL = info.URLList().StringAt(0);
|
||||
|
||||
BString publisherName = info.Vendor();
|
||||
const BStringList& copyrightList = info.CopyrightList();
|
||||
if (!copyrightList.IsEmpty()) {
|
||||
publisherName = "";
|
||||
|
||||
for (int32 i = 0; i < copyrightList.CountStrings(); i++) {
|
||||
if (!publisherName.IsEmpty())
|
||||
publisherName << ", ";
|
||||
publisherName << copyrightList.StringAt(i);
|
||||
}
|
||||
}
|
||||
if (!publisherName.IsEmpty())
|
||||
publisherName.Prepend("© ");
|
||||
|
||||
fCoreInfo = PackageCoreInfoRef(new PackageCoreInfo(), true);
|
||||
fCoreInfo->SetArchitecture(info.ArchitectureName());
|
||||
fCoreInfo->SetVersion(new PackageVersion(info.Version()));
|
||||
fCoreInfo->SetPublisher(
|
||||
PackagePublisherInfoRef(new PackagePublisherInfo(publisherName, publisherURL), true));
|
||||
|
||||
fLocalizedText = PackageLocalizedTextRef(new PackageLocalizedText(), true);
|
||||
fLocalizedText->SetTitle(info.Name());
|
||||
fLocalizedText->SetSummary(info.Summary());
|
||||
fLocalizedText->SetDescription(info.Description());
|
||||
|
||||
// TODO: Retrieve local file size
|
||||
fLocalInfo = PackageLocalInfoRef(new PackageLocalInfo(), true);
|
||||
fLocalInfo->SetFlags(info.Flags());
|
||||
fLocalInfo->SetFileName(info.FileName());
|
||||
}
|
||||
|
||||
|
||||
PackageInfo::PackageInfo(const PackageInfo& other)
|
||||
:
|
||||
fName(other.fName),
|
||||
@@ -98,30 +44,11 @@ PackageInfo::PackageInfo(const PackageInfo& other)
|
||||
fClassificationInfo(other.fClassificationInfo),
|
||||
fScreenshotInfo(other.fScreenshotInfo),
|
||||
fUserRatingInfo(other.fUserRatingInfo),
|
||||
fLocalInfo(other.fLocalInfo),
|
||||
|
||||
fListeners(),
|
||||
fIsCollatingChanges(false),
|
||||
fCollatedChanges(0)
|
||||
fLocalInfo(other.fLocalInfo)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageInfo&
|
||||
PackageInfo::operator=(const PackageInfo& other)
|
||||
{
|
||||
fName = other.fName;
|
||||
fCoreInfo = other.fCoreInfo;
|
||||
fLocalizedText = other.fLocalizedText;
|
||||
fClassificationInfo = other.fClassificationInfo;
|
||||
fScreenshotInfo = other.fScreenshotInfo;
|
||||
fUserRatingInfo = other.fUserRatingInfo;
|
||||
fLocalInfo = other.fLocalInfo;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageInfo::operator==(const PackageInfo& other) const
|
||||
{
|
||||
@@ -142,8 +69,43 @@ PackageInfo::operator!=(const PackageInfo& other) const
|
||||
}
|
||||
|
||||
|
||||
const BString&
|
||||
PackageInfo::Name() const
|
||||
{
|
||||
return fName;
|
||||
}
|
||||
|
||||
|
||||
const PackageCoreInfoRef
|
||||
PackageInfo::CoreInfo() const
|
||||
{
|
||||
return fCoreInfo;
|
||||
}
|
||||
|
||||
|
||||
const PackageClassificationInfoRef
|
||||
PackageInfo::PackageClassificationInfo() const
|
||||
{
|
||||
return fClassificationInfo;
|
||||
}
|
||||
|
||||
|
||||
const PackageScreenshotInfoRef
|
||||
PackageInfo::ScreenshotInfo() const
|
||||
{
|
||||
return fScreenshotInfo;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInfo::SetName(const BString& value)
|
||||
{
|
||||
fName = value;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
PackageInfo::DiffMask(const PackageInfo& other) const
|
||||
PackageInfo::ChangeMask(const PackageInfo& other) const
|
||||
{
|
||||
uint32 result = 0;
|
||||
|
||||
@@ -167,14 +129,11 @@ PackageInfo::DiffMask(const PackageInfo& other) const
|
||||
void
|
||||
PackageInfo::SetCoreInfo(PackageCoreInfoRef value)
|
||||
{
|
||||
if (value != fCoreInfo) {
|
||||
fCoreInfo = value;
|
||||
_NotifyListeners(PKG_CHANGED_CORE_INFO);
|
||||
}
|
||||
fCoreInfo = value;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalizedTextRef
|
||||
const PackageLocalizedTextRef
|
||||
PackageInfo::LocalizedText() const
|
||||
{
|
||||
return fLocalizedText;
|
||||
@@ -184,16 +143,11 @@ PackageInfo::LocalizedText() const
|
||||
void
|
||||
PackageInfo::SetLocalizedText(PackageLocalizedTextRef value)
|
||||
{
|
||||
if (fLocalizedText != value) {
|
||||
fLocalizedText = value;
|
||||
_NotifyListeners(PKG_CHANGED_LOCALIZED_TEXT);
|
||||
// TODO; separate out these later - they are bundled for now to keep the existing
|
||||
// logic working.
|
||||
}
|
||||
fLocalizedText = value;
|
||||
}
|
||||
|
||||
|
||||
UserRatingInfoRef
|
||||
const PackageUserRatingInfoRef
|
||||
PackageInfo::UserRatingInfo() const
|
||||
{
|
||||
return fUserRatingInfo;
|
||||
@@ -201,16 +155,13 @@ PackageInfo::UserRatingInfo() const
|
||||
|
||||
|
||||
void
|
||||
PackageInfo::SetUserRatingInfo(UserRatingInfoRef value)
|
||||
PackageInfo::SetUserRatingInfo(PackageUserRatingInfoRef& value)
|
||||
{
|
||||
if (fUserRatingInfo != value) {
|
||||
fUserRatingInfo = value;
|
||||
_NotifyListeners(PKG_CHANGED_RATINGS);
|
||||
}
|
||||
fUserRatingInfo = value;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoRef
|
||||
const PackageLocalInfoRef
|
||||
PackageInfo::LocalInfo() const
|
||||
{
|
||||
return fLocalInfo;
|
||||
@@ -220,99 +171,137 @@ PackageInfo::LocalInfo() const
|
||||
void
|
||||
PackageInfo::SetLocalInfo(PackageLocalInfoRef& localInfo)
|
||||
{
|
||||
if (fLocalInfo != localInfo) {
|
||||
fLocalInfo = localInfo;
|
||||
_NotifyListeners(PKG_CHANGED_LOCAL_INFO);
|
||||
}
|
||||
fLocalInfo = localInfo;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInfo::SetPackageClassificationInfo(PackageClassificationInfoRef value)
|
||||
{
|
||||
if (value != fClassificationInfo) {
|
||||
fClassificationInfo = value;
|
||||
_NotifyListeners(PKG_CHANGED_CLASSIFICATION);
|
||||
}
|
||||
fClassificationInfo = value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInfo::SetScreenshotInfo(PackageScreenshotInfoRef value)
|
||||
{
|
||||
if (value != fScreenshotInfo) {
|
||||
fScreenshotInfo = value;
|
||||
_NotifyListeners(PKG_CHANGED_SCREENSHOTS);
|
||||
}
|
||||
fScreenshotInfo = value;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageInfo::AddListener(const PackageInfoListenerRef& listener)
|
||||
// #pragma mark - PackageLocalInfoBuilder
|
||||
|
||||
|
||||
PackageInfoBuilder::PackageInfoBuilder(const BString& name)
|
||||
:
|
||||
fName(name),
|
||||
fCoreInfo(),
|
||||
fLocalizedText(),
|
||||
fClassificationInfo(),
|
||||
fScreenshotInfo(),
|
||||
fUserRatingInfo(),
|
||||
fLocalInfo()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageInfoBuilder::PackageInfoBuilder(const PackageInfoRef& value)
|
||||
:
|
||||
fName(),
|
||||
fCoreInfo(),
|
||||
fLocalizedText(),
|
||||
fClassificationInfo(),
|
||||
fScreenshotInfo(),
|
||||
fUserRatingInfo(),
|
||||
fLocalInfo()
|
||||
{
|
||||
if (value.IsSet())
|
||||
_Init(value.Get());
|
||||
}
|
||||
|
||||
|
||||
PackageInfoBuilder::PackageInfoBuilder(const PackageInfo& value)
|
||||
{
|
||||
_Init(&value);
|
||||
}
|
||||
|
||||
|
||||
PackageInfoBuilder::~PackageInfoBuilder()
|
||||
{
|
||||
fListeners.push_back(listener);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInfo::RemoveListener(const PackageInfoListenerRef& listener)
|
||||
PackageInfoBuilder::_Init(const PackageInfo* value)
|
||||
{
|
||||
fListeners.erase(std::remove(fListeners.begin(), fListeners.end(),
|
||||
listener), fListeners.end());
|
||||
fName = value->Name();
|
||||
fCoreInfo = value->CoreInfo();
|
||||
fLocalizedText = value->LocalizedText();
|
||||
fClassificationInfo = value->PackageClassificationInfo();
|
||||
fScreenshotInfo = value->ScreenshotInfo();
|
||||
fUserRatingInfo = value->UserRatingInfo();
|
||||
fLocalInfo = value->LocalInfo();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInfo::NotifyChangedIcon()
|
||||
PackageInfoRef
|
||||
PackageInfoBuilder::BuildRef()
|
||||
{
|
||||
_NotifyListeners(PKG_CHANGED_ICON);
|
||||
PackageInfo* info = new PackageInfo();
|
||||
info->SetName(fName);
|
||||
info->SetCoreInfo(fCoreInfo);
|
||||
info->SetLocalizedText(fLocalizedText);
|
||||
info->SetPackageClassificationInfo(fClassificationInfo);
|
||||
info->SetScreenshotInfo(fScreenshotInfo);
|
||||
info->SetUserRatingInfo(fUserRatingInfo);
|
||||
info->SetLocalInfo(fLocalInfo);
|
||||
return PackageInfoRef(info, true);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInfo::StartCollatingChanges()
|
||||
PackageInfoBuilder&
|
||||
PackageInfoBuilder::WithCoreInfo(PackageCoreInfoRef value)
|
||||
{
|
||||
fIsCollatingChanges = true;
|
||||
fCollatedChanges = 0;
|
||||
fCoreInfo = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInfo::EndCollatingChanges()
|
||||
PackageInfoBuilder&
|
||||
PackageInfoBuilder::WithLocalizedText(PackageLocalizedTextRef value)
|
||||
{
|
||||
if (fIsCollatingChanges && fCollatedChanges != 0)
|
||||
_NotifyListenersImmediate(fCollatedChanges);
|
||||
fIsCollatingChanges = false;
|
||||
fCollatedChanges = 0;
|
||||
fLocalizedText = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInfo::_NotifyListeners(uint32 changes)
|
||||
PackageInfoBuilder&
|
||||
PackageInfoBuilder::WithPackageClassificationInfo(PackageClassificationInfoRef value)
|
||||
{
|
||||
if (fIsCollatingChanges)
|
||||
fCollatedChanges |= changes;
|
||||
else
|
||||
_NotifyListenersImmediate(changes);
|
||||
fClassificationInfo = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInfo::_NotifyListenersImmediate(uint32 changes)
|
||||
PackageInfoBuilder&
|
||||
PackageInfoBuilder::WithUserRatingInfo(PackageUserRatingInfoRef value)
|
||||
{
|
||||
if (fListeners.empty())
|
||||
return;
|
||||
|
||||
// Clone list to avoid listeners detaching themselves in notifications
|
||||
// to screw up the list while iterating it.
|
||||
std::vector<PackageInfoListenerRef> listeners(fListeners);
|
||||
PackageInfoEvent event(PackageInfoRef(this), changes);
|
||||
|
||||
std::vector<PackageInfoListenerRef>::iterator it;
|
||||
for (it = listeners.begin(); it != listeners.end(); it++) {
|
||||
const PackageInfoListenerRef listener = *it;
|
||||
if (listener.IsSet())
|
||||
listener->PackageChanged(event);
|
||||
}
|
||||
fUserRatingInfo = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageInfoBuilder&
|
||||
PackageInfoBuilder::WithLocalInfo(PackageLocalInfoRef value)
|
||||
{
|
||||
fLocalInfo = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageInfoBuilder&
|
||||
PackageInfoBuilder::WithScreenshotInfo(PackageScreenshotInfoRef value)
|
||||
{
|
||||
fScreenshotInfo = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2016-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_INFO_H
|
||||
@@ -8,76 +8,63 @@
|
||||
|
||||
|
||||
#include <Referenceable.h>
|
||||
#include <package/PackageInfo.h>
|
||||
|
||||
#include "Language.h"
|
||||
#include "List.h"
|
||||
#include "PackageClassificationInfo.h"
|
||||
#include "PackageCoreInfo.h"
|
||||
#include "PackageInfoListener.h"
|
||||
#include "PackageLocalInfo.h"
|
||||
#include "PackageLocalizedText.h"
|
||||
#include "PackagePublisherInfo.h"
|
||||
#include "PackageScreenshotInfo.h"
|
||||
#include "PackageUserRatingInfo.h"
|
||||
#include "ScreenshotInfo.h"
|
||||
#include "UserRatingInfo.h"
|
||||
|
||||
|
||||
using BPackageKit::BPackageInfo;
|
||||
|
||||
|
||||
class PackageInfoBuilder;
|
||||
|
||||
|
||||
/*! Instances of this class should not be created directly; instead use the
|
||||
PackageInfoBuilder class as a builder-constructor.
|
||||
*/
|
||||
class PackageInfo : public BReferenceable {
|
||||
friend class PackageInfoBuilder;
|
||||
|
||||
public:
|
||||
PackageInfo();
|
||||
PackageInfo(const BPackageInfo& info);
|
||||
PackageInfo(const PackageInfo& other);
|
||||
|
||||
PackageInfo& operator=(const PackageInfo& other);
|
||||
bool operator==(const PackageInfo& other) const;
|
||||
bool operator!=(const PackageInfo& other) const;
|
||||
|
||||
uint32 DiffMask(const PackageInfo& other) const;
|
||||
uint32 ChangeMask(const PackageInfo& other) const;
|
||||
|
||||
const BString& Name() const
|
||||
{ return fName; }
|
||||
|
||||
PackageCoreInfoRef CoreInfo() const
|
||||
{ return fCoreInfo; }
|
||||
void SetCoreInfo(PackageCoreInfoRef value);
|
||||
|
||||
PackageLocalizedTextRef
|
||||
const BString& Name() const;
|
||||
const PackageCoreInfoRef
|
||||
CoreInfo() const;
|
||||
const PackageLocalizedTextRef
|
||||
LocalizedText() const;
|
||||
void SetLocalizedText(PackageLocalizedTextRef value);
|
||||
|
||||
void SetPackageClassificationInfo(
|
||||
PackageClassificationInfoRef value);
|
||||
PackageClassificationInfoRef
|
||||
PackageClassificationInfo() const
|
||||
{ return fClassificationInfo; }
|
||||
|
||||
UserRatingInfoRef UserRatingInfo() const;
|
||||
void SetUserRatingInfo(UserRatingInfoRef userRatingInfo);
|
||||
|
||||
PackageLocalInfoRef LocalInfo() const;
|
||||
void SetLocalInfo(PackageLocalInfoRef& localInfo);
|
||||
|
||||
PackageScreenshotInfoRef
|
||||
ScreenshotInfo() const
|
||||
{ return fScreenshotInfo; }
|
||||
void SetScreenshotInfo(PackageScreenshotInfoRef value);
|
||||
|
||||
bool AddListener(
|
||||
const PackageInfoListenerRef& listener);
|
||||
void RemoveListener(
|
||||
const PackageInfoListenerRef& listener);
|
||||
|
||||
void StartCollatingChanges();
|
||||
void EndCollatingChanges();
|
||||
void NotifyChangedIcon();
|
||||
const PackageClassificationInfoRef
|
||||
PackageClassificationInfo() const;
|
||||
const PackageUserRatingInfoRef
|
||||
UserRatingInfo() const;
|
||||
const PackageLocalInfoRef
|
||||
LocalInfo() const;
|
||||
const PackageScreenshotInfoRef
|
||||
ScreenshotInfo() const;
|
||||
|
||||
private:
|
||||
void _NotifyListeners(uint32 changes);
|
||||
void _NotifyListenersImmediate(uint32 changes);
|
||||
|
||||
void SetName(const BString& value);
|
||||
void SetCoreInfo(PackageCoreInfoRef value);
|
||||
void SetLocalizedText(PackageLocalizedTextRef value);
|
||||
void SetPackageClassificationInfo(PackageClassificationInfoRef value);
|
||||
void SetUserRatingInfo(PackageUserRatingInfoRef& userRatingInfo);
|
||||
void SetLocalInfo(PackageLocalInfoRef& localInfo);
|
||||
void SetScreenshotInfo(PackageScreenshotInfoRef value);
|
||||
|
||||
private:
|
||||
BString fName;
|
||||
@@ -89,19 +76,55 @@ private:
|
||||
fClassificationInfo;
|
||||
PackageScreenshotInfoRef
|
||||
fScreenshotInfo;
|
||||
UserRatingInfoRef fUserRatingInfo;
|
||||
PackageUserRatingInfoRef
|
||||
fUserRatingInfo;
|
||||
PackageLocalInfoRef fLocalInfo;
|
||||
|
||||
std::vector<PackageInfoListenerRef>
|
||||
fListeners;
|
||||
bool fIsCollatingChanges;
|
||||
uint32 fCollatedChanges;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
typedef BReference<PackageInfo> PackageInfoRef;
|
||||
|
||||
|
||||
class PackageInfoBuilder
|
||||
{
|
||||
public:
|
||||
PackageInfoBuilder(const BString& name);
|
||||
PackageInfoBuilder(const PackageInfoRef& value);
|
||||
PackageInfoBuilder(const PackageInfo& value);
|
||||
virtual ~PackageInfoBuilder();
|
||||
|
||||
PackageInfoRef BuildRef();
|
||||
|
||||
PackageInfoBuilder&
|
||||
WithCoreInfo(PackageCoreInfoRef value);
|
||||
PackageInfoBuilder&
|
||||
WithLocalizedText(PackageLocalizedTextRef value);
|
||||
PackageInfoBuilder&
|
||||
WithPackageClassificationInfo(PackageClassificationInfoRef value);
|
||||
PackageInfoBuilder&
|
||||
WithUserRatingInfo(PackageUserRatingInfoRef userRatingInfo);
|
||||
PackageInfoBuilder&
|
||||
WithLocalInfo(PackageLocalInfoRef localInfo);
|
||||
PackageInfoBuilder&
|
||||
WithScreenshotInfo(PackageScreenshotInfoRef value);
|
||||
|
||||
private:
|
||||
void _Init(const PackageInfo* value);
|
||||
|
||||
private:
|
||||
BString fName;
|
||||
|
||||
PackageCoreInfoRef fCoreInfo;
|
||||
PackageLocalizedTextRef
|
||||
fLocalizedText;
|
||||
PackageClassificationInfoRef
|
||||
fClassificationInfo;
|
||||
PackageScreenshotInfoRef
|
||||
fScreenshotInfo;
|
||||
PackageUserRatingInfoRef
|
||||
fUserRatingInfo;
|
||||
PackageLocalInfoRef fLocalInfo;
|
||||
};
|
||||
|
||||
|
||||
#endif // PACKAGE_INFO_H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -49,23 +49,6 @@ PackageLocalInfo::~PackageLocalInfo()
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfo&
|
||||
PackageLocalInfo::operator=(const PackageLocalInfo& other)
|
||||
{
|
||||
fState = other.fState;
|
||||
fInstallationLocations = other.fInstallationLocations;
|
||||
fDownloadProgress = other.fDownloadProgress;
|
||||
fFlags = other.fFlags;
|
||||
fSystemDependency = other.fSystemDependency;
|
||||
fLocalFilePath = other.fLocalFilePath;
|
||||
fFileName = other.fFileName;
|
||||
fSize = other.fSize;
|
||||
fViewed = other.fViewed;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageLocalInfo::operator==(const PackageLocalInfo& other) const
|
||||
{
|
||||
@@ -88,6 +71,69 @@ PackageLocalInfo::operator!=(const PackageLocalInfo& other) const
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageLocalInfo::Viewed() const
|
||||
{
|
||||
return fViewed;
|
||||
}
|
||||
|
||||
|
||||
const BString&
|
||||
PackageLocalInfo::LocalFilePath() const
|
||||
{
|
||||
return fLocalFilePath;
|
||||
}
|
||||
|
||||
|
||||
const BString&
|
||||
PackageLocalInfo::FileName() const
|
||||
{
|
||||
return fFileName;
|
||||
}
|
||||
|
||||
|
||||
off_t
|
||||
PackageLocalInfo::Size() const
|
||||
{
|
||||
return fSize;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
PackageLocalInfo::Flags() const
|
||||
{
|
||||
return fFlags;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageLocalInfo::IsSystemDependency() const
|
||||
{
|
||||
return fSystemDependency;
|
||||
}
|
||||
|
||||
|
||||
PackageState
|
||||
PackageLocalInfo::State() const
|
||||
{
|
||||
return fState;
|
||||
}
|
||||
|
||||
|
||||
const PackageInstallationLocationSet&
|
||||
PackageLocalInfo::InstallationLocations() const
|
||||
{
|
||||
return fInstallationLocations;
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
PackageLocalInfo::DownloadProgress() const
|
||||
{
|
||||
return fDownloadProgress;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageLocalInfo::IsSystemPackage() const
|
||||
{
|
||||
@@ -122,10 +168,17 @@ PackageLocalInfo::AddInstallationLocation(int32 location)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageLocalInfo::ClearInstallationLocations()
|
||||
bool
|
||||
PackageLocalInfo::HasInstallationLocation(int32 location) const
|
||||
{
|
||||
fInstallationLocations.clear();
|
||||
return fInstallationLocations.find(location) != fInstallationLocations.end();
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
PackageLocalInfo::CountInstallationLocations() const
|
||||
{
|
||||
return static_cast<int32>(fInstallationLocations.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -177,3 +230,211 @@ PackageLocalInfo::SetFileName(const BString& value)
|
||||
{
|
||||
fFileName = value;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - PackageLocalInfoBuilder
|
||||
|
||||
|
||||
PackageLocalInfoBuilder::PackageLocalInfoBuilder()
|
||||
:
|
||||
fViewed(false),
|
||||
fLocalFilePath(),
|
||||
fFileName(),
|
||||
fSize(0),
|
||||
fFlags(0),
|
||||
fSystemDependency(false),
|
||||
fState(NONE),
|
||||
fInstallationLocations(),
|
||||
fDownloadProgress(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoBuilder::PackageLocalInfoBuilder(const PackageLocalInfoRef& value)
|
||||
:
|
||||
fViewed(false),
|
||||
fLocalFilePath(),
|
||||
fFileName(),
|
||||
fSize(0),
|
||||
fFlags(0),
|
||||
fSystemDependency(false),
|
||||
fState(NONE),
|
||||
fInstallationLocations(),
|
||||
fDownloadProgress(0.0)
|
||||
{
|
||||
fSource = value;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoBuilder::~PackageLocalInfoBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageLocalInfoBuilder::_InitFromSource()
|
||||
{
|
||||
if (fSource.IsSet()) {
|
||||
_Init(fSource);
|
||||
fSource.Unset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageLocalInfoBuilder::_Init(const PackageLocalInfo* value)
|
||||
{
|
||||
fViewed = value->Viewed();
|
||||
fLocalFilePath = value->LocalFilePath();
|
||||
fFileName = value->FileName();
|
||||
fSize = value->Size();
|
||||
fFlags = value->Flags();
|
||||
fSystemDependency = value->IsSystemDependency();
|
||||
fState = value->State();
|
||||
fDownloadProgress = value->DownloadProgress();
|
||||
|
||||
PackageInstallationLocationSet valueLocations = value->InstallationLocations();
|
||||
PackageInstallationLocationSet::const_iterator it;
|
||||
|
||||
for (it = valueLocations.begin(); it != valueLocations.end(); it++)
|
||||
fInstallationLocations.insert(*it);
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoRef
|
||||
PackageLocalInfoBuilder::BuildRef()
|
||||
{
|
||||
if (fSource.IsSet())
|
||||
return fSource;
|
||||
|
||||
PackageLocalInfo* localInfo = new PackageLocalInfo();
|
||||
|
||||
if (fViewed)
|
||||
localInfo->SetViewed();
|
||||
|
||||
localInfo->SetLocalFilePath(fLocalFilePath);
|
||||
localInfo->SetFileName(fFileName);
|
||||
localInfo->SetSize(fSize);
|
||||
localInfo->SetFlags(fFlags);
|
||||
localInfo->SetSystemDependency(fSystemDependency);
|
||||
localInfo->SetState(fState);
|
||||
if (fState == DOWNLOADING)
|
||||
localInfo->SetDownloadProgress(fDownloadProgress);
|
||||
|
||||
PackageInstallationLocationSet::const_iterator it;
|
||||
|
||||
for (it = fInstallationLocations.begin(); it != fInstallationLocations.end(); it++)
|
||||
localInfo->AddInstallationLocation(*it);
|
||||
|
||||
return PackageLocalInfoRef(localInfo, true);
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoBuilder&
|
||||
PackageLocalInfoBuilder::WithViewed()
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Viewed()) {
|
||||
_InitFromSource();
|
||||
fViewed = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoBuilder&
|
||||
PackageLocalInfoBuilder::WithLocalFilePath(const char* path)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->LocalFilePath() != path) {
|
||||
_InitFromSource();
|
||||
fLocalFilePath.SetTo(path);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoBuilder&
|
||||
PackageLocalInfoBuilder::WithFileName(const BString& value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->FileName() != value) {
|
||||
_InitFromSource();
|
||||
fFileName.SetTo(value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoBuilder&
|
||||
PackageLocalInfoBuilder::WithSize(off_t size)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Size() != size) {
|
||||
_InitFromSource();
|
||||
fSize = size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoBuilder&
|
||||
PackageLocalInfoBuilder::WithFlags(int32 value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Flags() != value) {
|
||||
_InitFromSource();
|
||||
fFlags = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoBuilder&
|
||||
PackageLocalInfoBuilder::WithSystemDependency(bool value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->IsSystemDependency() != value) {
|
||||
_InitFromSource();
|
||||
fSystemDependency = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoBuilder&
|
||||
PackageLocalInfoBuilder::WithState(PackageState value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->State() != value) {
|
||||
_InitFromSource();
|
||||
fState = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoBuilder&
|
||||
PackageLocalInfoBuilder::WithDownloadProgress(float value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->DownloadProgress() != value) {
|
||||
_InitFromSource();
|
||||
fDownloadProgress = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoBuilder&
|
||||
PackageLocalInfoBuilder::AddInstallationLocation(int32 value)
|
||||
{
|
||||
if (!fSource.IsSet() || !fSource->HasInstallationLocation(value)) {
|
||||
_InitFromSource();
|
||||
fInstallationLocations.insert(value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalInfoBuilder&
|
||||
PackageLocalInfoBuilder::ClearInstallationLocations()
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->CountInstallationLocations() != 0) {
|
||||
_InitFromSource();
|
||||
fInstallationLocations.clear();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_LOCAL_INFO_H
|
||||
@@ -27,58 +27,49 @@ enum PackageState {
|
||||
};
|
||||
|
||||
|
||||
class PackageLocalInfoBuilder;
|
||||
|
||||
|
||||
/*! Instances of this class should not be created directly; instead use the
|
||||
PackageLocalInfoBuilder class as a builder-constructor.
|
||||
*/
|
||||
class PackageLocalInfo : public BReferenceable
|
||||
{
|
||||
friend class PackageLocalInfoBuilder;
|
||||
|
||||
public:
|
||||
PackageLocalInfo();
|
||||
PackageLocalInfo(const PackageLocalInfo& other);
|
||||
virtual ~PackageLocalInfo();
|
||||
|
||||
PackageLocalInfo& operator=(const PackageLocalInfo& other);
|
||||
bool operator==(const PackageLocalInfo& other) const;
|
||||
bool operator!=(const PackageLocalInfo& other) const;
|
||||
|
||||
bool IsLocalFile() const;
|
||||
|
||||
void SetViewed();
|
||||
bool Viewed() const
|
||||
{ return fViewed; }
|
||||
|
||||
void SetLocalFilePath(const char* path);
|
||||
const BString& LocalFilePath() const
|
||||
{ return fLocalFilePath; }
|
||||
|
||||
void SetFileName(const BString& value);
|
||||
const BString& FileName() const
|
||||
{ return fFileName; }
|
||||
|
||||
void SetSize(off_t size);
|
||||
off_t Size() const
|
||||
{ return fSize; }
|
||||
|
||||
void SetFlags(int32 value);
|
||||
int32 Flags() const
|
||||
{ return fFlags; }
|
||||
|
||||
bool Viewed() const;
|
||||
const BString& LocalFilePath() const;
|
||||
const BString& FileName() const;
|
||||
off_t Size() const;
|
||||
int32 Flags() const;
|
||||
bool IsSystemPackage() const;
|
||||
|
||||
void SetSystemDependency(bool isDependency);
|
||||
bool IsSystemDependency() const
|
||||
{ return fSystemDependency; }
|
||||
|
||||
void SetState(PackageState state);
|
||||
PackageState State() const
|
||||
{ return fState; }
|
||||
|
||||
void AddInstallationLocation(int32 location);
|
||||
bool IsSystemDependency() const;
|
||||
PackageState State() const;
|
||||
bool HasInstallationLocation(int32 location) const;
|
||||
int32 CountInstallationLocations() const;
|
||||
const PackageInstallationLocationSet&
|
||||
InstallationLocations() const
|
||||
{ return fInstallationLocations; }
|
||||
void ClearInstallationLocations();
|
||||
InstallationLocations() const;
|
||||
float DownloadProgress() const;
|
||||
|
||||
private:
|
||||
void SetViewed();
|
||||
void SetLocalFilePath(const char* path);
|
||||
void SetFileName(const BString& value);
|
||||
void SetSize(off_t size);
|
||||
void SetFlags(int32 value);
|
||||
void SetSystemDependency(bool isDependency);
|
||||
void SetState(PackageState state);
|
||||
void AddInstallationLocation(int32 location);
|
||||
void SetDownloadProgress(float progress);
|
||||
float DownloadProgress() const
|
||||
{ return fDownloadProgress; }
|
||||
|
||||
private:
|
||||
bool fViewed;
|
||||
@@ -97,4 +88,56 @@ private:
|
||||
typedef BReference<PackageLocalInfo> PackageLocalInfoRef;
|
||||
|
||||
|
||||
class PackageLocalInfoBuilder
|
||||
{
|
||||
public:
|
||||
PackageLocalInfoBuilder();
|
||||
PackageLocalInfoBuilder(const PackageLocalInfoRef& value);
|
||||
virtual ~PackageLocalInfoBuilder();
|
||||
|
||||
PackageLocalInfoRef BuildRef();
|
||||
|
||||
PackageLocalInfoBuilder&
|
||||
WithViewed();
|
||||
PackageLocalInfoBuilder&
|
||||
WithLocalFilePath(const char* path);
|
||||
PackageLocalInfoBuilder&
|
||||
WithFileName(const BString& value);
|
||||
PackageLocalInfoBuilder&
|
||||
WithSize(off_t size);
|
||||
PackageLocalInfoBuilder&
|
||||
WithFlags(int32 value);
|
||||
PackageLocalInfoBuilder&
|
||||
WithSystemDependency(bool isDependency);
|
||||
PackageLocalInfoBuilder&
|
||||
WithState(PackageState state);
|
||||
PackageLocalInfoBuilder&
|
||||
WithDownloadProgress(float progress);
|
||||
|
||||
PackageLocalInfoBuilder&
|
||||
AddInstallationLocation(int32 location);
|
||||
PackageLocalInfoBuilder&
|
||||
ClearInstallationLocations();
|
||||
|
||||
private:
|
||||
void _InitFromSource();
|
||||
void _Init(const PackageLocalInfo* value);
|
||||
|
||||
private:
|
||||
PackageLocalInfoRef fSource;
|
||||
bool fViewed;
|
||||
BString fLocalFilePath;
|
||||
BString fFileName;
|
||||
off_t fSize;
|
||||
int32 fFlags;
|
||||
bool fSystemDependency;
|
||||
// When true, this value indicates that the package is a dependency of the
|
||||
// system and so cannot be uninstalled.
|
||||
PackageState fState;
|
||||
PackageInstallationLocationSet
|
||||
fInstallationLocations;
|
||||
float fDownloadProgress;
|
||||
};
|
||||
|
||||
|
||||
#endif // PACKAGE_LOCAL_INFO_H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -117,3 +117,127 @@ PackageLocalizedText::operator!=(const PackageLocalizedText& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - PackageLocalInfoBuilder
|
||||
|
||||
|
||||
PackageLocalizedTextBuilder::PackageLocalizedTextBuilder()
|
||||
:
|
||||
fTitle(),
|
||||
fSummary(),
|
||||
fDescription(),
|
||||
fHasChangelog(false),
|
||||
fChangelog()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageLocalizedTextBuilder::PackageLocalizedTextBuilder(const PackageLocalizedTextRef& value)
|
||||
:
|
||||
fTitle(),
|
||||
fSummary(),
|
||||
fDescription(),
|
||||
fHasChangelog(false),
|
||||
fChangelog()
|
||||
{
|
||||
fSource = value;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalizedTextBuilder::~PackageLocalizedTextBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageLocalizedTextBuilder::_InitFromSource()
|
||||
{
|
||||
if (fSource.IsSet()) {
|
||||
_Init(fSource);
|
||||
fSource.Unset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageLocalizedTextBuilder::_Init(const PackageLocalizedText* value)
|
||||
{
|
||||
fTitle = value->Title();
|
||||
fSummary = value->Summary();
|
||||
fDescription = value->Description();
|
||||
fHasChangelog = value->HasChangelog();
|
||||
fChangelog = value->Changelog();
|
||||
}
|
||||
|
||||
|
||||
PackageLocalizedTextRef
|
||||
PackageLocalizedTextBuilder::BuildRef()
|
||||
{
|
||||
if (fSource.IsSet())
|
||||
return fSource;
|
||||
|
||||
PackageLocalizedText* localizedText = new PackageLocalizedText();
|
||||
localizedText->SetTitle(fTitle);
|
||||
localizedText->SetSummary(fSummary);
|
||||
localizedText->SetDescription(fDescription);
|
||||
localizedText->SetHasChangelog(fHasChangelog);
|
||||
localizedText->SetChangelog(fChangelog);
|
||||
|
||||
return PackageLocalizedTextRef(localizedText, true);
|
||||
}
|
||||
|
||||
|
||||
PackageLocalizedTextBuilder&
|
||||
PackageLocalizedTextBuilder::WithTitle(const BString& value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Title() != value) {
|
||||
_InitFromSource();
|
||||
fTitle = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalizedTextBuilder&
|
||||
PackageLocalizedTextBuilder::WithSummary(const BString& value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Summary() != value) {
|
||||
_InitFromSource();
|
||||
fSummary = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalizedTextBuilder&
|
||||
PackageLocalizedTextBuilder::WithDescription(const BString& value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Description() != value) {
|
||||
_InitFromSource();
|
||||
fDescription = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalizedTextBuilder&
|
||||
PackageLocalizedTextBuilder::WithHasChangelog(bool value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->HasChangelog() != value) {
|
||||
_InitFromSource();
|
||||
fHasChangelog = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageLocalizedTextBuilder&
|
||||
PackageLocalizedTextBuilder::WithChangelog(const BString& value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Changelog() != value) {
|
||||
_InitFromSource();
|
||||
fChangelog = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_LOCALIZED_TEXT_H
|
||||
@@ -10,30 +10,37 @@
|
||||
#include <String.h>
|
||||
|
||||
|
||||
class PackageLocalizedTextBuilder;
|
||||
|
||||
|
||||
/*! Instances of this class should not be created directly; instead use the
|
||||
PackageLocalizedTextBuilder class as a builder-constructor.
|
||||
*/
|
||||
class PackageLocalizedText : public BReferenceable
|
||||
{
|
||||
friend class PackageLocalizedTextBuilder;
|
||||
|
||||
public:
|
||||
PackageLocalizedText();
|
||||
PackageLocalizedText(const PackageLocalizedText& other);
|
||||
|
||||
const BString& Title() const;
|
||||
void SetTitle(const BString& value);
|
||||
|
||||
const BString& Summary() const;
|
||||
void SetSummary(const BString& value);
|
||||
|
||||
const BString& Description() const;
|
||||
void SetDescription(const BString& value);
|
||||
|
||||
const bool HasChangelog() const;
|
||||
void SetHasChangelog(bool value);
|
||||
|
||||
void SetChangelog(const BString& value);
|
||||
const BString& Changelog() const;
|
||||
|
||||
bool operator==(const PackageLocalizedText& other) const;
|
||||
bool operator!=(const PackageLocalizedText& other) const;
|
||||
|
||||
const BString& Title() const;
|
||||
const BString& Summary() const;
|
||||
const BString& Description() const;
|
||||
const bool HasChangelog() const;
|
||||
const BString& Changelog() const;
|
||||
|
||||
private:
|
||||
|
||||
void SetTitle(const BString& value);
|
||||
void SetSummary(const BString& value);
|
||||
void SetDescription(const BString& value);
|
||||
void SetHasChangelog(bool value);
|
||||
void SetChangelog(const BString& value);
|
||||
|
||||
private:
|
||||
BString fTitle;
|
||||
BString fSummary;
|
||||
@@ -47,4 +54,40 @@ private:
|
||||
typedef BReference<PackageLocalizedText> PackageLocalizedTextRef;
|
||||
|
||||
|
||||
class PackageLocalizedTextBuilder
|
||||
{
|
||||
public:
|
||||
PackageLocalizedTextBuilder();
|
||||
PackageLocalizedTextBuilder(const PackageLocalizedTextRef& value);
|
||||
virtual ~PackageLocalizedTextBuilder();
|
||||
|
||||
PackageLocalizedTextRef
|
||||
BuildRef();
|
||||
|
||||
PackageLocalizedTextBuilder&
|
||||
WithTitle(const BString& value);
|
||||
PackageLocalizedTextBuilder&
|
||||
WithSummary(const BString& value);
|
||||
PackageLocalizedTextBuilder&
|
||||
WithDescription(const BString& value);
|
||||
PackageLocalizedTextBuilder&
|
||||
WithHasChangelog(bool value);
|
||||
PackageLocalizedTextBuilder&
|
||||
WithChangelog(const BString& value);
|
||||
|
||||
private:
|
||||
void _InitFromSource();
|
||||
void _Init(const PackageLocalizedText* value);
|
||||
|
||||
private:
|
||||
PackageLocalizedTextRef
|
||||
fSource;
|
||||
BString fTitle;
|
||||
BString fSummary;
|
||||
BString fDescription;
|
||||
bool fHasChangelog;
|
||||
BString fChangelog;
|
||||
};
|
||||
|
||||
|
||||
#endif // PACKAGE_LOCALIZED_TEXT_H
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2016-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_PUBLISHER_INFO_H
|
||||
@@ -33,6 +33,8 @@ private:
|
||||
BString fWebsite;
|
||||
};
|
||||
|
||||
|
||||
typedef BReference<PackagePublisherInfo> PackagePublisherInfoRef;
|
||||
|
||||
|
||||
#endif // PACKAGE_PUBLISHER_INFO_H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -19,14 +19,6 @@ PackageScreenshotInfo::PackageScreenshotInfo(const PackageScreenshotInfo& other)
|
||||
}
|
||||
|
||||
|
||||
PackageScreenshotInfo&
|
||||
PackageScreenshotInfo::operator=(const PackageScreenshotInfo& other)
|
||||
{
|
||||
fScreenshotInfos = other.fScreenshotInfos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageScreenshotInfo::operator==(const PackageScreenshotInfo& other) const
|
||||
{
|
||||
@@ -41,13 +33,6 @@ PackageScreenshotInfo::operator!=(const PackageScreenshotInfo& other) const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageScreenshotInfo::Clear()
|
||||
{
|
||||
fScreenshotInfos.clear();
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
PackageScreenshotInfo::Count() const
|
||||
{
|
||||
@@ -55,7 +40,7 @@ PackageScreenshotInfo::Count() const
|
||||
}
|
||||
|
||||
|
||||
ScreenshotInfoRef
|
||||
const ScreenshotInfoRef
|
||||
PackageScreenshotInfo::ScreenshotAtIndex(int32 index) const
|
||||
{
|
||||
return fScreenshotInfos[index];
|
||||
@@ -66,4 +51,73 @@ void
|
||||
PackageScreenshotInfo::AddScreenshot(const ScreenshotInfoRef& info)
|
||||
{
|
||||
fScreenshotInfos.push_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - PackageScreenshotInfoBuilder
|
||||
|
||||
|
||||
PackageScreenshotInfoBuilder::PackageScreenshotInfoBuilder()
|
||||
:
|
||||
fSource(),
|
||||
fScreenshotInfos()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageScreenshotInfoBuilder::PackageScreenshotInfoBuilder(const PackageScreenshotInfoRef& other)
|
||||
:
|
||||
fScreenshotInfos()
|
||||
{
|
||||
fSource = other;
|
||||
}
|
||||
|
||||
|
||||
PackageScreenshotInfoBuilder::~PackageScreenshotInfoBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageScreenshotInfoBuilder::_InitFromSource()
|
||||
{
|
||||
if (fSource.IsSet()) {
|
||||
_Init(fSource.Get());
|
||||
fSource.Unset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageScreenshotInfoBuilder::_Init(const PackageScreenshotInfo* value)
|
||||
{
|
||||
int32 count = value->Count();
|
||||
for (int32 i = 0; i < count; i++)
|
||||
fScreenshotInfos.push_back(value->ScreenshotAtIndex(i));
|
||||
}
|
||||
|
||||
|
||||
PackageScreenshotInfoRef
|
||||
PackageScreenshotInfoBuilder::BuildRef()
|
||||
{
|
||||
if (fSource.IsSet())
|
||||
return fSource;
|
||||
|
||||
PackageScreenshotInfo* screenshotInfo = new PackageScreenshotInfo();
|
||||
|
||||
std::vector<ScreenshotInfoRef>::const_iterator it;
|
||||
for (it = fScreenshotInfos.begin(); it != fScreenshotInfos.end(); it++)
|
||||
screenshotInfo->AddScreenshot(*it);
|
||||
|
||||
return PackageScreenshotInfoRef(screenshotInfo, true);
|
||||
}
|
||||
|
||||
|
||||
PackageScreenshotInfoBuilder&
|
||||
PackageScreenshotInfoBuilder::AddScreenshot(const ScreenshotInfoRef& value)
|
||||
{
|
||||
if (fSource.IsSet())
|
||||
_InitFromSource();
|
||||
fScreenshotInfos.push_back(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_SCREENSHOT_INFO_H
|
||||
@@ -14,21 +14,28 @@
|
||||
#include "ScreenshotInfo.h"
|
||||
|
||||
|
||||
class PackageScreenshotInfoBuilder;
|
||||
|
||||
|
||||
/*! Instances of this class should not be created directly; instead use the
|
||||
PackageScreenshotInfoBuilder class as a builder-constructor.
|
||||
*/
|
||||
class PackageScreenshotInfo : public BReferenceable
|
||||
{
|
||||
friend class PackageScreenshotInfoBuilder;
|
||||
|
||||
public:
|
||||
PackageScreenshotInfo();
|
||||
PackageScreenshotInfo(const PackageScreenshotInfo& other);
|
||||
|
||||
PackageScreenshotInfo&
|
||||
operator=(const PackageScreenshotInfo& other);
|
||||
bool operator==(const PackageScreenshotInfo& other) const;
|
||||
bool operator!=(const PackageScreenshotInfo& other) const;
|
||||
|
||||
void Clear();
|
||||
void AddScreenshot(const ScreenshotInfoRef& info);
|
||||
int32 Count() const;
|
||||
ScreenshotInfoRef ScreenshotAtIndex(int32 index) const;
|
||||
const ScreenshotInfoRef ScreenshotAtIndex(int32 index) const;
|
||||
|
||||
private:
|
||||
void AddScreenshot(const ScreenshotInfoRef& info);
|
||||
|
||||
private:
|
||||
std::vector<ScreenshotInfoRef>
|
||||
@@ -39,4 +46,29 @@ private:
|
||||
typedef BReference<PackageScreenshotInfo> PackageScreenshotInfoRef;
|
||||
|
||||
|
||||
class PackageScreenshotInfoBuilder
|
||||
{
|
||||
public:
|
||||
PackageScreenshotInfoBuilder();
|
||||
PackageScreenshotInfoBuilder(const PackageScreenshotInfoRef& other);
|
||||
virtual ~PackageScreenshotInfoBuilder();
|
||||
|
||||
PackageScreenshotInfoRef
|
||||
BuildRef();
|
||||
|
||||
PackageScreenshotInfoBuilder&
|
||||
AddScreenshot(const ScreenshotInfoRef& value);
|
||||
|
||||
private:
|
||||
void _InitFromSource();
|
||||
void _Init(const PackageScreenshotInfo* value);
|
||||
|
||||
private:
|
||||
PackageScreenshotInfoRef
|
||||
fSource;
|
||||
std::vector<ScreenshotInfoRef>
|
||||
fScreenshotInfos;
|
||||
};
|
||||
|
||||
|
||||
#endif // PACKAGE_SCREENSHOT_INFO_H
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "PackageUserRatingInfo.h"
|
||||
|
||||
|
||||
PackageUserRatingInfo::PackageUserRatingInfo()
|
||||
:
|
||||
fUserRatings(),
|
||||
fSummary(),
|
||||
fUserRatingsPopulated(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageUserRatingInfo::PackageUserRatingInfo(const PackageUserRatingInfo& other)
|
||||
:
|
||||
fSummary(other.Summary()),
|
||||
fUserRatingsPopulated(other.UserRatingsPopulated())
|
||||
{
|
||||
for (int32 i = CountUserRatings() - 1; i >= 0; i--)
|
||||
AddUserRating(other.UserRatingAtIndex(i));
|
||||
}
|
||||
|
||||
|
||||
const UserRatingSummaryRef
|
||||
PackageUserRatingInfo::Summary() const
|
||||
{
|
||||
return fSummary;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageUserRatingInfo::SetSummary(UserRatingSummaryRef value)
|
||||
{
|
||||
fSummary = value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageUserRatingInfo::SetUserRatingsPopulated()
|
||||
{
|
||||
fUserRatingsPopulated = true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageUserRatingInfo::UserRatingsPopulated() const
|
||||
{
|
||||
return fUserRatingsPopulated;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
PackageUserRatingInfo::CountUserRatings() const
|
||||
{
|
||||
return fUserRatings.size();
|
||||
}
|
||||
|
||||
|
||||
const UserRatingRef
|
||||
PackageUserRatingInfo::UserRatingAtIndex(int32 index) const
|
||||
{
|
||||
return fUserRatings[index];
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageUserRatingInfo::AddUserRating(const UserRatingRef& rating)
|
||||
{
|
||||
fUserRatings.push_back(rating);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageUserRatingInfo::operator==(const PackageUserRatingInfo& other) const
|
||||
{
|
||||
if (Summary() != other.Summary())
|
||||
return false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageUserRatingInfo::operator!=(const PackageUserRatingInfo& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - PackageUserRatingInfoBuilder
|
||||
|
||||
|
||||
PackageUserRatingInfoBuilder::PackageUserRatingInfoBuilder()
|
||||
:
|
||||
fSource(),
|
||||
fUserRatings(),
|
||||
fSummary(),
|
||||
fUserRatingsPopulated(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageUserRatingInfoBuilder::PackageUserRatingInfoBuilder(const PackageUserRatingInfoRef& other)
|
||||
:
|
||||
fSource(other),
|
||||
fUserRatings(),
|
||||
fSummary(),
|
||||
fUserRatingsPopulated(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageUserRatingInfoBuilder::~PackageUserRatingInfoBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageUserRatingInfoRef
|
||||
PackageUserRatingInfoBuilder::BuildRef()
|
||||
{
|
||||
if (fSource.IsSet())
|
||||
return fSource;
|
||||
|
||||
PackageUserRatingInfo* userRatingInfo = new PackageUserRatingInfo();
|
||||
|
||||
userRatingInfo->SetSummary(fSummary);
|
||||
|
||||
if (fUserRatingsPopulated)
|
||||
userRatingInfo->SetUserRatingsPopulated();
|
||||
|
||||
std::vector<UserRatingRef>::const_iterator it;
|
||||
for (it = fUserRatings.begin(); it != fUserRatings.end(); it++)
|
||||
userRatingInfo->AddUserRating(*it);
|
||||
|
||||
return PackageUserRatingInfoRef(userRatingInfo, true);
|
||||
}
|
||||
|
||||
|
||||
PackageUserRatingInfoBuilder&
|
||||
PackageUserRatingInfoBuilder::AddUserRating(const UserRatingRef& rating)
|
||||
{
|
||||
if (fSource.IsSet())
|
||||
_InitFromSource();
|
||||
fUserRatings.push_back(rating);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageUserRatingInfoBuilder&
|
||||
PackageUserRatingInfoBuilder::WithSummary(UserRatingSummaryRef value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->Summary() != value) {
|
||||
_InitFromSource();
|
||||
fSummary = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PackageUserRatingInfoBuilder&
|
||||
PackageUserRatingInfoBuilder::WithUserRatingsPopulated()
|
||||
{
|
||||
if (!fSource.IsSet() || !fSource->UserRatingsPopulated()) {
|
||||
_InitFromSource();
|
||||
fUserRatingsPopulated = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageUserRatingInfoBuilder::_InitFromSource()
|
||||
{
|
||||
if (fSource.IsSet()) {
|
||||
_Init(fSource.Get());
|
||||
fSource.Unset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageUserRatingInfoBuilder::_Init(const PackageUserRatingInfo* value)
|
||||
{
|
||||
fSummary = value->Summary();
|
||||
fUserRatingsPopulated = value->UserRatingsPopulated();
|
||||
|
||||
int32 count = value->CountUserRatings();
|
||||
for (int32 i = 0; i < count; i++)
|
||||
fUserRatings.push_back(value->UserRatingAtIndex(i));
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_USER_RATING_INFO_H
|
||||
#define PACKAGE_USER_RATING_INFO_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "UserRating.h"
|
||||
#include "UserRatingSummary.h"
|
||||
|
||||
|
||||
class PackageUserRatingInfoBuilder;
|
||||
|
||||
|
||||
/*! This class carries the collection of user ratings related to a package but
|
||||
also provides an instance of `UserRatingSummaryRef` which is a summary of
|
||||
the user ratings.
|
||||
|
||||
Instances of this class should not be created directly; instead use the
|
||||
PackageUserRatingInfoBuilder class as a builder-constructor.
|
||||
*/
|
||||
class PackageUserRatingInfo : public BReferenceable
|
||||
{
|
||||
friend class PackageUserRatingInfoBuilder;
|
||||
|
||||
public:
|
||||
PackageUserRatingInfo();
|
||||
PackageUserRatingInfo(const PackageUserRatingInfo& other);
|
||||
|
||||
bool operator==(const PackageUserRatingInfo& other) const;
|
||||
bool operator!=(const PackageUserRatingInfo& other) const;
|
||||
|
||||
const UserRatingSummaryRef
|
||||
Summary() const;
|
||||
int32 CountUserRatings() const;
|
||||
const UserRatingRef UserRatingAtIndex(int32 index) const;
|
||||
bool UserRatingsPopulated() const;
|
||||
|
||||
private:
|
||||
void SetSummary(UserRatingSummaryRef value);
|
||||
void AddUserRating(const UserRatingRef& rating);
|
||||
void SetUserRatingsPopulated();
|
||||
|
||||
private:
|
||||
std::vector<UserRatingRef>
|
||||
fUserRatings;
|
||||
UserRatingSummaryRef
|
||||
fSummary;
|
||||
bool fUserRatingsPopulated;
|
||||
};
|
||||
|
||||
|
||||
typedef BReference<PackageUserRatingInfo> PackageUserRatingInfoRef;
|
||||
|
||||
|
||||
class PackageUserRatingInfoBuilder
|
||||
{
|
||||
public:
|
||||
PackageUserRatingInfoBuilder();
|
||||
PackageUserRatingInfoBuilder(const PackageUserRatingInfoRef& other);
|
||||
virtual ~PackageUserRatingInfoBuilder();
|
||||
|
||||
PackageUserRatingInfoRef
|
||||
BuildRef();
|
||||
|
||||
PackageUserRatingInfoBuilder&
|
||||
AddUserRating(const UserRatingRef& rating);
|
||||
PackageUserRatingInfoBuilder&
|
||||
WithSummary(UserRatingSummaryRef value);
|
||||
PackageUserRatingInfoBuilder&
|
||||
WithUserRatingsPopulated();
|
||||
|
||||
private:
|
||||
void _InitFromSource();
|
||||
void _Init(const PackageUserRatingInfo* value);
|
||||
|
||||
private:
|
||||
PackageUserRatingInfoRef
|
||||
fSource;
|
||||
std::vector<UserRatingRef>
|
||||
fUserRatings;
|
||||
UserRatingSummaryRef
|
||||
fSummary;
|
||||
bool fUserRatingsPopulated;
|
||||
};
|
||||
|
||||
|
||||
#endif // PACKAGE_USER_RATING_INFO_H
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,14 @@ PackageVersion::PackageVersion()
|
||||
}
|
||||
|
||||
|
||||
PackageVersion::PackageVersion(uint64 createTimestamp)
|
||||
:
|
||||
BPackageVersion(),
|
||||
fCreateTimestamp(createTimestamp)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageVersion::PackageVersion(const PackageVersion& other)
|
||||
:
|
||||
BPackageVersion(other),
|
||||
@@ -23,6 +31,14 @@ PackageVersion::PackageVersion(const PackageVersion& other)
|
||||
}
|
||||
|
||||
|
||||
PackageVersion::PackageVersion(const PackageVersion& other, uint64 createTimestamp)
|
||||
:
|
||||
BPackageVersion(other),
|
||||
fCreateTimestamp(createTimestamp)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageVersion::PackageVersion(const BPackageVersion& other)
|
||||
:
|
||||
BPackageVersion(other),
|
||||
@@ -36,22 +52,10 @@ PackageVersion::~PackageVersion()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageVersion::SetCreateTimestamp(uint64 value)
|
||||
uint64
|
||||
PackageVersion::CreateTimestamp() const
|
||||
{
|
||||
fCreateTimestamp = value;
|
||||
}
|
||||
|
||||
|
||||
PackageVersion&
|
||||
PackageVersion::operator=(const PackageVersion& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
// can't use BPackageVersion operator= possibly because it is inlined?
|
||||
SetTo(other.Major(), other.Minor(), other.Micro(), other.PreRelease(), other.Revision());
|
||||
fCreateTimestamp = other.fCreateTimestamp;
|
||||
}
|
||||
return *this;
|
||||
return fCreateTimestamp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_VERSION_H
|
||||
@@ -18,17 +18,16 @@ class PackageVersion : public BPackageVersion, public BReferenceable
|
||||
{
|
||||
public:
|
||||
PackageVersion();
|
||||
PackageVersion(uint64 createTimestamp);
|
||||
PackageVersion(const PackageVersion& other);
|
||||
PackageVersion(const PackageVersion& other, uint64 createTimestamp);
|
||||
PackageVersion(const BPackageVersion& other);
|
||||
virtual ~PackageVersion();
|
||||
|
||||
PackageVersion& operator=(const PackageVersion& other);
|
||||
bool operator==(const PackageVersion& other) const;
|
||||
bool operator!=(const PackageVersion& other) const;
|
||||
|
||||
uint64 CreateTimestamp() const
|
||||
{ return fCreateTimestamp; }
|
||||
void SetCreateTimestamp(uint64 value);
|
||||
uint64 CreateTimestamp() const;
|
||||
|
||||
private:
|
||||
uint64 fCreateTimestamp;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2013, Rene Gollent <[email protected]>.
|
||||
* Copyright 2016-2023, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -30,14 +30,6 @@ UserInfo::UserInfo(const UserInfo& other)
|
||||
}
|
||||
|
||||
|
||||
UserInfo&
|
||||
UserInfo::operator=(const UserInfo& other)
|
||||
{
|
||||
fNickName = other.fNickName;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UserInfo::operator==(const UserInfo& other) const
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2016-2023, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef USER_INFO_H
|
||||
@@ -16,7 +16,6 @@ public:
|
||||
UserInfo(const BString& nickName);
|
||||
UserInfo(const UserInfo& other);
|
||||
|
||||
UserInfo& operator=(const UserInfo& other);
|
||||
bool operator==(const UserInfo& other) const;
|
||||
bool operator!=(const UserInfo& other) const;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2013, Rene Gollent <[email protected]>.
|
||||
* Copyright 2016-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -47,19 +47,6 @@ UserRating::UserRating(const UserRating& other)
|
||||
}
|
||||
|
||||
|
||||
UserRating&
|
||||
UserRating::operator=(const UserRating& other)
|
||||
{
|
||||
fUserInfo = other.fUserInfo;
|
||||
fRating = other.fRating;
|
||||
fComment = other.fComment;
|
||||
fLanguageId = other.fLanguageId;
|
||||
fPackageVersion = other.fPackageVersion;
|
||||
fCreateTimestamp = other.fCreateTimestamp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UserRating::operator==(const UserRating& other) const
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2016-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef USER_RATING_H
|
||||
@@ -23,7 +23,6 @@ public:
|
||||
uint64 createTimestamp);
|
||||
UserRating(const UserRating& other);
|
||||
|
||||
UserRating& operator=(const UserRating& other);
|
||||
bool operator==(const UserRating& other) const;
|
||||
bool operator!=(const UserRating& other) const;
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "UserRatingInfo.h"
|
||||
|
||||
|
||||
UserRatingInfo::UserRatingInfo()
|
||||
:
|
||||
fUserRatings(),
|
||||
fSummary(),
|
||||
fUserRatingsPopulated(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
UserRatingInfo::UserRatingInfo(const UserRatingInfo& other)
|
||||
:
|
||||
fSummary(other.Summary()),
|
||||
fUserRatingsPopulated(other.UserRatingsPopulated())
|
||||
{
|
||||
for (int32 i = CountUserRatings() - 1; i >= 0; i--)
|
||||
AddUserRating(other.UserRatingAtIndex(i));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UserRatingInfo::Clear()
|
||||
{
|
||||
fSummary.Unset();
|
||||
ClearUserRatings();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UserRatingInfo::SetSummary(UserRatingSummaryRef value)
|
||||
{
|
||||
fSummary = value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UserRatingInfo::SetUserRatingsPopulated()
|
||||
{
|
||||
fUserRatingsPopulated = true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UserRatingInfo::UserRatingsPopulated() const
|
||||
{
|
||||
return fUserRatingsPopulated;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UserRatingInfo::ClearUserRatings()
|
||||
{
|
||||
fUserRatings.clear();
|
||||
fUserRatingsPopulated = false;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
UserRatingInfo::CountUserRatings() const
|
||||
{
|
||||
return fUserRatings.size();
|
||||
}
|
||||
|
||||
|
||||
UserRatingRef
|
||||
UserRatingInfo::UserRatingAtIndex(int32 index) const
|
||||
{
|
||||
return fUserRatings[index];
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UserRatingInfo::AddUserRating(const UserRatingRef& rating)
|
||||
{
|
||||
fUserRatings.push_back(rating);
|
||||
}
|
||||
|
||||
|
||||
UserRatingInfo&
|
||||
UserRatingInfo::operator=(const UserRatingInfo& other)
|
||||
{
|
||||
fSummary = other.Summary();
|
||||
|
||||
fUserRatings.clear();
|
||||
|
||||
fUserRatingsPopulated = other.UserRatingsPopulated();
|
||||
|
||||
for (int32 i = CountUserRatings() - 1; i >= 0; i--)
|
||||
AddUserRating(other.UserRatingAtIndex(i));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UserRatingInfo::operator==(const UserRatingInfo& other) const
|
||||
{
|
||||
if (Summary() != other.Summary())
|
||||
return false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UserRatingInfo::operator!=(const UserRatingInfo& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef USER_RATING_INFO_H
|
||||
#define USER_RATING_INFO_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "UserRating.h"
|
||||
#include "UserRatingSummary.h"
|
||||
|
||||
|
||||
/*! This class carries the collection of user ratings related to a package but also provides
|
||||
an instance of `UserRatingSummaryRef` which is a summary of the user ratings.
|
||||
*/
|
||||
|
||||
class UserRatingInfo : public BReferenceable
|
||||
{
|
||||
public:
|
||||
UserRatingInfo();
|
||||
UserRatingInfo(const UserRatingInfo& other);
|
||||
|
||||
void Clear();
|
||||
|
||||
const UserRatingSummaryRef
|
||||
Summary() const
|
||||
{ return fSummary; }
|
||||
void SetSummary(UserRatingSummaryRef value);
|
||||
|
||||
void ClearUserRatings();
|
||||
void AddUserRating(const UserRatingRef& rating);
|
||||
int32 CountUserRatings() const;
|
||||
UserRatingRef UserRatingAtIndex(int32 index) const;
|
||||
|
||||
void SetUserRatingsPopulated();
|
||||
bool UserRatingsPopulated() const;
|
||||
|
||||
UserRatingInfo& operator=(const UserRatingInfo& other);
|
||||
bool operator==(const UserRatingInfo& other) const;
|
||||
bool operator!=(const UserRatingInfo& other) const;
|
||||
|
||||
private:
|
||||
std::vector<UserRatingRef>
|
||||
fUserRatings;
|
||||
UserRatingSummaryRef
|
||||
fSummary;
|
||||
bool fUserRatingsPopulated;
|
||||
};
|
||||
|
||||
typedef BReference<UserRatingInfo> UserRatingInfoRef;
|
||||
|
||||
|
||||
#endif // USER_RATING_SUMMARY_H
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2013, Rene Gollent <[email protected]>.
|
||||
* Copyright 2016-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -18,7 +18,7 @@ UserRatingSummary::UserRatingSummary()
|
||||
fRatingCount(0),
|
||||
fRatingCountNoStar(0)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
for (int i = 0; i <= 5; i++)
|
||||
fRatingCountByStar[i] = 0;
|
||||
}
|
||||
|
||||
@@ -34,15 +34,17 @@ UserRatingSummary::UserRatingSummary(const UserRatingSummary& other)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UserRatingSummary::Clear()
|
||||
float
|
||||
UserRatingSummary::AverageRating() const
|
||||
{
|
||||
fAverageRating = RATING_MISSING;
|
||||
fRatingCount = 0;
|
||||
fRatingCountNoStar = 0;
|
||||
return fAverageRating;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
fRatingCountByStar[i] = 0;
|
||||
|
||||
int
|
||||
UserRatingSummary::RatingCount() const
|
||||
{
|
||||
return fRatingCount;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,20 +95,6 @@ UserRatingSummary::SetRatingByStar(int star, int ratingCount)
|
||||
}
|
||||
|
||||
|
||||
UserRatingSummary&
|
||||
UserRatingSummary::operator=(const UserRatingSummary& other)
|
||||
{
|
||||
fAverageRating = other.AverageRating();
|
||||
fRatingCount = other.RatingCount();
|
||||
fRatingCountNoStar = other.RatingCountByStar(-1);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
fRatingCountByStar[i] = other.RatingCountByStar(i);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UserRatingSummary::operator==(const UserRatingSummary& other) const
|
||||
{
|
||||
@@ -129,3 +117,117 @@ UserRatingSummary::operator!=(const UserRatingSummary& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - UserRatingSummaryBuilder
|
||||
|
||||
|
||||
UserRatingSummaryBuilder::UserRatingSummaryBuilder()
|
||||
:
|
||||
fAverageRating(RATING_MISSING),
|
||||
fRatingCount(0),
|
||||
fRatingCountNoStar(0)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
fRatingCountByStar[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
UserRatingSummaryBuilder::UserRatingSummaryBuilder(const UserRatingSummaryRef& other)
|
||||
:
|
||||
fSource(),
|
||||
fAverageRating(RATING_MISSING),
|
||||
fRatingCount(0),
|
||||
fRatingCountNoStar(0)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
fRatingCountByStar[i] = other->RatingCountByStar(i);
|
||||
}
|
||||
|
||||
|
||||
UserRatingSummaryBuilder::~UserRatingSummaryBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
UserRatingSummaryRef
|
||||
UserRatingSummaryBuilder::BuildRef()
|
||||
{
|
||||
if (fSource.IsSet())
|
||||
return fSource;
|
||||
|
||||
UserRatingSummary* userRatingSummary = new UserRatingSummary();
|
||||
userRatingSummary->SetAverageRating(fAverageRating);
|
||||
userRatingSummary->SetRatingCount(fRatingCount);
|
||||
userRatingSummary->SetRatingByStar(RATING_MISSING_STAR, fRatingCountNoStar);
|
||||
|
||||
for (int star = 0; star <= 5; star++)
|
||||
userRatingSummary->SetRatingByStar(star, fRatingCountByStar[star]);
|
||||
|
||||
return UserRatingSummaryRef(userRatingSummary, true);
|
||||
}
|
||||
|
||||
|
||||
UserRatingSummaryBuilder&
|
||||
UserRatingSummaryBuilder::WithAverageRating(float value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->AverageRating() != value) {
|
||||
_InitFromSource();
|
||||
fAverageRating = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
UserRatingSummaryBuilder&
|
||||
UserRatingSummaryBuilder::WithRatingCount(int value)
|
||||
{
|
||||
if (!fSource.IsSet() || fSource->RatingCount() != value) {
|
||||
_InitFromSource();
|
||||
fRatingCount = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
UserRatingSummaryBuilder&
|
||||
UserRatingSummaryBuilder::AddRatingByStar(int star, int ratingCount)
|
||||
{
|
||||
if (star < RATING_MISSING_STAR || star > 5) {
|
||||
HDERROR("bad star %" B_PRId32 " in builder", star);
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (!fSource.IsSet() || fSource->RatingCountByStar(star) != ratingCount) {
|
||||
_InitFromSource();
|
||||
|
||||
if (star == RATING_MISSING_STAR)
|
||||
fRatingCountNoStar = ratingCount;
|
||||
else
|
||||
fRatingCountByStar[star] = ratingCount;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UserRatingSummaryBuilder::_InitFromSource()
|
||||
{
|
||||
if (fSource.IsSet()) {
|
||||
_Init(fSource.Get());
|
||||
fSource.Unset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UserRatingSummaryBuilder::_Init(const UserRatingSummary* value)
|
||||
{
|
||||
fAverageRating = value->AverageRating();
|
||||
fRatingCount = value->RatingCount();
|
||||
fRatingCountNoStar = value->RatingCountByStar(RATING_MISSING_STAR);
|
||||
|
||||
for (int i = 0; i <= 5; i++)
|
||||
fRatingCountByStar[i] = value->RatingCountByStar(i);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <[email protected]>.
|
||||
* Copyright 2016-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef USER_RATING_SUMMARY_H
|
||||
@@ -15,39 +15,70 @@
|
||||
include users' ratings for every single version of a package but only the last
|
||||
one. Other rules also apply. For this reason, the calculation is performed on
|
||||
the server-side and presented here.
|
||||
*/
|
||||
|
||||
Instances of this class should not be created directly; instead use the
|
||||
UserRatingSummaryBuilder class as a builder-constructor.
|
||||
*/
|
||||
class UserRatingSummary : public BReferenceable
|
||||
{
|
||||
friend class UserRatingSummaryBuilder;
|
||||
|
||||
public:
|
||||
UserRatingSummary();
|
||||
UserRatingSummary(const UserRatingSummary& other);
|
||||
|
||||
void Clear();
|
||||
bool operator==(const UserRatingSummary& other) const;
|
||||
bool operator!=(const UserRatingSummary& other) const;
|
||||
|
||||
float AverageRating() const
|
||||
{ return fAverageRating; }
|
||||
int RatingCount() const
|
||||
{ return fRatingCount; }
|
||||
float AverageRating() const;
|
||||
int RatingCount() const;
|
||||
int RatingCountByStar(int star) const;
|
||||
|
||||
private:
|
||||
void SetAverageRating(float value);
|
||||
void SetRatingCount(int value);
|
||||
void SetRatingByStar(int star, int ratingCount);
|
||||
|
||||
UserRatingSummary& operator=(const UserRatingSummary& other);
|
||||
bool operator==(const UserRatingSummary& other) const;
|
||||
bool operator!=(const UserRatingSummary& other) const;
|
||||
|
||||
private:
|
||||
float fAverageRating;
|
||||
int fRatingCount;
|
||||
|
||||
int fRatingCountNoStar;
|
||||
int fRatingCountByStar[6];
|
||||
};
|
||||
|
||||
|
||||
typedef BReference<UserRatingSummary> UserRatingSummaryRef;
|
||||
|
||||
|
||||
class UserRatingSummaryBuilder
|
||||
{
|
||||
public:
|
||||
UserRatingSummaryBuilder();
|
||||
UserRatingSummaryBuilder(const UserRatingSummaryRef& other);
|
||||
virtual ~UserRatingSummaryBuilder();
|
||||
|
||||
UserRatingSummaryRef
|
||||
BuildRef();
|
||||
|
||||
UserRatingSummaryBuilder&
|
||||
WithAverageRating(float value);
|
||||
UserRatingSummaryBuilder&
|
||||
WithRatingCount(int value);
|
||||
UserRatingSummaryBuilder&
|
||||
AddRatingByStar(int star, int ratingCount);
|
||||
|
||||
private:
|
||||
void _InitFromSource();
|
||||
void _Init(const UserRatingSummary* value);
|
||||
|
||||
private:
|
||||
UserRatingSummaryRef
|
||||
fSource;
|
||||
float fAverageRating;
|
||||
int fRatingCount;
|
||||
int fRatingCountNoStar;
|
||||
int fRatingCountByStar[6];
|
||||
};
|
||||
|
||||
|
||||
#endif // USER_RATING_SUMMARY_H
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2018-2022, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2018-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "AbstractProcess.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <AutoLocker.h>
|
||||
@@ -18,6 +18,9 @@
|
||||
#include "ProcessListener.h"
|
||||
|
||||
|
||||
static const bigtime_t kProcessUpdateMinimumDelay = 250000;
|
||||
|
||||
|
||||
AbstractProcess::AbstractProcess()
|
||||
:
|
||||
fLock(),
|
||||
@@ -25,7 +28,8 @@ AbstractProcess::AbstractProcess()
|
||||
fWasStopped(false),
|
||||
fProcessState(PROCESS_INITIAL),
|
||||
fErrorStatus(B_OK),
|
||||
fDurationSeconds(0.0)
|
||||
fDurationSeconds(0.0),
|
||||
fLastProgressUpdate(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -72,7 +76,7 @@ AbstractProcess::Run()
|
||||
|
||||
BStopWatch stopWatch("process", true);
|
||||
status_t runResult = RunInternal();
|
||||
fDurationSeconds = ((double) stopWatch.ElapsedTime() / 1000000.0);
|
||||
fDurationSeconds = static_cast<double>(stopWatch.ElapsedTime()) / 1000000.0;
|
||||
|
||||
if (runResult != B_OK)
|
||||
HDERROR("[%s] an error has arisen; %s", Name(), strerror(runResult));
|
||||
@@ -109,11 +113,11 @@ AbstractProcess::ErrorStatus()
|
||||
}
|
||||
|
||||
|
||||
/*! This method will stop the process. The actual process may carry on to
|
||||
perform some tidy-ups on its thread so this does not stop the thread or
|
||||
change the state of the process; just indicates to the running thread that
|
||||
it should stop. If it has not yet been started then it will be put into
|
||||
finished state.
|
||||
/*! This method will stop the process. The actual process may carry on to
|
||||
perform some tidy-ups on its thread so this does not stop the thread or
|
||||
change the state of the process; just indicates to the running thread that
|
||||
it should stop. If it has not yet been started then it will be put into
|
||||
finished state.
|
||||
*/
|
||||
|
||||
status_t
|
||||
@@ -196,6 +200,22 @@ AbstractProcess::LogReport()
|
||||
}
|
||||
|
||||
|
||||
/*! This method should be called before processing any progress. It will prevent
|
||||
progress updates from coming through too frequently.
|
||||
*/
|
||||
bool
|
||||
AbstractProcess::_ShouldProcessProgress()
|
||||
{
|
||||
bigtime_t now = system_time();
|
||||
|
||||
if (now - fLastProgressUpdate < kProcessUpdateMinimumDelay)
|
||||
return false;
|
||||
|
||||
fLastProgressUpdate = now;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ char
|
||||
AbstractProcess::_ProcessStateIdentifier(process_state value)
|
||||
{
|
||||
@@ -209,4 +229,4 @@ AbstractProcess::_ProcessStateIdentifier(process_state value)
|
||||
default:
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2022, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2018-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef ABSTRACT_PROCESS_H
|
||||
@@ -50,6 +50,8 @@ protected:
|
||||
|
||||
static char _ProcessStateIdentifier(process_state value);
|
||||
|
||||
bool _ShouldProcessProgress();
|
||||
|
||||
protected:
|
||||
BLocker fLock;
|
||||
|
||||
@@ -59,6 +61,7 @@ private:
|
||||
process_state fProcessState;
|
||||
status_t fErrorStatus;
|
||||
double fDurationSeconds;
|
||||
bigtime_t fLastProgressUpdate;
|
||||
};
|
||||
|
||||
#endif // ABSTRACT_PROCESS_H
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright 2018-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2018-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "ProcessCoordinatorFactory.h"
|
||||
|
||||
#include <Autolock.h>
|
||||
#include <AutoLocker.h>
|
||||
#include <Autolock.h>
|
||||
|
||||
#include <package/Context.h>
|
||||
#include <package/PackageRoster.h>
|
||||
@@ -42,13 +42,11 @@ using namespace BPackageKit;
|
||||
|
||||
|
||||
/*static*/ ProcessCoordinator*
|
||||
ProcessCoordinatorFactory::CreateIncrementViewCounter(
|
||||
Model* model, const PackageInfoRef package)
|
||||
ProcessCoordinatorFactory::CreateIncrementViewCounter(Model* model, const PackageInfoRef package)
|
||||
{
|
||||
ProcessCoordinator* processCoordinator = new ProcessCoordinator(
|
||||
"IncrementViewCounter");
|
||||
AbstractProcessNode* node = new ThreadedProcessNode(
|
||||
new IncrementViewCounterProcess(model, package));
|
||||
ProcessCoordinator* processCoordinator = new ProcessCoordinator("IncrementViewCounter");
|
||||
AbstractProcessNode* node
|
||||
= new ThreadedProcessNode(new IncrementViewCounterProcess(model, package));
|
||||
processCoordinator->AddNode(node);
|
||||
return processCoordinator;
|
||||
}
|
||||
@@ -56,56 +54,46 @@ ProcessCoordinatorFactory::CreateIncrementViewCounter(
|
||||
|
||||
/*static*/ ProcessCoordinator*
|
||||
ProcessCoordinatorFactory::CreateUserDetailVerifierCoordinator(
|
||||
UserDetailVerifierListener* userDetailVerifierListener,
|
||||
Model* model)
|
||||
UserDetailVerifierListener* userDetailVerifierListener, Model* model)
|
||||
{
|
||||
ProcessCoordinator* processCoordinator = new ProcessCoordinator(
|
||||
"UserDetailVerifier");
|
||||
AbstractProcessNode* userDetailVerifier = new ThreadedProcessNode(
|
||||
new UserDetailVerifierProcess(model, userDetailVerifierListener));
|
||||
ProcessCoordinator* processCoordinator = new ProcessCoordinator("UserDetailVerifier");
|
||||
AbstractProcessNode* userDetailVerifier
|
||||
= new ThreadedProcessNode(new UserDetailVerifierProcess(model, userDetailVerifierListener));
|
||||
processCoordinator->AddNode(userDetailVerifier);
|
||||
return processCoordinator;
|
||||
}
|
||||
|
||||
|
||||
/* static */ ProcessCoordinator*
|
||||
ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
|
||||
PackageInfoListenerRef packageInfoListener,
|
||||
Model* model, bool forceLocalUpdate)
|
||||
ProcessCoordinatorFactory::CreateBulkLoadCoordinator(Model* model, bool forceLocalUpdate)
|
||||
{
|
||||
bool areWorkingFilesAvailable = StorageUtils::AreWorkingFilesAvailable();
|
||||
uint32 serverProcessOptions = _CalculateServerProcessOptions();
|
||||
BAutolock locker(model->Lock());
|
||||
ProcessCoordinator* processCoordinator = new ProcessCoordinator(
|
||||
"BulkLoad", new BMessage(MSG_BULK_LOAD_DONE));
|
||||
ProcessCoordinator* processCoordinator
|
||||
= new ProcessCoordinator("BulkLoad", new BMessage(MSG_BULK_LOAD_DONE));
|
||||
|
||||
AbstractProcessNode *localRepositoryUpdate =
|
||||
new ThreadedProcessNode(new LocalRepositoryUpdateProcess(model,
|
||||
forceLocalUpdate));
|
||||
AbstractProcessNode* localRepositoryUpdate
|
||||
= new ThreadedProcessNode(new LocalRepositoryUpdateProcess(model, forceLocalUpdate));
|
||||
processCoordinator->AddNode(localRepositoryUpdate);
|
||||
|
||||
AbstractProcessNode *localPkgDataLoad =
|
||||
new ThreadedProcessNode(new LocalPkgDataLoadProcess(
|
||||
packageInfoListener, model, forceLocalUpdate));
|
||||
AbstractProcessNode* localPkgDataLoad
|
||||
= new ThreadedProcessNode(new LocalPkgDataLoadProcess(model, forceLocalUpdate));
|
||||
localPkgDataLoad->AddPredecessor(localRepositoryUpdate);
|
||||
processCoordinator->AddNode(localPkgDataLoad);
|
||||
|
||||
if (areWorkingFilesAvailable) {
|
||||
AbstractProcessNode *serverIconExportUpdate =
|
||||
new ThreadedProcessNode(new ServerIconExportUpdateProcess(model,
|
||||
serverProcessOptions));
|
||||
AbstractProcessNode* serverIconExportUpdate = new ThreadedProcessNode(
|
||||
new ServerIconExportUpdateProcess(model, serverProcessOptions));
|
||||
serverIconExportUpdate->AddPredecessor(localPkgDataLoad);
|
||||
processCoordinator->AddNode(serverIconExportUpdate);
|
||||
|
||||
AbstractProcessNode *serverRepositoryDataUpdate =
|
||||
new ThreadedProcessNode(new ServerRepositoryDataUpdateProcess(model,
|
||||
serverProcessOptions));
|
||||
AbstractProcessNode* serverRepositoryDataUpdate = new ThreadedProcessNode(
|
||||
new ServerRepositoryDataUpdateProcess(model, serverProcessOptions));
|
||||
serverRepositoryDataUpdate->AddPredecessor(localPkgDataLoad);
|
||||
processCoordinator->AddNode(serverRepositoryDataUpdate);
|
||||
|
||||
AbstractProcessNode *serverReferenceDataUpdate =
|
||||
new ThreadedProcessNode(new ServerReferenceDataUpdateProcess(model,
|
||||
serverProcessOptions));
|
||||
AbstractProcessNode* serverReferenceDataUpdate = new ThreadedProcessNode(
|
||||
new ServerReferenceDataUpdateProcess(model, serverProcessOptions));
|
||||
processCoordinator->AddNode(serverReferenceDataUpdate);
|
||||
|
||||
// This one has to run after the server data is taken up because it
|
||||
@@ -113,8 +101,8 @@ ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
|
||||
// sourced from the server. It has all of the
|
||||
// `ServerPkgDataUpdateProcess` nodes configured as its predecessors.
|
||||
|
||||
AbstractProcessNode* populatePkgSizes =
|
||||
new ThreadedProcessNode(new PopulatePkgSizesProcess(model));
|
||||
AbstractProcessNode* populatePkgSizes
|
||||
= new ThreadedProcessNode(new PopulatePkgSizesProcess(model));
|
||||
|
||||
// create a process for each of the repositories that are configured on
|
||||
// the local system. Later, only those that have a web-app repository
|
||||
@@ -127,20 +115,19 @@ ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
|
||||
status_t repoNamesResult = roster.GetRepositoryNames(repoNames);
|
||||
|
||||
if (repoNamesResult == B_OK) {
|
||||
AutoLocker<BLocker> locker(model->Lock());
|
||||
|
||||
for (int32 i = 0; i < repoNames.CountStrings(); i++) {
|
||||
AbstractProcessNode* processNode = new ThreadedProcessNode(
|
||||
new ServerPkgDataUpdateProcess(
|
||||
repoNames.StringAt(i), model, serverProcessOptions));
|
||||
AbstractProcessNode* processNode
|
||||
= new ThreadedProcessNode(new ServerPkgDataUpdateProcess(repoNames.StringAt(i),
|
||||
model, serverProcessOptions));
|
||||
processNode->AddPredecessor(serverRepositoryDataUpdate);
|
||||
processNode->AddPredecessor(serverReferenceDataUpdate);
|
||||
processCoordinator->AddNode(processNode);
|
||||
|
||||
populatePkgSizes->AddPredecessor(processNode);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
HDERROR("a problem has arisen getting the repository names.");
|
||||
}
|
||||
|
||||
processCoordinator->AddNode(populatePkgSizes);
|
||||
}
|
||||
@@ -150,8 +137,7 @@ ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
|
||||
|
||||
|
||||
/*static*/ ProcessCoordinator*
|
||||
ProcessCoordinatorFactory::CreatePackageActionCoordinator(
|
||||
Model* model, BMessage* message)
|
||||
ProcessCoordinatorFactory::CreatePackageActionCoordinator(Model* model, BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case MSG_PKG_INSTALL:
|
||||
@@ -176,89 +162,80 @@ ProcessCoordinatorFactory::CacheScreenshotCoordinator(Model* model,
|
||||
|
||||
|
||||
/*static*/ ProcessCoordinator*
|
||||
ProcessCoordinatorFactory::PopulatePkgChangelogCoordinator(Model* model, PackageInfoRef package)
|
||||
ProcessCoordinatorFactory::PopulatePkgChangelogCoordinator(Model* model, const BString& packageName)
|
||||
{
|
||||
return _CreateSingleProcessCoordinator("PopulatePkgChangelog",
|
||||
new PopulatePkgChangelogFromServerProcess(package, model));
|
||||
new PopulatePkgChangelogFromServerProcess(packageName, model));
|
||||
}
|
||||
|
||||
|
||||
/*static*/ ProcessCoordinator*
|
||||
ProcessCoordinatorFactory::PopulatePkgUserRatingsCoordinator(Model* model, PackageInfoRef package)
|
||||
ProcessCoordinatorFactory::PopulatePkgUserRatingsCoordinator(Model* model,
|
||||
const BString& packageName)
|
||||
{
|
||||
return _CreateSingleProcessCoordinator("PopulatePkgUserRatings",
|
||||
new PopulatePkgUserRatingsFromServerProcess(package, model));
|
||||
new PopulatePkgUserRatingsFromServerProcess(packageName, model));
|
||||
}
|
||||
|
||||
|
||||
/*static*/ PackageInfoRef
|
||||
ProcessCoordinatorFactory::_ExtractPackageFromMessage(
|
||||
Model* model, BMessage* message)
|
||||
/*static*/ BString
|
||||
ProcessCoordinatorFactory::_ExtractPackageNameFromMessage(BMessage* message)
|
||||
{
|
||||
BString pkgName;
|
||||
if (message->FindString(KEY_PACKAGE_NAME, &pkgName) != B_OK)
|
||||
HDFATAL("malformed message missing key [%s]", KEY_PACKAGE_NAME);
|
||||
return model->PackageForName(pkgName);
|
||||
return pkgName;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ ProcessCoordinator*
|
||||
ProcessCoordinatorFactory::_CreateInstallPackageActionCoordinator(
|
||||
Model* model, BMessage* message)
|
||||
ProcessCoordinatorFactory::_CreateInstallPackageActionCoordinator(Model* model, BMessage* message)
|
||||
{
|
||||
ProcessCoordinator* processCoordinator = new ProcessCoordinator(
|
||||
"InstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE));
|
||||
PackageInfoRef package = _ExtractPackageFromMessage(model, message);
|
||||
if (package.IsSet()) {
|
||||
AbstractProcessNode *processNode =
|
||||
new ThreadedProcessNode(
|
||||
new InstallPackageProcess(package, model), 10);
|
||||
processCoordinator->AddNode(processNode);
|
||||
} else {
|
||||
HDERROR("unable to find the package");
|
||||
}
|
||||
ProcessCoordinator* processCoordinator
|
||||
= new ProcessCoordinator("InstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE));
|
||||
|
||||
AbstractProcessNode* processNode = new ThreadedProcessNode(
|
||||
new InstallPackageProcess(_ExtractPackageNameFromMessage(message), model), 10);
|
||||
|
||||
processCoordinator->AddNode(processNode);
|
||||
|
||||
return processCoordinator;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ ProcessCoordinator*
|
||||
ProcessCoordinatorFactory::_CreateUninstallPackageActionCoordinator(
|
||||
Model* model, BMessage* message)
|
||||
ProcessCoordinatorFactory::_CreateUninstallPackageActionCoordinator(Model* model, BMessage* message)
|
||||
{
|
||||
ProcessCoordinator* processCoordinator = new ProcessCoordinator(
|
||||
"UninstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE));
|
||||
PackageInfoRef package = _ExtractPackageFromMessage(model, message);
|
||||
if (package.IsSet()) {
|
||||
AbstractProcessNode *processNode =
|
||||
new ThreadedProcessNode(
|
||||
new UninstallPackageProcess(package, model), 10);
|
||||
processCoordinator->AddNode(processNode);
|
||||
} else {
|
||||
HDERROR("unable to find the package");
|
||||
}
|
||||
ProcessCoordinator* processCoordinator
|
||||
= new ProcessCoordinator("UninstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE));
|
||||
|
||||
AbstractProcessNode* processNode = new ThreadedProcessNode(
|
||||
new UninstallPackageProcess(_ExtractPackageNameFromMessage(message), model), 10);
|
||||
|
||||
processCoordinator->AddNode(processNode);
|
||||
|
||||
return processCoordinator;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ ProcessCoordinator*
|
||||
ProcessCoordinatorFactory::_CreateOpenPackageActionCoordinator(
|
||||
Model* model, BMessage* message)
|
||||
ProcessCoordinatorFactory::_CreateOpenPackageActionCoordinator(Model* model, BMessage* message)
|
||||
{
|
||||
ProcessCoordinator* processCoordinator = new ProcessCoordinator(
|
||||
"OpenPackage", new BMessage(MSG_PACKAGE_ACTION_DONE));
|
||||
PackageInfoRef package = _ExtractPackageFromMessage(model, message);
|
||||
if (package.IsSet()) {
|
||||
BMessage deskbarLinkMessage;
|
||||
if (message->FindMessage(KEY_DESKBAR_LINK, &deskbarLinkMessage) != B_OK)
|
||||
HDFATAL("malformed message missing key [%s]", KEY_DESKBAR_LINK);
|
||||
DeskbarLink deskbarLink(&deskbarLinkMessage);
|
||||
AbstractProcessNode *processNode =
|
||||
new ThreadedProcessNode(new OpenPackageProcess(
|
||||
package, model, deskbarLink));
|
||||
processCoordinator->AddNode(processNode);
|
||||
} else {
|
||||
HDERROR("unable to find the package");
|
||||
}
|
||||
ProcessCoordinator* processCoordinator
|
||||
= new ProcessCoordinator("OpenPackage", new BMessage(MSG_PACKAGE_ACTION_DONE));
|
||||
|
||||
BMessage deskbarLinkMessage;
|
||||
|
||||
if (message->FindMessage(KEY_DESKBAR_LINK, &deskbarLinkMessage) != B_OK)
|
||||
HDFATAL("malformed message missing key [%s]", KEY_DESKBAR_LINK);
|
||||
|
||||
DeskbarLink deskbarLink(&deskbarLinkMessage);
|
||||
|
||||
AbstractProcessNode* processNode = new ThreadedProcessNode(
|
||||
new OpenPackageProcess(_ExtractPackageNameFromMessage(message), model, deskbarLink));
|
||||
|
||||
processCoordinator->AddNode(processNode);
|
||||
|
||||
return processCoordinator;
|
||||
}
|
||||
|
||||
@@ -269,8 +246,7 @@ ProcessCoordinatorFactory::_CalculateServerProcessOptions()
|
||||
uint32 processOptions = 0;
|
||||
|
||||
if (ServerSettings::IsClientTooOld()) {
|
||||
HDINFO("bulk load proceeding without network communications "
|
||||
"because the client is too old");
|
||||
HDINFO("bulk load proceeding without network communications because the client is too old");
|
||||
processOptions |= SERVER_PROCESS_NO_NETWORKING;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2018-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PROCESS_COORDINATOR_FACTORY_H
|
||||
@@ -26,13 +26,10 @@ public:
|
||||
static ProcessCoordinator* CreateIncrementViewCounter(Model* model,
|
||||
const PackageInfoRef package);
|
||||
|
||||
static ProcessCoordinator* CreateBulkLoadCoordinator(
|
||||
PackageInfoListenerRef packageInfoListener,
|
||||
Model* model, bool forceLocalUpdate);
|
||||
static ProcessCoordinator* CreateBulkLoadCoordinator(Model* model, bool forceLocalUpdate);
|
||||
|
||||
static ProcessCoordinator* CreateUserDetailVerifierCoordinator(
|
||||
UserDetailVerifierListener*
|
||||
userDetailVerifierListener,
|
||||
UserDetailVerifierListener* userDetailVerifierListener,
|
||||
Model* model);
|
||||
|
||||
static ProcessCoordinator* CreatePackageActionCoordinator(
|
||||
@@ -42,16 +39,15 @@ public:
|
||||
Model* model, ScreenshotCoordinate& screenshotCoordinate);
|
||||
|
||||
static ProcessCoordinator* PopulatePkgChangelogCoordinator(Model* model,
|
||||
PackageInfoRef package);
|
||||
const BString& packageName);
|
||||
|
||||
static ProcessCoordinator* PopulatePkgUserRatingsCoordinator(Model* model,
|
||||
PackageInfoRef package);
|
||||
const BString& packageName);
|
||||
|
||||
private:
|
||||
static uint32 _CalculateServerProcessOptions();
|
||||
|
||||
static PackageInfoRef _ExtractPackageFromMessage(
|
||||
Model* model, BMessage* message);
|
||||
static BString _ExtractPackageNameFromMessage(BMessage* message);
|
||||
|
||||
static ProcessCoordinator* _CreateInstallPackageActionCoordinator(
|
||||
Model* model, BMessage* message);
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
/*
|
||||
* Copyright 2017-2023, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2017-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "AbstractServerProcess.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <BufferedDataIO.h>
|
||||
#include <AutoDeleter.h>
|
||||
#include <BufferedDataIO.h>
|
||||
#include <File.h>
|
||||
#include <FileIO.h>
|
||||
#include <HttpTime.h>
|
||||
@@ -26,7 +27,6 @@
|
||||
#include "ServerSettings.h"
|
||||
#include "StandardMetaDataJsonEventListener.h"
|
||||
#include "StorageUtils.h"
|
||||
#include "LoggingUrlProtocolListener.h"
|
||||
|
||||
|
||||
using namespace BPrivate::Network;
|
||||
@@ -40,14 +40,173 @@ using namespace BPrivate::Network;
|
||||
#define TIMEOUT_MICROSECONDS 3e+7
|
||||
|
||||
|
||||
const size_t kFileBufferSize = 10 * 1024;
|
||||
static const size_t kFileBufferSize = 10 * 1024;
|
||||
|
||||
|
||||
// #pragma mark - Interface ReadProgressDataIO
|
||||
|
||||
|
||||
class ReadProgressDataIO : public BDataIO
|
||||
{
|
||||
public:
|
||||
ReadProgressDataIO(AbstractServerProcess* serverProcess,
|
||||
BDataIO* delegate, size_t bytesTotal);
|
||||
virtual ~ReadProgressDataIO();
|
||||
|
||||
virtual ssize_t Read(void* buffer, size_t size);
|
||||
virtual ssize_t Write(const void* buffer, size_t size);
|
||||
|
||||
virtual status_t Flush();
|
||||
|
||||
private:
|
||||
AbstractServerProcess*
|
||||
fServerProcess;
|
||||
BDataIO* fDelegate;
|
||||
size_t fBytesRead;
|
||||
size_t fBytesTotal;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - Interface LoggingUrlProtocolListener
|
||||
|
||||
|
||||
class LoggingUrlProtocolListener : public BUrlProtocolListener
|
||||
{
|
||||
public:
|
||||
LoggingUrlProtocolListener(AbstractServerProcess* serverProcess,
|
||||
BString traceLoggingIdentifier, bool traceLogging);
|
||||
virtual ~LoggingUrlProtocolListener();
|
||||
|
||||
size_t ContentLength();
|
||||
|
||||
virtual void DownloadProgress(BUrlRequest* caller,
|
||||
off_t bytesReceived, off_t bytesTotal);
|
||||
virtual void BytesWritten(BUrlRequest* caller,
|
||||
size_t bytesWritten);
|
||||
virtual void DebugMessage(BUrlRequest* caller,
|
||||
BUrlProtocolDebugMessage type,
|
||||
const char* text);
|
||||
|
||||
private:
|
||||
AbstractServerProcess*
|
||||
fServerProcess;
|
||||
bool fTraceLogging;
|
||||
BString fTraceLoggingIdentifier;
|
||||
size_t fContentLength;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - Implementation for ReadProgressDataIO
|
||||
|
||||
|
||||
ReadProgressDataIO::ReadProgressDataIO(AbstractServerProcess* serverProcess, BDataIO* delegate,
|
||||
size_t bytesTotal)
|
||||
:
|
||||
fServerProcess(serverProcess),
|
||||
fDelegate(delegate),
|
||||
fBytesRead(0),
|
||||
fBytesTotal(bytesTotal)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ReadProgressDataIO::~ReadProgressDataIO()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
ReadProgressDataIO::Read(void* buffer, size_t size)
|
||||
{
|
||||
ssize_t actualRead = fDelegate->Read(buffer, size);
|
||||
|
||||
if (actualRead > 0) {
|
||||
fBytesRead += actualRead;
|
||||
|
||||
if (fBytesTotal > 0.0f) {
|
||||
float progress = static_cast<float>(fBytesRead) / static_cast<float>(fBytesTotal);
|
||||
fServerProcess->SetDataProcessingProgress(progress);
|
||||
}
|
||||
}
|
||||
|
||||
return actualRead;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
ReadProgressDataIO::Write(const void* buffer, size_t size)
|
||||
{
|
||||
return B_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ReadProgressDataIO::Flush()
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Implementation for LoggingUrlProtocolListener
|
||||
|
||||
|
||||
LoggingUrlProtocolListener::LoggingUrlProtocolListener(AbstractServerProcess* serverProcess,
|
||||
BString traceLoggingIdentifier, bool traceLogging)
|
||||
:
|
||||
fServerProcess(serverProcess),
|
||||
fTraceLogging(traceLogging),
|
||||
fTraceLoggingIdentifier(traceLoggingIdentifier),
|
||||
fContentLength(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LoggingUrlProtocolListener::~LoggingUrlProtocolListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LoggingUrlProtocolListener::BytesWritten(BUrlRequest* caller, size_t bytesWritten)
|
||||
{
|
||||
fContentLength += bytesWritten;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LoggingUrlProtocolListener::DownloadProgress(BUrlRequest* caller, off_t bytesReceived,
|
||||
off_t bytesTotal)
|
||||
{
|
||||
float progress = static_cast<float>(bytesReceived) / static_cast<float>(bytesTotal);
|
||||
fServerProcess->SetDownloadProgress(progress);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LoggingUrlProtocolListener::DebugMessage(BUrlRequest* caller, BUrlProtocolDebugMessage type,
|
||||
const char* text)
|
||||
{
|
||||
HDTRACE("url->file <%s>; %s", fTraceLoggingIdentifier.String(), text);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
LoggingUrlProtocolListener::ContentLength()
|
||||
{
|
||||
return fContentLength;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - AbstractServerProcess
|
||||
|
||||
|
||||
AbstractServerProcess::AbstractServerProcess(uint32 options)
|
||||
:
|
||||
AbstractProcess(),
|
||||
fOptions(options),
|
||||
fRequest(NULL)
|
||||
fRequest(NULL),
|
||||
fDownloadProgress(kProgressIndeterminate),
|
||||
fDataProcessingProgress(kProgressIndeterminate)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -57,6 +216,44 @@ AbstractServerProcess::~AbstractServerProcess()
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
AbstractServerProcess::Progress()
|
||||
{
|
||||
if (fDataProcessingProgress >= 0.0f)
|
||||
return 0.5f + (0.5f * fminf(fDataProcessingProgress, 1.0));
|
||||
if (fDownloadProgress >= 0.0f)
|
||||
return 0.5f * fminf(fDownloadProgress, 1.0);
|
||||
return kProgressIndeterminate;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AbstractServerProcess::SetDownloadProgress(float value)
|
||||
{
|
||||
if (fDownloadProgress == 1.0 || (!_ShouldProcessProgress() && value != 1.0))
|
||||
return;
|
||||
|
||||
if (fDataProcessingProgress < 0.0f)
|
||||
fDownloadProgress = value;
|
||||
else
|
||||
fDownloadProgress = 1.0;
|
||||
|
||||
_NotifyChanged();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AbstractServerProcess::SetDataProcessingProgress(float value)
|
||||
{
|
||||
if (fDataProcessingProgress == 1.0 || (!_ShouldProcessProgress() && value != 1.0))
|
||||
return;
|
||||
|
||||
fDownloadProgress = 1.0;
|
||||
fDataProcessingProgress = value;
|
||||
_NotifyChanged();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AbstractServerProcess::HasOption(uint32 flag)
|
||||
{
|
||||
@@ -67,8 +264,7 @@ AbstractServerProcess::HasOption(uint32 flag)
|
||||
bool
|
||||
AbstractServerProcess::ShouldAttemptNetworkDownload(bool hasDataAlready)
|
||||
{
|
||||
return
|
||||
!HasOption(SERVER_PROCESS_NO_NETWORKING)
|
||||
return !HasOption(SERVER_PROCESS_NO_NETWORKING)
|
||||
&& !(HasOption(SERVER_PROCESS_PREFER_CACHE) && hasDataAlready);
|
||||
}
|
||||
|
||||
@@ -76,16 +272,15 @@ AbstractServerProcess::ShouldAttemptNetworkDownload(bool hasDataAlready)
|
||||
status_t
|
||||
AbstractServerProcess::StopInternal()
|
||||
{
|
||||
if (fRequest != NULL) {
|
||||
if (fRequest != NULL)
|
||||
return fRequest->Stop();
|
||||
}
|
||||
|
||||
return AbstractProcess::StopInternal();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AbstractServerProcess::IfModifiedSinceHeaderValue(BString& headerValue) const
|
||||
AbstractServerProcess::IfModifiedSinceHeaderValue(BString& headerValue)
|
||||
{
|
||||
BPath metaDataPath;
|
||||
BString jsonPath;
|
||||
@@ -102,15 +297,15 @@ AbstractServerProcess::IfModifiedSinceHeaderValue(BString& headerValue) const
|
||||
|
||||
|
||||
status_t
|
||||
AbstractServerProcess::IfModifiedSinceHeaderValue(BString& headerValue,
|
||||
const BPath& metaDataPath, const BString& jsonPath) const
|
||||
AbstractServerProcess::IfModifiedSinceHeaderValue(BString& headerValue, const BPath& metaDataPath,
|
||||
const BString& jsonPath)
|
||||
{
|
||||
headerValue.SetTo("");
|
||||
struct stat s;
|
||||
|
||||
if (-1 == stat(metaDataPath.Path(), &s)) {
|
||||
if (ENOENT != errno)
|
||||
return B_ERROR;
|
||||
return B_ERROR;
|
||||
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
@@ -121,11 +316,11 @@ AbstractServerProcess::IfModifiedSinceHeaderValue(BString& headerValue,
|
||||
StandardMetaData metaData;
|
||||
status_t result = PopulateMetaData(metaData, metaDataPath, jsonPath);
|
||||
|
||||
if (result == B_OK)
|
||||
if (result == B_OK) {
|
||||
SetIfModifiedSinceHeaderValueFromMetaData(headerValue, metaData);
|
||||
else {
|
||||
HDERROR("unable to parse the meta-data date and time from [%s]"
|
||||
" - cannot set the 'If-Modified-Since' header",
|
||||
} else {
|
||||
HDERROR("unable to parse the meta-data date and time from [%s] - cannot set the "
|
||||
"'If-Modified-Since' header",
|
||||
metaDataPath.Path());
|
||||
}
|
||||
|
||||
@@ -134,23 +329,19 @@ AbstractServerProcess::IfModifiedSinceHeaderValue(BString& headerValue,
|
||||
|
||||
|
||||
/*static*/ void
|
||||
AbstractServerProcess::SetIfModifiedSinceHeaderValueFromMetaData(
|
||||
BString& headerValue,
|
||||
AbstractServerProcess::SetIfModifiedSinceHeaderValueFromMetaData(BString& headerValue,
|
||||
const StandardMetaData& metaData)
|
||||
{
|
||||
// An example of this output would be; 'Fri, 24 Oct 2014 19:32:27 +0000'
|
||||
BDateTime modifiedDateTime = metaData
|
||||
.GetDataModifiedTimestampAsDateTime();
|
||||
BDateTime modifiedDateTime = metaData.GetDataModifiedTimestampAsDateTime();
|
||||
BHttpTime modifiedHttpTime(modifiedDateTime);
|
||||
headerValue.SetTo(modifiedHttpTime
|
||||
.ToString(B_HTTP_TIME_FORMAT_COOKIE));
|
||||
headerValue.SetTo(modifiedHttpTime.ToString(B_HTTP_TIME_FORMAT_COOKIE));
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AbstractServerProcess::PopulateMetaData(
|
||||
StandardMetaData& metaData, const BPath& path,
|
||||
const BString& jsonPath) const
|
||||
AbstractServerProcess::PopulateMetaData(StandardMetaData& metaData, const BPath& path,
|
||||
const BString& jsonPath)
|
||||
{
|
||||
StandardMetaDataJsonEventListener listener(jsonPath, metaData);
|
||||
status_t result = ParseJsonFromFileWithListener(&listener, path);
|
||||
@@ -164,8 +355,7 @@ AbstractServerProcess::PopulateMetaData(
|
||||
return result;
|
||||
|
||||
if (!metaData.IsPopulated()) {
|
||||
HDERROR("the meta data was read from [%s], but no values "
|
||||
"were extracted", path.Path());
|
||||
HDERROR("the meta data was read from [%s], but no values were extracted", path.Path());
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
@@ -174,7 +364,7 @@ AbstractServerProcess::PopulateMetaData(
|
||||
|
||||
|
||||
/* static */ bool
|
||||
AbstractServerProcess::_LooksLikeGzip(const char *pathStr)
|
||||
AbstractServerProcess::_LooksLikeGzip(const char* pathStr)
|
||||
{
|
||||
int l = strlen(pathStr);
|
||||
return l > 4 && 0 == strncmp(&pathStr[l - 3], ".gz", 3);
|
||||
@@ -187,36 +377,53 @@ AbstractServerProcess::_LooksLikeGzip(const char *pathStr)
|
||||
*/
|
||||
|
||||
status_t
|
||||
AbstractServerProcess::ParseJsonFromFileWithListener(
|
||||
BJsonEventListener *listener,
|
||||
const BPath& path) const
|
||||
AbstractServerProcess::ParseJsonFromFileWithListener(BJsonEventListener* listener,
|
||||
const BPath& path)
|
||||
{
|
||||
const char* pathStr = path.Path();
|
||||
|
||||
bool fileExists = false;
|
||||
off_t fileSize = 0;
|
||||
status_t existsResult = StorageUtils::ExistsObject(path, &fileExists, NULL, &fileSize);
|
||||
|
||||
if (existsResult != B_OK) {
|
||||
HDERROR("[%s] unable to get the length of the data file [%s]", Name(), pathStr);
|
||||
return existsResult;
|
||||
}
|
||||
|
||||
if (!fileExists) {
|
||||
HDERROR("[%s] missing data file [%s]", Name(), pathStr);
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (fileSize == 0) {
|
||||
HDERROR("[%s] empty data file [%s]", Name(), pathStr);
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
FILE* file = fopen(pathStr, "rb");
|
||||
|
||||
if (file == NULL) {
|
||||
HDERROR("[%s] unable to find the meta data file at [%s]", Name(),
|
||||
path.Path());
|
||||
HDERROR("[%s] unable to find the data file at [%s]", Name(), pathStr);
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
BFileIO rawInput(file, true); // takes ownership
|
||||
|
||||
BDataIO* bufferedRawInput = new BBufferedDataIO(rawInput, kFileBufferSize, false, true);
|
||||
ReadProgressDataIO readProgress(this, &rawInput, fileSize);
|
||||
BDataIO* bufferedRawInput = new BBufferedDataIO(readProgress, kFileBufferSize, false, true);
|
||||
ObjectDeleter<BDataIO> bufferedRawInputDeleter(bufferedRawInput);
|
||||
|
||||
// if the file extension ends with '.gz' then the data will be
|
||||
// compressed and the algorithm needs to decompress the data as
|
||||
// it is parsed.
|
||||
// if the file extension ends with '.gz' then the data will be
|
||||
// compressed and the algorithm needs to decompress the data as
|
||||
// it is parsed.
|
||||
|
||||
if (_LooksLikeGzip(pathStr)) {
|
||||
BDataIO* gzDecompressedInput = NULL;
|
||||
BZlibDecompressionParameters* zlibDecompressionParameters
|
||||
= new BZlibDecompressionParameters();
|
||||
|
||||
status_t result = BZlibCompressionAlgorithm()
|
||||
.CreateDecompressingInputStream(bufferedRawInput,
|
||||
zlibDecompressionParameters, gzDecompressedInput);
|
||||
status_t result = BZlibCompressionAlgorithm().CreateDecompressingInputStream(
|
||||
bufferedRawInput, zlibDecompressionParameters, gzDecompressedInput);
|
||||
|
||||
if (B_OK != result)
|
||||
return result;
|
||||
@@ -231,49 +438,47 @@ AbstractServerProcess::ParseJsonFromFileWithListener(
|
||||
}
|
||||
|
||||
|
||||
/*! In order to reduce the chance of failure half way through downloading a
|
||||
large file, this method will download the file to a temporary file and
|
||||
then it can rename the file to the final target file.
|
||||
/*! In order to reduce the chance of failure half way through downloading a
|
||||
large file, this method will download the file to a temporary file and
|
||||
then it can rename the file to the final target file.
|
||||
*/
|
||||
|
||||
status_t
|
||||
AbstractServerProcess::DownloadToLocalFileAtomically(
|
||||
const BPath& targetFilePath,
|
||||
const BUrl& url)
|
||||
AbstractServerProcess::DownloadToLocalFileAtomically(const BPath& targetFilePath, const BUrl& url)
|
||||
{
|
||||
BPath temporaryFilePath(tmpnam(NULL), NULL, true);
|
||||
status_t result = DownloadToLocalFile(
|
||||
temporaryFilePath, url, 0, 0);
|
||||
status_t result = DownloadToLocalFile(temporaryFilePath, url, 0, 0);
|
||||
|
||||
// if the data is coming in as .gz, but is not stored as .gz then
|
||||
// the data should be decompressed in the temporary file location
|
||||
// before being shifted into place.
|
||||
|
||||
if (result == B_OK
|
||||
&& _LooksLikeGzip(url.Path())
|
||||
&& !_LooksLikeGzip(targetFilePath.Path()))
|
||||
if (result == B_OK && _LooksLikeGzip(url.Path()) && !_LooksLikeGzip(targetFilePath.Path()))
|
||||
result = _DeGzipInSitu(temporaryFilePath);
|
||||
|
||||
// not copying if the data has not changed because the data will be
|
||||
// zero length. This is if the result is APP_ERR_NOT_MODIFIED.
|
||||
// not copying if the data has not changed because the data will be
|
||||
// zero length. This is if the result is APP_ERR_NOT_MODIFIED.
|
||||
|
||||
if (result == B_OK) {
|
||||
// if the file is zero length then assume that something has
|
||||
// gone wrong.
|
||||
// if the file is zero length then assume that something has
|
||||
// gone wrong.
|
||||
off_t size;
|
||||
bool hasFile;
|
||||
|
||||
result = StorageUtils::ExistsObject(temporaryFilePath, &hasFile, NULL,
|
||||
&size);
|
||||
result = StorageUtils::ExistsObject(temporaryFilePath, &hasFile, NULL, &size);
|
||||
|
||||
if (result == B_OK && hasFile && size > 0) {
|
||||
if (rename(temporaryFilePath.Path(), targetFilePath.Path()) != 0) {
|
||||
HDINFO("[%s] did rename [%s] --> [%s]",
|
||||
Name(), temporaryFilePath.Path(), targetFilePath.Path());
|
||||
HDINFO("[%s] did rename [%s] --> [%s]", Name(), temporaryFilePath.Path(),
|
||||
targetFilePath.Path());
|
||||
result = B_IO_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSuccess(result))
|
||||
SetDownloadProgress(1.0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -292,13 +497,11 @@ AbstractServerProcess::_DeGzipInSitu(const BPath& path)
|
||||
BZlibDecompressionParameters* zlibDecompressionParameters
|
||||
= new BZlibDecompressionParameters();
|
||||
|
||||
result = BZlibCompressionAlgorithm()
|
||||
.CreateDecompressingInputStream(&file,
|
||||
zlibDecompressionParameters, gzDecompressedInput);
|
||||
result = BZlibCompressionAlgorithm().CreateDecompressingInputStream(&file,
|
||||
zlibDecompressionParameters, gzDecompressedInput);
|
||||
|
||||
if (result == B_OK) {
|
||||
ObjectDeleter<BDataIO> gzDecompressedInputDeleter(
|
||||
gzDecompressedInput);
|
||||
ObjectDeleter<BDataIO> gzDecompressedInputDeleter(gzDecompressedInput);
|
||||
result = DataIOUtils::CopyAll(&tmpFile, gzDecompressedInput);
|
||||
}
|
||||
}
|
||||
@@ -308,8 +511,7 @@ AbstractServerProcess::_DeGzipInSitu(const BPath& path)
|
||||
HDERROR("unable to move the uncompressed data into place");
|
||||
result = B_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
HDERROR("it was not possible to decompress the data");
|
||||
}
|
||||
|
||||
@@ -318,15 +520,14 @@ AbstractServerProcess::_DeGzipInSitu(const BPath& path)
|
||||
|
||||
|
||||
status_t
|
||||
AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath,
|
||||
const BUrl& url, uint32 redirects, uint32 failures)
|
||||
AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath, const BUrl& url,
|
||||
uint32 redirects, uint32 failures)
|
||||
{
|
||||
if (WasStopped())
|
||||
return B_CANCELED;
|
||||
|
||||
if (redirects > MAX_REDIRECTS) {
|
||||
HDINFO("[%s] exceeded %d redirects --> failure", Name(),
|
||||
MAX_REDIRECTS);
|
||||
HDINFO("[%s] exceeded %d redirects --> failure", Name(), MAX_REDIRECTS);
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
@@ -338,7 +539,7 @@ AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath,
|
||||
HDINFO("[%s] will stream '%s' to [%s]", Name(), url.UrlString().String(),
|
||||
targetFilePath.Path());
|
||||
|
||||
LoggingUrlProtocolListener listener(Name(), Logger::IsTraceEnabled());
|
||||
LoggingUrlProtocolListener listener(this, Name(), Logger::IsTraceEnabled());
|
||||
BFile targetFile(targetFilePath.Path(), O_WRONLY | O_CREAT);
|
||||
status_t err = targetFile.InitCheck();
|
||||
if (err != B_OK)
|
||||
@@ -348,26 +549,23 @@ AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath,
|
||||
ServerSettings::AugmentHeaders(headers);
|
||||
|
||||
BString ifModifiedSinceHeader;
|
||||
status_t ifModifiedSinceHeaderStatus = IfModifiedSinceHeaderValue(
|
||||
ifModifiedSinceHeader);
|
||||
status_t ifModifiedSinceHeaderStatus = IfModifiedSinceHeaderValue(ifModifiedSinceHeader);
|
||||
|
||||
if (ifModifiedSinceHeaderStatus == B_OK &&
|
||||
ifModifiedSinceHeader.Length() > 0) {
|
||||
if (ifModifiedSinceHeaderStatus == B_OK && ifModifiedSinceHeader.Length() > 0)
|
||||
headers.AddHeader("If-Modified-Since", ifModifiedSinceHeader);
|
||||
}
|
||||
|
||||
thread_id thread;
|
||||
|
||||
BUrlRequest* request = BUrlProtocolRoster::MakeRequest(url, &targetFile,
|
||||
&listener);
|
||||
BUrlRequest* request = BUrlProtocolRoster::MakeRequest(url, &targetFile, &listener);
|
||||
if (request == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fRequest = dynamic_cast<BHttpRequest *>(request);
|
||||
fRequest = dynamic_cast<BHttpRequest*>(request);
|
||||
if (fRequest == NULL) {
|
||||
delete request;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
fRequest->SetHeaders(headers);
|
||||
fRequest->SetMaxRedirections(0);
|
||||
fRequest->SetTimeout(TIMEOUT_MICROSECONDS);
|
||||
@@ -376,11 +574,10 @@ AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath,
|
||||
|
||||
wait_for_thread(thread, NULL);
|
||||
|
||||
const BHttpResult& result = dynamic_cast<const BHttpResult&>(
|
||||
fRequest->Result());
|
||||
const BHttpResult& result = dynamic_cast<const BHttpResult&>(fRequest->Result());
|
||||
int32 statusCode = result.StatusCode();
|
||||
const BHttpHeaders responseHeaders = result.Headers();
|
||||
const char *locationC = responseHeaders["Location"];
|
||||
const char* locationC = responseHeaders["Location"];
|
||||
BString location;
|
||||
|
||||
if (locationC != NULL)
|
||||
@@ -415,8 +612,7 @@ AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath,
|
||||
return DownloadToLocalFile(targetFilePath, url, redirects, failures + 1);
|
||||
}
|
||||
|
||||
HDERROR("[%s] unexpected response from server [%" B_PRId32 "]",
|
||||
Name(), statusCode);
|
||||
HDERROR("[%s] unexpected response from server [%" B_PRId32 "]", Name(), statusCode);
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -433,9 +629,9 @@ AbstractServerProcess::DeleteLocalFile(const BPath& currentFilePath)
|
||||
|
||||
|
||||
/*! When a file is damaged or corrupted in some way, the file should be 'moved
|
||||
aside' so that it is not involved in the next update. This method will
|
||||
create such an alternative 'damaged' file location and move this file to
|
||||
that location.
|
||||
aside' so that it is not involved in the next update. This method will
|
||||
create such an alternative 'damaged' file location and move this file to
|
||||
that location.
|
||||
*/
|
||||
|
||||
status_t
|
||||
@@ -449,19 +645,20 @@ AbstractServerProcess::MoveDamagedFileAside(const BPath& currentFilePath)
|
||||
damagedFilePath.Append(damagedLeaf.String());
|
||||
|
||||
if (0 != rename(currentFilePath.Path(), damagedFilePath.Path())) {
|
||||
HDERROR("[%s] unable to move damaged file [%s] aside to [%s]",
|
||||
Name(), currentFilePath.Path(), damagedFilePath.Path());
|
||||
HDERROR("[%s] unable to move damaged file [%s] aside to [%s]", Name(),
|
||||
currentFilePath.Path(), damagedFilePath.Path());
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
HDINFO("[%s] did move damaged file [%s] aside to [%s]",
|
||||
Name(), currentFilePath.Path(), damagedFilePath.Path());
|
||||
HDINFO("[%s] did move damaged file [%s] aside to [%s]", Name(), currentFilePath.Path(),
|
||||
damagedFilePath.Path());
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AbstractServerProcess::IsSuccess(status_t e) {
|
||||
AbstractServerProcess::IsSuccess(status_t e)
|
||||
{
|
||||
return e == B_OK || e == HD_ERR_NOT_MODIFIED;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2020, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2017-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef ABSTRACT_SERVER_PROCESS_H
|
||||
@@ -34,6 +34,11 @@ public:
|
||||
AbstractServerProcess(uint32 options);
|
||||
virtual ~AbstractServerProcess();
|
||||
|
||||
virtual float Progress();
|
||||
|
||||
void SetDownloadProgress(float value);
|
||||
void SetDataProcessingProgress(float value);
|
||||
|
||||
protected:
|
||||
virtual status_t GetStandardMetaDataPath(
|
||||
BPath& path) const = 0;
|
||||
@@ -41,11 +46,11 @@ protected:
|
||||
BString& jsonPath) const = 0;
|
||||
|
||||
virtual status_t IfModifiedSinceHeaderValue(
|
||||
BString& headerValue) const;
|
||||
BString& headerValue);
|
||||
status_t IfModifiedSinceHeaderValue(
|
||||
BString& headerValue,
|
||||
const BPath& metaDataPath,
|
||||
const BString& jsonPath) const;
|
||||
const BString& jsonPath);
|
||||
static void SetIfModifiedSinceHeaderValueFromMetaData(
|
||||
BString& headerValue,
|
||||
const StandardMetaData& metaData);
|
||||
@@ -53,11 +58,11 @@ protected:
|
||||
status_t PopulateMetaData(
|
||||
StandardMetaData& metaData,
|
||||
const BPath& path,
|
||||
const BString& jsonPath) const;
|
||||
const BString& jsonPath);
|
||||
|
||||
status_t ParseJsonFromFileWithListener(
|
||||
BJsonEventListener *listener,
|
||||
const BPath& path) const;
|
||||
const BPath& path);
|
||||
|
||||
virtual status_t DownloadToLocalFileAtomically(
|
||||
const BPath& targetFilePath,
|
||||
@@ -81,13 +86,16 @@ private:
|
||||
const BUrl& url,
|
||||
uint32 redirects, uint32 failures);
|
||||
|
||||
static bool _LooksLikeGzip(const char *pathStr);
|
||||
static status_t _DeGzipInSitu(const BPath& path);
|
||||
static bool _LooksLikeGzip(const char *pathStr);
|
||||
static status_t _DeGzipInSitu(const BPath& path);
|
||||
|
||||
private:
|
||||
uint32 fOptions;
|
||||
|
||||
BHttpRequest* fRequest;
|
||||
|
||||
float fDownloadProgress;
|
||||
float fDataProcessingProgress;
|
||||
};
|
||||
|
||||
#endif // ABSTRACT_SERVER_PROCESS_H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2017-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -16,12 +16,11 @@
|
||||
#include "StorageUtils.h"
|
||||
|
||||
|
||||
AbstractSingleFileServerProcess::AbstractSingleFileServerProcess(
|
||||
uint32 options)
|
||||
AbstractSingleFileServerProcess::AbstractSingleFileServerProcess(uint32 options)
|
||||
:
|
||||
AbstractServerProcess(options),
|
||||
fDownloadDurationSeconds(0.0),
|
||||
fProcessLocalDataDurationSeconds(0.0)
|
||||
fProcessLocalDataDurationSeconds(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -56,25 +55,25 @@ AbstractSingleFileServerProcess::RunInternal()
|
||||
|
||||
if (IsSuccess(result) && ShouldAttemptNetworkDownload(hasData)) {
|
||||
BStopWatch stopWatch("download", true);
|
||||
result = DownloadToLocalFileAtomically(
|
||||
localPath,
|
||||
result = DownloadToLocalFileAtomically(localPath,
|
||||
ServerSettings::CreateFullUrl(urlPathComponent));
|
||||
fDownloadDurationSeconds = ((double) stopWatch.ElapsedTime() / 1000000.0);
|
||||
fDownloadDurationSeconds = ((double)stopWatch.ElapsedTime() / 1000000.0);
|
||||
|
||||
if (!IsSuccess(result)) {
|
||||
if (hasData) {
|
||||
HDINFO("[%s] failed to update data, but have old data "
|
||||
"anyway so carry on with that", Name());
|
||||
HDINFO("[%s] failed to update data, but have old data anyway so carry on with that",
|
||||
Name());
|
||||
result = B_OK;
|
||||
} else
|
||||
} else {
|
||||
HDERROR("[%s] failed to obtain data", Name());
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
HDINFO("[%s] did fetch data", Name());
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSuccess(result)) {
|
||||
status_t hasDataResult = StorageUtils::ExistsObject(
|
||||
localPath, &hasData, NULL, &size);
|
||||
status_t hasDataResult = StorageUtils::ExistsObject(localPath, &hasData, NULL, &size);
|
||||
|
||||
hasData = hasData && size > 0;
|
||||
|
||||
@@ -89,7 +88,7 @@ AbstractSingleFileServerProcess::RunInternal()
|
||||
|
||||
BStopWatch stopWatch("process local data", true);
|
||||
result = ProcessLocalData();
|
||||
fProcessLocalDataDurationSeconds = ((double) stopWatch.ElapsedTime() / 1000000.0);
|
||||
fProcessLocalDataDurationSeconds = ((double)stopWatch.ElapsedTime() / 1000000.0);
|
||||
|
||||
switch (result) {
|
||||
case B_OK:
|
||||
@@ -124,8 +123,7 @@ AbstractSingleFileServerProcess::LogReport()
|
||||
if (ProcessState() == PROCESS_COMPLETE) {
|
||||
BString downloadLogLine;
|
||||
BString localDataLogLine;
|
||||
downloadLogLine.SetToFormat("\n - download %6.3f",
|
||||
fDownloadDurationSeconds);
|
||||
downloadLogLine.SetToFormat("\n - download %6.3f", fDownloadDurationSeconds);
|
||||
localDataLogLine.SetToFormat("\n - process local data %6.3f",
|
||||
fProcessLocalDataDurationSeconds);
|
||||
result.Append(downloadLogLine);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021-2023, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2021-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "IncrementViewCounterProcess.h"
|
||||
@@ -20,14 +20,14 @@
|
||||
#define B_TRANSLATION_CONTEXT "IncrementViewCounterProcess"
|
||||
|
||||
|
||||
IncrementViewCounterProcess::IncrementViewCounterProcess(
|
||||
Model* model, const PackageInfoRef& package)
|
||||
IncrementViewCounterProcess::IncrementViewCounterProcess(Model* model,
|
||||
const PackageInfoRef& package)
|
||||
:
|
||||
fPackage(package),
|
||||
fModel(model)
|
||||
{
|
||||
fDescription = BString(B_TRANSLATE("Recording view of \"%PackageName%\""))
|
||||
.ReplaceAll("%PackageName%", fPackage->Name());
|
||||
.ReplaceAll("%PackageName%", fPackage->Name());
|
||||
}
|
||||
|
||||
|
||||
@@ -77,8 +77,8 @@ IncrementViewCounterProcess::RunInternal()
|
||||
|
||||
while (attempts > 0 && !WasStopped()) {
|
||||
BMessage resultEnvelope;
|
||||
WebAppInterface* webAppInterface = fModel->GetWebAppInterface();
|
||||
result = webAppInterface->IncrementViewCounter(fPackage, depot, resultEnvelope);
|
||||
WebAppInterfaceRef webApp = fModel->WebApp();
|
||||
result = webApp->IncrementViewCounter(fPackage, depot, resultEnvelope);
|
||||
|
||||
if (result == B_OK) {
|
||||
int32 errorCode = WebAppInterface::ErrorCodeFromResponse(resultEnvelope);
|
||||
@@ -97,8 +97,9 @@ IncrementViewCounterProcess::RunInternal()
|
||||
result = B_ERROR;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
HDERROR("an error has arisen incrementing the view counter");
|
||||
}
|
||||
|
||||
attempts--;
|
||||
_SpinBetweenAttempts();
|
||||
@@ -115,4 +116,3 @@ IncrementViewCounterProcess::_SpinBetweenAttempts()
|
||||
for (int32 i = 0; i < 10 && !WasStopped(); i++)
|
||||
usleep(miniSpinDelays);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,13 @@
|
||||
/*
|
||||
* Copyright 2018-2022, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2018-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef LOCAL_PKG_DATA_LOAD_PROCESS__H
|
||||
#define LOCAL_PKG_DATA_LOAD_PROCESS__H
|
||||
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "AbstractProcess.h"
|
||||
|
||||
#include "Model.h"
|
||||
@@ -29,9 +31,7 @@ class PkgDataLoadState;
|
||||
|
||||
class LocalPkgDataLoadProcess : public AbstractProcess {
|
||||
public:
|
||||
LocalPkgDataLoadProcess(
|
||||
PackageInfoListenerRef packageInfoListener,
|
||||
Model *model, bool force = false);
|
||||
LocalPkgDataLoadProcess(Model *model, bool force = false);
|
||||
virtual ~LocalPkgDataLoadProcess();
|
||||
|
||||
const char* Name() const;
|
||||
@@ -41,14 +41,11 @@ protected:
|
||||
virtual status_t RunInternal();
|
||||
|
||||
private:
|
||||
void _NotifyError(const BString& messageText) const;
|
||||
off_t _DeriveSize(const PackageInfoRef modelInfo) const;
|
||||
static void _NotifyError(const BString& messageText);
|
||||
|
||||
private:
|
||||
Model* fModel;
|
||||
bool fForce;
|
||||
PackageInfoListenerRef
|
||||
fPackageInfoListener;
|
||||
};
|
||||
|
||||
#endif // LOCAL_PKG_DATA_LOAD_PROCESS__H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Note that this file included code earlier from `Model.cpp` and
|
||||
@@ -21,10 +21,10 @@
|
||||
|
||||
|
||||
PopulatePkgChangelogFromServerProcess::PopulatePkgChangelogFromServerProcess(
|
||||
PackageInfoRef packageInfo, Model* model)
|
||||
const BString& packageName, Model* model)
|
||||
:
|
||||
fModel(model),
|
||||
fPackageInfo(packageInfo)
|
||||
fPackageName(packageName)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -54,10 +54,9 @@ PopulatePkgChangelogFromServerProcess::RunInternal()
|
||||
// TODO; use API spec to code generation techniques instead of this manually written client.
|
||||
|
||||
BMessage responsePayload;
|
||||
BString packageName = fPackageInfo->Name();
|
||||
status_t result;
|
||||
|
||||
result = fModel->GetWebAppInterface()->GetChangelog(packageName, responsePayload);
|
||||
result = fModel->WebApp()->GetChangelog(fPackageName, responsePayload);
|
||||
|
||||
if (result == B_OK) {
|
||||
BMessage resultMessage;
|
||||
@@ -67,31 +66,11 @@ PopulatePkgChangelogFromServerProcess::RunInternal()
|
||||
|
||||
if (result == B_OK) {
|
||||
if (resultMessage.FindString("content", &content) == B_OK) {
|
||||
content.Trim();
|
||||
|
||||
PackageLocalizedTextRef localizedText = fPackageInfo->LocalizedText();
|
||||
|
||||
if (localizedText.IsSet()) {
|
||||
localizedText = PackageLocalizedTextRef(
|
||||
new PackageLocalizedText(*(localizedText.Get())), true);
|
||||
} else {
|
||||
localizedText = PackageLocalizedTextRef(new PackageLocalizedText(), true);
|
||||
}
|
||||
|
||||
localizedText->SetChangelog(content);
|
||||
|
||||
// TODO; later work to make the `PackageInfo` immutable to avoid this locking
|
||||
BAutolock locker(fModel->Lock());
|
||||
fPackageInfo->SetLocalizedText(localizedText);
|
||||
HDDEBUG("changelog populated for [%s]", packageName.String());
|
||||
result = _UpdateChangelog(content.Trim());
|
||||
HDDEBUG("changelog populated for [%s]", fPackageName.String());
|
||||
} else {
|
||||
HDDEBUG("no changelog present for [%s]", packageName.String());
|
||||
HDDEBUG("no changelog present for [%s]", fPackageName.String());
|
||||
}
|
||||
} else {
|
||||
int32 errorCode = WebAppInterface::ErrorCodeFromResponse(responsePayload);
|
||||
|
||||
if (errorCode != ERROR_CODE_NONE)
|
||||
ServerHelper::NotifyServerJsonRpcError(responsePayload);
|
||||
}
|
||||
} else {
|
||||
ServerHelper::NotifyTransportError(result);
|
||||
@@ -99,3 +78,25 @@ PopulatePkgChangelogFromServerProcess::RunInternal()
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PopulatePkgChangelogFromServerProcess::_UpdateChangelog(const BString& value)
|
||||
{
|
||||
PackageInfoRef package = fModel->PackageForName(fPackageName);
|
||||
|
||||
if (!package.IsSet()) {
|
||||
HDERROR("the package [%s] was not found", fPackageName.String());
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
PackageLocalizedTextRef localizedText
|
||||
= PackageLocalizedTextBuilder(package->LocalizedText()).WithChangelog(value).BuildRef();
|
||||
|
||||
PackageInfoRef updatedPackage
|
||||
= PackageInfoBuilder(package).WithLocalizedText(localizedText).BuildRef();
|
||||
|
||||
fModel->AddPackage(updatedPackage);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
|
||||
*/
|
||||
@@ -31,7 +31,7 @@ class PkgDataLoadState;
|
||||
class PopulatePkgChangelogFromServerProcess : public AbstractProcess
|
||||
{
|
||||
public:
|
||||
PopulatePkgChangelogFromServerProcess(PackageInfoRef packageInfo,
|
||||
PopulatePkgChangelogFromServerProcess(const BString& packageName,
|
||||
Model *model);
|
||||
virtual ~PopulatePkgChangelogFromServerProcess();
|
||||
|
||||
@@ -41,9 +41,12 @@ public:
|
||||
protected:
|
||||
virtual status_t RunInternal();
|
||||
|
||||
private:
|
||||
status_t _UpdateChangelog(const BString& value);
|
||||
|
||||
private:
|
||||
Model* fModel;
|
||||
PackageInfoRef fPackageInfo;
|
||||
BString fPackageName;
|
||||
};
|
||||
|
||||
#endif // POPULATE_PKG_CHANGELOG_FROM_SERVER_PROCESS__H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2018-2025, Andrew Lindesay <[email protected]>.
|
||||
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
@@ -23,7 +23,8 @@
|
||||
|
||||
PopulatePkgSizesProcess::PopulatePkgSizesProcess(Model* model)
|
||||
:
|
||||
fModel(model)
|
||||
fModel(model),
|
||||
fProgress(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -47,55 +48,97 @@ PopulatePkgSizesProcess::Description() const
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
PopulatePkgSizesProcess::Progress()
|
||||
{
|
||||
return fProgress;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PopulatePkgSizesProcess::RunInternal()
|
||||
{
|
||||
int32 countPkgs = 0;
|
||||
int32 countPkgs;
|
||||
int32 countPkgSized = 0;
|
||||
int32 countPkgUnsized = 0;
|
||||
|
||||
HDINFO("[%s] will populate size for pkgs without a size", Name());
|
||||
|
||||
for (int32 d = 0; d < fModel->CountDepots() && !WasStopped(); d++) {
|
||||
DepotInfoRef depotInfo = fModel->DepotAtIndex(d);
|
||||
countPkgs += depotInfo->CountPackages();
|
||||
const std::vector<PackageInfoRef> packages = _SnapshotOfPackages();
|
||||
std::vector<PackageInfoRef> updatedPackages;
|
||||
|
||||
for (int32 p = 0; p < depotInfo->CountPackages(); p++) {
|
||||
PackageInfoRef packageInfo = depotInfo->PackageAtIndex(p);
|
||||
countPkgs = static_cast<int32>(packages.size());
|
||||
|
||||
if (!packageInfo.IsSet())
|
||||
HDFATAL("package is not set");
|
||||
for (int32 i = 0; i < countPkgs; i++) {
|
||||
PackageInfoRef package = packages[i];
|
||||
const char* packageName = package->Name().String();
|
||||
|
||||
PackageLocalInfoRef localInfo = PackageUtils::NewLocalInfo(packageInfo);
|
||||
PackageState state = localInfo->State();
|
||||
if (!package.IsSet())
|
||||
HDFATAL("package is not set");
|
||||
|
||||
if (localInfo->Size() <= 0 && (state == ACTIVATED || state == INSTALLED)) {
|
||||
off_t derivedSize = _DeriveSize(packageInfo);
|
||||
PackageLocalInfoRef localInfo = package->LocalInfo();
|
||||
|
||||
if (derivedSize > 0) {
|
||||
localInfo->SetSize(derivedSize);
|
||||
countPkgSized++;
|
||||
HDDEBUG("[%s] did derive a size for package [%s]", Name(),
|
||||
packageInfo->Name().String());
|
||||
} else {
|
||||
countPkgUnsized++;
|
||||
HDDEBUG("[%s] unable to derive a size for package [%s]", Name(),
|
||||
packageInfo->Name().String());
|
||||
}
|
||||
if (_ShouldDeriveSize(localInfo)) {
|
||||
off_t derivedSize = _DeriveSize(package);
|
||||
|
||||
if (derivedSize > 0) {
|
||||
PackageLocalInfoBuilder localInfoBuilder;
|
||||
|
||||
if (localInfo.IsSet())
|
||||
localInfoBuilder = PackageLocalInfoBuilder(localInfo);
|
||||
|
||||
localInfoBuilder.WithSize(derivedSize);
|
||||
|
||||
PackageLocalInfoRef localInfo = localInfoBuilder.BuildRef();
|
||||
|
||||
updatedPackages.push_back(
|
||||
PackageInfoBuilder(package).WithLocalInfo(localInfo).BuildRef());
|
||||
|
||||
countPkgSized++;
|
||||
HDDEBUG("[%s] did derive a size for package [%s]", Name(), packageName);
|
||||
} else {
|
||||
countPkgUnsized++;
|
||||
HDDEBUG("[%s] unable to derive a size for package [%s]", Name(), packageName);
|
||||
}
|
||||
|
||||
packageInfo->SetLocalInfo(localInfo);
|
||||
}
|
||||
|
||||
_SetProgress(static_cast<float>(i) / static_cast<float>(countPkgs));
|
||||
}
|
||||
|
||||
fModel->AddPackagesWithChange(updatedPackages, PKG_CHANGED_LOCAL_INFO);
|
||||
|
||||
_SetProgress(1.0);
|
||||
|
||||
HDINFO("[%s] did populate size for %" B_PRId32 " packages with %" B_PRId32
|
||||
" already having a size and %" B_PRId32 " unable to derive a size",
|
||||
Name(), countPkgSized, countPkgs - countPkgSized, countPkgUnsized);
|
||||
" already having a size and %" B_PRId32 " unable to derive a size",
|
||||
Name(), countPkgSized, countPkgs - (countPkgSized + countPkgUnsized), countPkgUnsized);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<PackageInfoRef>
|
||||
PopulatePkgSizesProcess::_SnapshotOfPackages() const
|
||||
{
|
||||
return fModel->Packages();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PopulatePkgSizesProcess::_ShouldDeriveSize(PackageLocalInfoRef localInfo) const
|
||||
{
|
||||
if (!localInfo.IsSet())
|
||||
return true;
|
||||
|
||||
if (localInfo->Size() > 0)
|
||||
return false;
|
||||
|
||||
PackageState state = localInfo->State();
|
||||
|
||||
return state == ACTIVATED || state == INSTALLED;
|
||||
}
|
||||
|
||||
|
||||
off_t
|
||||
PopulatePkgSizesProcess::_DeriveSize(const PackageInfoRef package) const
|
||||
{
|
||||
@@ -111,4 +154,14 @@ PopulatePkgSizesProcess::_DeriveSize(const PackageInfoRef package) const
|
||||
HDDEBUG("unable to get the local file of package [%s]", package->Name().String());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PopulatePkgSizesProcess::_SetProgress(float value)
|
||||
{
|
||||
if (!_ShouldProcessProgress() && value != 1.0 && (value - fProgress) < 0.1)
|
||||
return;
|
||||
fProgress = value;
|
||||
_NotifyChanged();
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/*
|
||||
* Copyright 2023, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2023-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef POPULATE_PKG_SIZES_PROCESS_H
|
||||
#define POPULATE_PKG_SIZES_PROCESS_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include "AbstractProcess.h"
|
||||
@@ -23,15 +25,22 @@ public:
|
||||
|
||||
virtual const char* Name() const;
|
||||
virtual const char* Description() const;
|
||||
virtual float Progress();
|
||||
|
||||
protected:
|
||||
virtual status_t RunInternal();
|
||||
|
||||
private:
|
||||
const std::vector<PackageInfoRef>
|
||||
_SnapshotOfPackages() const;
|
||||
bool _ShouldDeriveSize(PackageLocalInfoRef localInfo) const;
|
||||
off_t _DeriveSize(const PackageInfoRef modelInfo) const;
|
||||
|
||||
void _SetProgress(float value);
|
||||
|
||||
private:
|
||||
Model* fModel;
|
||||
float fProgress;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2024, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*
|
||||
@@ -23,10 +23,10 @@
|
||||
|
||||
|
||||
PopulatePkgUserRatingsFromServerProcess::PopulatePkgUserRatingsFromServerProcess(
|
||||
PackageInfoRef packageInfo, Model* model)
|
||||
const BString& packageName, Model* model)
|
||||
:
|
||||
fModel(model),
|
||||
fPackageInfo(packageInfo)
|
||||
fPackageName(packageName)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -59,29 +59,21 @@ PopulatePkgUserRatingsFromServerProcess::RunInternal()
|
||||
|
||||
// Retrieve info from web-app
|
||||
BMessage info;
|
||||
BString webAppRepositoryCode = _WebAppRepositoryCode();
|
||||
|
||||
BString packageName;
|
||||
BString webAppRepositoryCode;
|
||||
|
||||
{
|
||||
BAutolock locker(&fLock);
|
||||
packageName = fPackageInfo->Name();
|
||||
|
||||
BString depotName = PackageUtils::DepotName(fPackageInfo);
|
||||
const DepotInfo* depot = fModel->DepotForName(depotName);
|
||||
|
||||
if (depot != NULL)
|
||||
webAppRepositoryCode = depot->WebAppRepositoryCode();
|
||||
if (webAppRepositoryCode.IsEmpty()) {
|
||||
HDERROR("unable to get the web app repository code for pkg [%s]", fPackageName.String());
|
||||
status = B_ERROR;
|
||||
}
|
||||
|
||||
if (status == B_OK) {
|
||||
status = fModel->GetWebAppInterface()->RetrieveUserRatingsForPackageForDisplay(packageName,
|
||||
status = fModel->WebApp()->RetrieveUserRatingsForPackageForDisplay(fPackageName,
|
||||
webAppRepositoryCode, BString(), 0, PACKAGE_INFO_MAX_USER_RATINGS, info);
|
||||
// ^ note intentionally not using the repository source code as this would then show
|
||||
// too few results as it would be architecture specific.
|
||||
}
|
||||
|
||||
UserRatingInfoRef userRatingInfo(new UserRatingInfo(), true);
|
||||
PackageUserRatingInfoBuilder userRatingInfoBuilder;
|
||||
|
||||
if (status == B_OK) {
|
||||
// Parse message
|
||||
@@ -112,7 +104,7 @@ PopulatePkgUserRatingsFromServerProcess::RunInternal()
|
||||
BString user;
|
||||
BMessage userInfo;
|
||||
if (item.FindMessage("user", &userInfo) != B_OK
|
||||
|| userInfo.FindString("nickname", &user) != B_OK) {
|
||||
|| userInfo.FindString("nickname", &user) != B_OK) {
|
||||
HDERROR("ignored user rating [%s] without a user nickname", code.String());
|
||||
continue;
|
||||
}
|
||||
@@ -170,15 +162,15 @@ PopulatePkgUserRatingsFromServerProcess::RunInternal()
|
||||
UserRatingRef userRating(
|
||||
new UserRating(UserInfo(user), rating, comment, languageCode,
|
||||
// note that language identifiers are "code" in HDS and "id" in Haiku
|
||||
versionString, (uint64) createTimestamp),
|
||||
versionString, static_cast<uint64>(createTimestamp)),
|
||||
true);
|
||||
userRatingInfo->AddUserRating(userRating);
|
||||
userRatingInfoBuilder.AddUserRating(userRating);
|
||||
HDDEBUG("rating [%s] retrieved from server", code.String());
|
||||
}
|
||||
|
||||
userRatingInfo->SetUserRatingsPopulated();
|
||||
userRatingInfoBuilder.WithUserRatingsPopulated();
|
||||
HDDEBUG("did retrieve %" B_PRIi32 " user ratings for [%s]", index - 1,
|
||||
packageName.String());
|
||||
fPackageName.String());
|
||||
}
|
||||
} else {
|
||||
int32 errorCode = WebAppInterface::ErrorCodeFromResponse(info);
|
||||
@@ -197,14 +189,13 @@ PopulatePkgUserRatingsFromServerProcess::RunInternal()
|
||||
BMessage summaryResponse;
|
||||
|
||||
if (status == B_OK) {
|
||||
status = fModel->GetWebAppInterface()->RetrieveUserRatingSummaryForPackage(packageName,
|
||||
status = fModel->WebApp()->RetrieveUserRatingSummaryForPackage(fPackageName,
|
||||
webAppRepositoryCode, summaryResponse);
|
||||
}
|
||||
|
||||
if (status == B_OK) {
|
||||
// Parse message
|
||||
|
||||
UserRatingSummaryRef userRatingSummary(new UserRatingSummary(), true);
|
||||
UserRatingSummaryBuilder userRatingSummaryBuilder;
|
||||
|
||||
BMessage result;
|
||||
|
||||
@@ -214,15 +205,18 @@ PopulatePkgUserRatingsFromServerProcess::RunInternal()
|
||||
status = summaryResponse.FindMessage("result", &result);
|
||||
|
||||
double sampleSizeF;
|
||||
int sampleSize = 0;
|
||||
bool hasData;
|
||||
|
||||
if (status == B_OK)
|
||||
status = result.FindDouble("sampleSize", &sampleSizeF);
|
||||
|
||||
if (status == B_OK)
|
||||
userRatingSummary->SetRatingCount(static_cast<int>(sampleSizeF));
|
||||
if (status == B_OK) {
|
||||
sampleSize = static_cast<int>(sampleSizeF);
|
||||
userRatingSummaryBuilder.WithRatingCount(sampleSize);
|
||||
}
|
||||
|
||||
hasData = status == B_OK && userRatingSummary->RatingCount() > 0;
|
||||
hasData = status == B_OK && sampleSize > 0;
|
||||
|
||||
if (hasData) {
|
||||
double ratingF;
|
||||
@@ -231,7 +225,7 @@ PopulatePkgUserRatingsFromServerProcess::RunInternal()
|
||||
status = result.FindDouble("rating", &ratingF);
|
||||
|
||||
if (status == B_OK)
|
||||
userRatingSummary->SetAverageRating(ratingF);
|
||||
userRatingSummaryBuilder.WithAverageRating(ratingF);
|
||||
}
|
||||
|
||||
if (hasData) {
|
||||
@@ -261,11 +255,12 @@ PopulatePkgUserRatingsFromServerProcess::RunInternal()
|
||||
if (status == B_OK)
|
||||
status = ratingDistributionItem.FindDouble("total", &ratingDistributionTotalF);
|
||||
|
||||
userRatingSummary->SetRatingByStar(static_cast<int>(ratingDistributionRatingF),
|
||||
userRatingSummaryBuilder.AddRatingByStar(
|
||||
static_cast<int>(ratingDistributionRatingF),
|
||||
static_cast<int>(ratingDistributionTotalF));
|
||||
}
|
||||
|
||||
userRatingInfo->SetSummary(userRatingSummary);
|
||||
userRatingInfoBuilder.WithSummary(userRatingSummaryBuilder.BuildRef());
|
||||
} else {
|
||||
int32 errorCode = WebAppInterface::ErrorCodeFromResponse(summaryResponse);
|
||||
|
||||
@@ -277,10 +272,28 @@ PopulatePkgUserRatingsFromServerProcess::RunInternal()
|
||||
}
|
||||
|
||||
if (status == B_OK) {
|
||||
// TODO; later make the PackageInfo immutable to avoid the need for locking here.
|
||||
BAutolock locker(&fLock);
|
||||
fPackageInfo->SetUserRatingInfo(userRatingInfo);
|
||||
PackageInfoRef package = fModel->PackageForName(fPackageName);
|
||||
|
||||
PackageInfoRef updatedPackage = PackageInfoBuilder(package)
|
||||
.WithUserRatingInfo(userRatingInfoBuilder.BuildRef())
|
||||
.BuildRef();
|
||||
|
||||
fModel->AddPackage(updatedPackage);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
const BString
|
||||
PopulatePkgUserRatingsFromServerProcess::_WebAppRepositoryCode() const
|
||||
{
|
||||
const PackageInfoRef package = fModel->PackageForName(fPackageName);
|
||||
const BString depotName = PackageUtils::DepotName(package);
|
||||
const DepotInfoRef depot = fModel->DepotForName(depotName);
|
||||
|
||||
if (depot.IsSet())
|
||||
return depot->WebAppRepositoryCode();
|
||||
|
||||
return BString();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2024-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef POPULATE_PKG_USER_RATINGS_FROM_SERVER_PROCESS__H
|
||||
@@ -29,7 +29,7 @@ class PkgDataLoadState;
|
||||
class PopulatePkgUserRatingsFromServerProcess : public AbstractProcess
|
||||
{
|
||||
public:
|
||||
PopulatePkgUserRatingsFromServerProcess(PackageInfoRef packageInfo,
|
||||
PopulatePkgUserRatingsFromServerProcess(const BString& packageName,
|
||||
Model *model);
|
||||
virtual ~PopulatePkgUserRatingsFromServerProcess();
|
||||
|
||||
@@ -39,9 +39,12 @@ public:
|
||||
protected:
|
||||
virtual status_t RunInternal();
|
||||
|
||||
private:
|
||||
const BString _WebAppRepositoryCode() const;
|
||||
|
||||
private:
|
||||
Model* fModel;
|
||||
PackageInfoRef fPackageInfo;
|
||||
BString fPackageName;
|
||||
};
|
||||
|
||||
#endif // POPULATE_PKG_USER_RATINGS_FROM_SERVER_PROCESS__H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2017-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "ServerIconExportUpdateProcess.h"
|
||||
@@ -8,13 +8,14 @@
|
||||
#include <time.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <AutoLocker.h>
|
||||
#include <BufferIO.h>
|
||||
#include <Catalog.h>
|
||||
#include <FileIO.h>
|
||||
|
||||
#include "DataIOUtils.h"
|
||||
#include "HaikuDepotConstants.h"
|
||||
#include "Logger.h"
|
||||
#include "PackageIconTarRepository.h"
|
||||
#include "ServerHelper.h"
|
||||
#include "StandardMetaDataJsonEventListener.h"
|
||||
#include "StorageUtils.h"
|
||||
@@ -55,6 +56,7 @@ InfoJsonExtractEntryListener::InfoJsonExtractEntryListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
InfoJsonExtractEntryListener::~InfoJsonExtractEntryListener()
|
||||
{
|
||||
}
|
||||
@@ -68,14 +70,12 @@ InfoJsonExtractEntryListener::GetInfoJsonData()
|
||||
|
||||
|
||||
status_t
|
||||
InfoJsonExtractEntryListener::Handle( const TarArchiveHeader& header,
|
||||
size_t offset, BDataIO *data)
|
||||
InfoJsonExtractEntryListener::Handle(const TarArchiveHeader& header, size_t offset, BDataIO* data)
|
||||
{
|
||||
if (header.Length() > 0 && header.FileName() == ENTRY_PATH_METADATA) {
|
||||
status_t copyResult = DataIOUtils::CopyAll(&fInfoJsonData, data);
|
||||
if (copyResult == B_OK) {
|
||||
HDINFO("[InfoJsonExtractEntryListener] did extract [%s]",
|
||||
ENTRY_PATH_METADATA);
|
||||
HDINFO("[InfoJsonExtractEntryListener] did extract [%s]", ENTRY_PATH_METADATA);
|
||||
fInfoJsonData.Seek(0, SEEK_SET);
|
||||
return B_CANCELED;
|
||||
// this will prevent further scanning of the tar file
|
||||
@@ -88,10 +88,8 @@ InfoJsonExtractEntryListener::Handle( const TarArchiveHeader& header,
|
||||
|
||||
|
||||
/*! This constructor will locate the cached data in a standardized location
|
||||
*/
|
||||
|
||||
ServerIconExportUpdateProcess::ServerIconExportUpdateProcess(
|
||||
Model* model,
|
||||
*/
|
||||
ServerIconExportUpdateProcess::ServerIconExportUpdateProcess(Model* model,
|
||||
uint32 serverProcessOptions)
|
||||
:
|
||||
AbstractSingleFileServerProcess(serverProcessOptions),
|
||||
@@ -122,8 +120,20 @@ ServerIconExportUpdateProcess::Description() const
|
||||
status_t
|
||||
ServerIconExportUpdateProcess::ProcessLocalData()
|
||||
{
|
||||
status_t result = fModel->InitPackageIconRepository();
|
||||
_NotifyPackagesWithIconsInDepots();
|
||||
BPath tarPath;
|
||||
status_t result = GetLocalPath(tarPath);
|
||||
|
||||
if (result == B_OK) {
|
||||
PackageIconTarRepository* tarRepository = new PackageIconTarRepository(tarPath);
|
||||
|
||||
result = tarRepository->Init();
|
||||
|
||||
if (result == B_OK)
|
||||
fModel->SetIconRepository(PackageIconRepositoryRef(tarRepository, true));
|
||||
else
|
||||
delete tarRepository;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -144,7 +154,7 @@ ServerIconExportUpdateProcess::GetLocalPath(BPath& path) const
|
||||
*/
|
||||
|
||||
status_t
|
||||
ServerIconExportUpdateProcess::IfModifiedSinceHeaderValue(BString& headerValue) const
|
||||
ServerIconExportUpdateProcess::IfModifiedSinceHeaderValue(BString& headerValue)
|
||||
{
|
||||
headerValue.SetTo("");
|
||||
|
||||
@@ -164,13 +174,13 @@ ServerIconExportUpdateProcess::IfModifiedSinceHeaderValue(BString& headerValue)
|
||||
}
|
||||
|
||||
if (result == B_OK) {
|
||||
BFile *tarIo = new BFile(tarPath.Path(), O_RDONLY);
|
||||
ObjectDeleter<BFile> tarIoDeleter(tarIo);
|
||||
InfoJsonExtractEntryListener* extractDataListener
|
||||
= new InfoJsonExtractEntryListener();
|
||||
ObjectDeleter<InfoJsonExtractEntryListener> extractDataListenerDeleter(
|
||||
extractDataListener);
|
||||
result = TarArchiveService::ForEachEntry(*tarIo, extractDataListener);
|
||||
BFile* tarIo = new BFile(tarPath.Path(), O_RDONLY);
|
||||
BBufferIO* bufferTarIo = new BBufferIO(tarIo, 10 * 1024, true);
|
||||
ObjectDeleter<BBufferIO> tarIoDeleter(bufferTarIo);
|
||||
|
||||
InfoJsonExtractEntryListener* extractDataListener = new InfoJsonExtractEntryListener();
|
||||
ObjectDeleter<InfoJsonExtractEntryListener> extractDataListenerDeleter(extractDataListener);
|
||||
result = TarArchiveService::ForEachEntry(*bufferTarIo, extractDataListener);
|
||||
|
||||
if (result == B_CANCELED) {
|
||||
// the cancellation is expected because it will cancel when it finds
|
||||
@@ -181,26 +191,20 @@ ServerIconExportUpdateProcess::IfModifiedSinceHeaderValue(BString& headerValue)
|
||||
StandardMetaData metaData;
|
||||
BString metaDataJsonPath;
|
||||
GetStandardMetaDataJsonPath(metaDataJsonPath);
|
||||
StandardMetaDataJsonEventListener parseInfoJsonListener(
|
||||
metaDataJsonPath, metaData);
|
||||
BPrivate::BJson::Parse(
|
||||
&(extractDataListener->GetInfoJsonData()),
|
||||
StandardMetaDataJsonEventListener parseInfoJsonListener(metaDataJsonPath, metaData);
|
||||
BPrivate::BJson::Parse(&(extractDataListener->GetInfoJsonData()),
|
||||
&parseInfoJsonListener);
|
||||
|
||||
result = parseInfoJsonListener.ErrorStatus();
|
||||
|
||||
// An example of this output would be; 'Fri, 24 Oct 2014 19:32:27 +0000'
|
||||
// An example of this output would be; 'Fri, 24 Oct 2014 19:32:27 +0000'
|
||||
|
||||
if (result == B_OK) {
|
||||
SetIfModifiedSinceHeaderValueFromMetaData(
|
||||
headerValue, metaData);
|
||||
} else {
|
||||
HDERROR("[%s] unable to parse the meta data from the tar file",
|
||||
Name());
|
||||
}
|
||||
if (result == B_OK)
|
||||
SetIfModifiedSinceHeaderValueFromMetaData(headerValue, metaData);
|
||||
else
|
||||
HDERROR("[%s] unable to parse the meta data from the tar file", Name());
|
||||
} else {
|
||||
HDERROR("[%s] did not find the metadata [%s] in the tar",
|
||||
Name(), ENTRY_PATH_METADATA);
|
||||
HDERROR("[%s] did not find the metadata [%s] in the tar", Name(), ENTRY_PATH_METADATA);
|
||||
result = B_BAD_DATA;
|
||||
}
|
||||
}
|
||||
@@ -218,8 +222,7 @@ ServerIconExportUpdateProcess::GetStandardMetaDataPath(BPath& path) const
|
||||
|
||||
|
||||
void
|
||||
ServerIconExportUpdateProcess::GetStandardMetaDataJsonPath(
|
||||
BString& jsonPath) const
|
||||
ServerIconExportUpdateProcess::GetStandardMetaDataJsonPath(BString& jsonPath) const
|
||||
{
|
||||
jsonPath.SetTo("$");
|
||||
// the "$" here indicates that the data is at the top level.
|
||||
@@ -231,27 +234,3 @@ ServerIconExportUpdateProcess::UrlPathComponent()
|
||||
{
|
||||
return "/__pkgicon/all.tar.gz";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ServerIconExportUpdateProcess::_NotifyPackagesWithIconsInDepots() const
|
||||
{
|
||||
for (int32 d = 0; d < fModel->CountDepots(); d++) {
|
||||
_NotifyPackagesWithIconsInDepot(fModel->DepotAtIndex(d));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ServerIconExportUpdateProcess::_NotifyPackagesWithIconsInDepot(
|
||||
const DepotInfoRef& depot) const
|
||||
{
|
||||
PackageIconRepository& packageIconRepository
|
||||
= fModel->GetPackageIconRepository();
|
||||
for (int32 p = 0; p < depot->CountPackages(); p++) {
|
||||
AutoLocker<BLocker> locker(fModel->Lock());
|
||||
const PackageInfoRef& packageInfoRef = depot->PackageAtIndex(p);
|
||||
if (packageIconRepository.HasAnyIcon(packageInfoRef->Name()))
|
||||
packageInfoRef->NotifyChangedIcon();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2020, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2017-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef SERVER_ICON_EXPORT_UPDATE_PROCESS_H
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
|
||||
virtual status_t GetLocalPath(BPath& path) const;
|
||||
virtual status_t IfModifiedSinceHeaderValue(
|
||||
BString& headerValue) const;
|
||||
BString& headerValue);
|
||||
|
||||
|
||||
virtual status_t GetStandardMetaDataPath(BPath& path) const;
|
||||
@@ -42,11 +42,6 @@ public:
|
||||
protected:
|
||||
virtual BString UrlPathComponent();
|
||||
|
||||
private:
|
||||
void _NotifyPackagesWithIconsInDepots() const;
|
||||
void _NotifyPackagesWithIconsInDepot(
|
||||
const DepotInfoRef& depotInfo) const;
|
||||
|
||||
private:
|
||||
Model* fModel;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2024, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2017-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -33,18 +33,22 @@
|
||||
#define B_TRANSLATION_CONTEXT "ServerPkgDataUpdateProcess"
|
||||
|
||||
|
||||
/*! This package listener (not at the JSON level) is feeding in the
|
||||
packages as they are parsed and processing them.
|
||||
static std::size_t kPackageBatchSize = 100;
|
||||
|
||||
static uint32 kPackageChangeMask = PKG_CHANGED_RATINGS | PKG_CHANGED_SCREENSHOTS
|
||||
| PKG_CHANGED_CLASSIFICATION | PKG_CHANGED_LOCALIZED_TEXT | PKG_CHANGED_LOCAL_INFO
|
||||
| PKG_CHANGED_CORE_INFO;
|
||||
|
||||
|
||||
/*! This package listener (not at the JSON level) is feeding in the
|
||||
packages as they are parsed and processing them.
|
||||
*/
|
||||
|
||||
class PackageFillingPkgListener : public DumpExportPkgListener {
|
||||
public:
|
||||
PackageFillingPkgListener(Model *model,
|
||||
BString& depotName, Stoppable* stoppable);
|
||||
PackageFillingPkgListener(Model *model, Stoppable* stoppable);
|
||||
virtual ~PackageFillingPkgListener();
|
||||
|
||||
virtual bool ConsumePackage(const PackageInfoRef& package,
|
||||
DumpExportPkg* pkg);
|
||||
virtual bool Handle(DumpExportPkg* item);
|
||||
virtual void Complete();
|
||||
|
||||
@@ -53,26 +57,36 @@ public:
|
||||
private:
|
||||
static ScreenshotInfoRef _CreateScreenshot(DumpExportPkgScreenshot* screenshot);
|
||||
|
||||
void _FlushUpdatedPackages();
|
||||
|
||||
const PackageInfoRef
|
||||
_PackageForName(const BString& name) const;
|
||||
const PackageInfoRef
|
||||
_CreateUpdatePackage(const PackageInfoRef& package,
|
||||
const DumpExportPkg* pkg);
|
||||
|
||||
void _InitCategories();
|
||||
|
||||
private:
|
||||
BString fDepotName;
|
||||
Model* fModel;
|
||||
std::vector<CategoryRef>
|
||||
std::map<BString, CategoryRef>
|
||||
fCategories;
|
||||
std::vector<PackageInfoRef>
|
||||
fUpdatedPackages;
|
||||
Stoppable* fStoppable;
|
||||
uint32 fCount;
|
||||
bool fDebugEnabled;
|
||||
};
|
||||
|
||||
|
||||
PackageFillingPkgListener::PackageFillingPkgListener(Model* model,
|
||||
BString& depotName, Stoppable* stoppable)
|
||||
PackageFillingPkgListener::PackageFillingPkgListener(Model* model, Stoppable* stoppable)
|
||||
:
|
||||
fDepotName(depotName),
|
||||
fModel(model),
|
||||
fStoppable(stoppable),
|
||||
fCount(0),
|
||||
fDebugEnabled(Logger::IsDebugEnabled())
|
||||
{
|
||||
_InitCategories();
|
||||
}
|
||||
|
||||
|
||||
@@ -81,110 +95,133 @@ PackageFillingPkgListener::~PackageFillingPkgListener()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageFillingPkgListener::ConsumePackage(const PackageInfoRef& package,
|
||||
DumpExportPkg* pkg)
|
||||
void
|
||||
PackageFillingPkgListener::_InitCategories()
|
||||
{
|
||||
std::vector<CategoryRef> categories = fModel->Categories();
|
||||
std::vector<CategoryRef>::const_iterator it;
|
||||
|
||||
for (it = categories.begin(); it != categories.end(); it++) {
|
||||
const CategoryRef& category = *it;
|
||||
fCategories[category->Code()] = category;
|
||||
}
|
||||
|
||||
if (fCategories.empty())
|
||||
HDERROR("there are no categories present");
|
||||
}
|
||||
|
||||
|
||||
const PackageInfoRef
|
||||
PackageFillingPkgListener::_PackageForName(const BString& name) const
|
||||
{
|
||||
return fModel->PackageForName(name);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageFillingPkgListener::_FlushUpdatedPackages()
|
||||
{
|
||||
fModel->AddPackagesWithChange(fUpdatedPackages, kPackageChangeMask);
|
||||
fUpdatedPackages.clear();
|
||||
}
|
||||
|
||||
|
||||
/*! This method will produce a new package with the data provided by the
|
||||
server.
|
||||
*/
|
||||
const PackageInfoRef
|
||||
PackageFillingPkgListener::_CreateUpdatePackage(const PackageInfoRef& package,
|
||||
const DumpExportPkg* pkg)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
// Collects all of the changes here into one set of notifications to
|
||||
// the package's listeners. This way the quantity of BMessages
|
||||
// communicated back to listeners is considerably reduced. See stop
|
||||
// invocation later in this method.
|
||||
PackageClassificationInfoBuilder classificationInfoBuilder(
|
||||
package->PackageClassificationInfo());
|
||||
PackageLocalizedTextBuilder localizedTextBuilder(package->LocalizedText());
|
||||
PackageLocalInfoBuilder localInfoBuilder(package->LocalInfo());
|
||||
PackageCoreInfoBuilder coreInfoBuilder(package->CoreInfo());
|
||||
PackageScreenshotInfoBuilder screenshotInfoBuilder;
|
||||
// don't want to start with the existing data; just take what comes from the server.
|
||||
PackageUserRatingInfoBuilder userRatingBuilder;
|
||||
|
||||
package->StartCollatingChanges();
|
||||
|
||||
PackageClassificationInfoRef packageClassificationInfo(new PackageClassificationInfo(), true);
|
||||
|
||||
PackageLocalizedTextRef localizedText = PackageUtils::NewLocalizedText(package);
|
||||
PackageLocalInfoRef localInfo = PackageUtils::NewLocalInfo(package);
|
||||
PackageCoreInfoRef coreInfo = PackageUtils::NewCoreInfo(package);
|
||||
|
||||
localizedText->SetHasChangelog(pkg->HasChangelog());
|
||||
localizedTextBuilder.WithHasChangelog(pkg->HasChangelog());
|
||||
|
||||
if (0 != pkg->CountPkgVersions()) {
|
||||
|
||||
// this makes the assumption that the only version will be the
|
||||
// latest one.
|
||||
// this makes the assumption that the only version will be the
|
||||
// latest one.
|
||||
|
||||
DumpExportPkgVersion* pkgVersion = pkg->PkgVersionsItemAt(0);
|
||||
|
||||
if (!pkgVersion->TitleIsNull())
|
||||
localizedText->SetTitle(*(pkgVersion->Title()));
|
||||
localizedTextBuilder.WithTitle(*(pkgVersion->Title()));
|
||||
|
||||
if (!pkgVersion->SummaryIsNull())
|
||||
localizedText->SetSummary(*(pkgVersion->Summary()));
|
||||
localizedTextBuilder.WithSummary(*(pkgVersion->Summary()));
|
||||
|
||||
if (!pkgVersion->DescriptionIsNull())
|
||||
localizedText->SetDescription(*(pkgVersion->Description()));
|
||||
localizedTextBuilder.WithDescription(*(pkgVersion->Description()));
|
||||
|
||||
if (!pkgVersion->PayloadLengthIsNull())
|
||||
localInfo->SetSize(static_cast<off_t>(pkgVersion->PayloadLength()));
|
||||
localInfoBuilder.WithSize(static_cast<off_t>(pkgVersion->PayloadLength()));
|
||||
|
||||
if (!pkgVersion->CreateTimestampIsNull()) {
|
||||
PackageVersionRef version = coreInfo->Version();
|
||||
PackageVersionRef versionRef = PackageUtils::Version(package);
|
||||
|
||||
if (!version.IsSet()) {
|
||||
version = PackageVersionRef(new PackageVersion(), true);
|
||||
coreInfo->SetVersion(version);
|
||||
if (versionRef.IsSet()) {
|
||||
PackageVersion* version = versionRef.Get();
|
||||
versionRef = PackageVersionRef(
|
||||
new PackageVersion(*version, pkgVersion->CreateTimestamp()), true);
|
||||
} else {
|
||||
versionRef
|
||||
= PackageVersionRef(new PackageVersion(pkgVersion->CreateTimestamp()), true);
|
||||
}
|
||||
|
||||
version->SetCreateTimestamp(pkgVersion->CreateTimestamp());
|
||||
coreInfoBuilder.WithVersion(versionRef);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pkg->DerivedRatingIsNull()) {
|
||||
// TODO; unify the naming here!
|
||||
userRatingBuilder.WithSummary(UserRatingSummaryBuilder()
|
||||
.WithAverageRating(pkg->DerivedRating())
|
||||
.WithRatingCount(pkg->DerivedRatingSampleSize())
|
||||
.BuildRef());
|
||||
}
|
||||
|
||||
int32 countPkgCategories = pkg->CountPkgCategories();
|
||||
|
||||
for (i = 0; i < countPkgCategories; i++) {
|
||||
BString* categoryCode = pkg->PkgCategoriesItemAt(i)->Code();
|
||||
CategoryRef category = fModel->CategoryByCode(*categoryCode);
|
||||
CategoryRef category = fCategories[*categoryCode];
|
||||
|
||||
if (!category.IsSet()) {
|
||||
HDERROR("unable to find the category for [%s]",
|
||||
categoryCode->String());
|
||||
} else
|
||||
packageClassificationInfo->AddCategory(category);
|
||||
}
|
||||
|
||||
if (!pkg->DerivedRatingIsNull()) {
|
||||
UserRatingInfoRef userRatingInfo(new UserRatingInfo(), true);
|
||||
UserRatingSummaryRef userRatingSummary(new UserRatingSummary(), true);
|
||||
// TODO; unify the naming here!
|
||||
userRatingSummary->SetAverageRating(pkg->DerivedRating());
|
||||
userRatingSummary->SetRatingCount(pkg->DerivedRatingSampleSize());
|
||||
userRatingInfo->SetSummary(userRatingSummary);
|
||||
package->SetUserRatingInfo(userRatingInfo);
|
||||
if (!category.IsSet())
|
||||
HDERROR("unable to find the category for [%s]", categoryCode->String());
|
||||
else
|
||||
classificationInfoBuilder.AddCategory(category);
|
||||
}
|
||||
|
||||
if (!pkg->ProminenceOrderingIsNull())
|
||||
packageClassificationInfo->SetProminence(static_cast<uint32>(pkg->ProminenceOrdering()));
|
||||
classificationInfoBuilder.WithProminence(static_cast<uint32>(pkg->ProminenceOrdering()));
|
||||
|
||||
if (!pkg->IsNativeDesktopIsNull())
|
||||
packageClassificationInfo->SetIsNativeDesktop(pkg->IsNativeDesktop());
|
||||
classificationInfoBuilder.WithIsNativeDesktop(pkg->IsNativeDesktop());
|
||||
|
||||
int32 countPkgScreenshots = pkg->CountPkgScreenshots();
|
||||
PackageScreenshotInfoRef screenshotInfo(new PackageScreenshotInfo(), true);
|
||||
|
||||
for (i = 0; i < countPkgScreenshots; i++) {
|
||||
DumpExportPkgScreenshot* screenshot = pkg->PkgScreenshotsItemAt(i);
|
||||
screenshotInfo->AddScreenshot(_CreateScreenshot(screenshot));
|
||||
screenshotInfoBuilder.AddScreenshot(_CreateScreenshot(screenshot));
|
||||
}
|
||||
|
||||
package->SetScreenshotInfo(screenshotInfo);
|
||||
package->SetLocalizedText(localizedText);
|
||||
package->SetLocalInfo(localInfo);
|
||||
package->SetCoreInfo(coreInfo);
|
||||
|
||||
HDTRACE("did populate data for [%s] (%s)", pkg->Name()->String(),
|
||||
fDepotName.String());
|
||||
|
||||
fCount++;
|
||||
|
||||
package->SetPackageClassificationInfo(packageClassificationInfo);
|
||||
|
||||
package->EndCollatingChanges();
|
||||
|
||||
return !fStoppable->WasStopped();
|
||||
return PackageInfoBuilder(package)
|
||||
.WithScreenshotInfo(screenshotInfoBuilder.BuildRef())
|
||||
.WithUserRatingInfo(userRatingBuilder.BuildRef())
|
||||
.WithLocalizedText(localizedTextBuilder.BuildRef())
|
||||
.WithLocalInfo(localInfoBuilder.BuildRef())
|
||||
.WithCoreInfo(coreInfoBuilder.BuildRef())
|
||||
.WithPackageClassificationInfo(classificationInfoBuilder.BuildRef())
|
||||
.BuildRef();
|
||||
}
|
||||
|
||||
|
||||
@@ -208,23 +245,20 @@ PackageFillingPkgListener::Count()
|
||||
bool
|
||||
PackageFillingPkgListener::Handle(DumpExportPkg* pkg)
|
||||
{
|
||||
AutoLocker<BLocker> locker(fModel->Lock());
|
||||
DepotInfoRef depot = fModel->DepotForName(fDepotName);
|
||||
const BString packageName = *(pkg->Name());
|
||||
PackageInfoRef package = _PackageForName(packageName);
|
||||
|
||||
if (depot.Get() != NULL) {
|
||||
const BString packageName = *(pkg->Name());
|
||||
PackageInfoRef package = depot->PackageByName(packageName);
|
||||
if (package.Get() != NULL)
|
||||
ConsumePackage(package, pkg);
|
||||
else {
|
||||
HDINFO("[PackageFillingPkgListener] unable to find the pkg [%s]",
|
||||
packageName.String());
|
||||
}
|
||||
if (package.IsSet()) {
|
||||
fUpdatedPackages.push_back(_CreateUpdatePackage(package, pkg));
|
||||
HDTRACE("did populate data for [%s]", pkg->Name()->String());
|
||||
fCount++;
|
||||
} else {
|
||||
HDINFO("[PackageFillingPkgListener] unable to find the depot [%s]",
|
||||
fDepotName.String());
|
||||
HDINFO("[PackageFillingPkgListener] unable to find the pkg [%s]", packageName.String());
|
||||
}
|
||||
|
||||
if (fUpdatedPackages.size() > kPackageBatchSize)
|
||||
_FlushUpdatedPackages();
|
||||
|
||||
return !fStoppable->WasStopped();
|
||||
}
|
||||
|
||||
@@ -232,12 +266,11 @@ PackageFillingPkgListener::Handle(DumpExportPkg* pkg)
|
||||
void
|
||||
PackageFillingPkgListener::Complete()
|
||||
{
|
||||
_FlushUpdatedPackages();
|
||||
}
|
||||
|
||||
|
||||
ServerPkgDataUpdateProcess::ServerPkgDataUpdateProcess(
|
||||
BString depotName,
|
||||
Model *model,
|
||||
ServerPkgDataUpdateProcess::ServerPkgDataUpdateProcess(BString depotName, Model* model,
|
||||
uint32 serverProcessOptions)
|
||||
:
|
||||
AbstractSingleFileServerProcess(serverProcessOptions),
|
||||
@@ -245,9 +278,7 @@ ServerPkgDataUpdateProcess::ServerPkgDataUpdateProcess(
|
||||
fDepotName(depotName)
|
||||
{
|
||||
fName.SetToFormat("ServerPkgDataUpdateProcess<%s>", depotName.String());
|
||||
fDescription.SetTo(
|
||||
B_TRANSLATE("Synchronizing package data for repository "
|
||||
"'%REPO_NAME%'"));
|
||||
fDescription.SetTo(B_TRANSLATE("Synchronizing package data for repository '%REPO_NAME%'"));
|
||||
fDescription.ReplaceAll("%REPO_NAME%", depotName.String());
|
||||
}
|
||||
|
||||
@@ -287,7 +318,6 @@ ServerPkgDataUpdateProcess::GetLocalPath(BPath& path) const
|
||||
BString webAppRepositorySourceCode = _DeriveWebAppRepositorySourceCode();
|
||||
|
||||
if (!webAppRepositorySourceCode.IsEmpty()) {
|
||||
AutoLocker<BLocker> locker(fModel->Lock());
|
||||
return StorageUtils::DumpExportPkgDataPath(path, webAppRepositorySourceCode,
|
||||
fModel->PreferredLanguage());
|
||||
}
|
||||
@@ -301,15 +331,12 @@ ServerPkgDataUpdateProcess::ProcessLocalData()
|
||||
{
|
||||
BStopWatch watch("ServerPkgDataUpdateProcess::ProcessLocalData", true);
|
||||
|
||||
PackageFillingPkgListener* itemListener =
|
||||
new PackageFillingPkgListener(fModel, fDepotName, this);
|
||||
ObjectDeleter<PackageFillingPkgListener>
|
||||
itemListenerDeleter(itemListener);
|
||||
PackageFillingPkgListener* itemListener = new PackageFillingPkgListener(fModel, this);
|
||||
ObjectDeleter<PackageFillingPkgListener> itemListenerDeleter(itemListener);
|
||||
|
||||
BulkContainerDumpExportPkgJsonListener* listener =
|
||||
new BulkContainerDumpExportPkgJsonListener(itemListener);
|
||||
ObjectDeleter<BulkContainerDumpExportPkgJsonListener>
|
||||
listenerDeleter(listener);
|
||||
BulkContainerDumpExportPkgJsonListener* listener
|
||||
= new BulkContainerDumpExportPkgJsonListener(itemListener);
|
||||
ObjectDeleter<BulkContainerDumpExportPkgJsonListener> listenerDeleter(listener);
|
||||
|
||||
BPath localPath;
|
||||
status_t result = GetLocalPath(localPath);
|
||||
@@ -324,8 +351,8 @@ ServerPkgDataUpdateProcess::ProcessLocalData()
|
||||
|
||||
if (Logger::IsInfoEnabled()) {
|
||||
double secs = watch.ElapsedTime() / 1000000.0;
|
||||
HDINFO("[%s] did process %" B_PRIi32 " packages' data "
|
||||
"in (%6.3g secs)", Name(), itemListener->Count(), secs);
|
||||
HDINFO("[%s] did process %" B_PRIi32 " packages' data in (%6.3g secs)", Name(),
|
||||
itemListener->Count(), secs);
|
||||
}
|
||||
|
||||
return listener->ErrorStatus();
|
||||
@@ -340,8 +367,7 @@ ServerPkgDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const
|
||||
|
||||
|
||||
void
|
||||
ServerPkgDataUpdateProcess::GetStandardMetaDataJsonPath(
|
||||
BString& jsonPath) const
|
||||
ServerPkgDataUpdateProcess::GetStandardMetaDataJsonPath(BString& jsonPath) const
|
||||
{
|
||||
jsonPath.SetTo("$.info");
|
||||
}
|
||||
@@ -352,9 +378,8 @@ ServerPkgDataUpdateProcess::_DeriveWebAppRepositorySourceCode() const
|
||||
{
|
||||
const DepotInfo* depot = fModel->DepotForName(fDepotName);
|
||||
|
||||
if (depot == NULL) {
|
||||
if (depot == NULL)
|
||||
return BString();
|
||||
}
|
||||
|
||||
return depot->WebAppRepositorySourceCode();
|
||||
}
|
||||
@@ -364,8 +389,8 @@ status_t
|
||||
ServerPkgDataUpdateProcess::RunInternal()
|
||||
{
|
||||
if (_DeriveWebAppRepositorySourceCode().IsEmpty()) {
|
||||
HDINFO("[%s] am not updating data for depot [%s] as there is no"
|
||||
" web app repository source code available",
|
||||
HDINFO("[%s] am not updating data for depot [%s] as there is no web app repository source "
|
||||
"code available",
|
||||
Name(), fDepotName.String());
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2019-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -32,8 +32,7 @@
|
||||
#define B_TRANSLATION_CONTEXT "ServerReferenceDataUpdateProcess"
|
||||
|
||||
|
||||
ServerReferenceDataUpdateProcess::ServerReferenceDataUpdateProcess(
|
||||
Model* model,
|
||||
ServerReferenceDataUpdateProcess::ServerReferenceDataUpdateProcess(Model* model,
|
||||
uint32 serverProcessOptions)
|
||||
:
|
||||
AbstractSingleFileServerProcess(serverProcessOptions),
|
||||
@@ -65,7 +64,6 @@ BString
|
||||
ServerReferenceDataUpdateProcess::UrlPathComponent()
|
||||
{
|
||||
BString result;
|
||||
AutoLocker<BLocker> locker(fModel->Lock());
|
||||
result.SetToFormat("/__reference/all-%s.json.gz", fModel->PreferredLanguage()->ID());
|
||||
return result;
|
||||
}
|
||||
@@ -74,7 +72,6 @@ ServerReferenceDataUpdateProcess::UrlPathComponent()
|
||||
status_t
|
||||
ServerReferenceDataUpdateProcess::GetLocalPath(BPath& path) const
|
||||
{
|
||||
AutoLocker<BLocker> locker(fModel->Lock());
|
||||
return StorageUtils::DumpExportReferenceDataPath(path, fModel->PreferredLanguage());
|
||||
}
|
||||
|
||||
@@ -82,8 +79,7 @@ ServerReferenceDataUpdateProcess::GetLocalPath(BPath& path) const
|
||||
status_t
|
||||
ServerReferenceDataUpdateProcess::ProcessLocalData()
|
||||
{
|
||||
SingleDumpExportReferenceJsonListener* listener =
|
||||
new SingleDumpExportReferenceJsonListener();
|
||||
SingleDumpExportReferenceJsonListener* listener = new SingleDumpExportReferenceJsonListener();
|
||||
|
||||
BPath localPath;
|
||||
status_t result = GetLocalPath(localPath);
|
||||
@@ -120,91 +116,68 @@ ServerReferenceDataUpdateProcess::_ProcessData(DumpExportReference* data)
|
||||
|
||||
|
||||
status_t
|
||||
ServerReferenceDataUpdateProcess::_ProcessNaturalLanguages(
|
||||
DumpExportReference* data)
|
||||
ServerReferenceDataUpdateProcess::_ProcessNaturalLanguages(DumpExportReference* data)
|
||||
{
|
||||
HDINFO("[%s] will populate from %" B_PRId32 " possible natural languages",
|
||||
Name(), data->CountNaturalLanguages());
|
||||
AutoLocker<BLocker> locker(fModel->Lock());
|
||||
HDINFO("[%s] will populate from %" B_PRId32 " possible natural languages", Name(),
|
||||
data->CountNaturalLanguages());
|
||||
|
||||
LanguageRepository* languageRepository = fModel->Languages();
|
||||
languageRepository->Clear();
|
||||
std::vector<LanguageRef> languages;
|
||||
int32 count = 0;
|
||||
|
||||
for (int32 i = 0; i < data->CountNaturalLanguages(); i++) {
|
||||
DumpExportReferenceNaturalLanguage* naturalLanguage =
|
||||
data->NaturalLanguagesItemAt(i);
|
||||
languageRepository->AddLanguage(
|
||||
LanguageRef(new Language(*(naturalLanguage->Code()), *(naturalLanguage->Name()),
|
||||
naturalLanguage->IsPopular()),
|
||||
true));
|
||||
for (int32 i = data->CountNaturalLanguages() - 1; i > 0; i--) {
|
||||
DumpExportReferenceNaturalLanguage* naturalLanguage = data->NaturalLanguagesItemAt(i);
|
||||
Language* language = new Language(*(naturalLanguage->Code()), *(naturalLanguage->Name()),
|
||||
naturalLanguage->IsPopular());
|
||||
languages.push_back(LanguageRef(language, true));
|
||||
count++;
|
||||
}
|
||||
|
||||
// it could be that the preferred language does not exist in the
|
||||
// list. In this case it is necessary to choose one from the list.
|
||||
fModel->SetPreferredLanguage(LocaleUtils::DeriveDefaultLanguage(fModel->Languages()));
|
||||
|
||||
HDINFO("[%s] did add %" B_PRId32 " supported languages", Name(), count);
|
||||
if (!languages.empty()) {
|
||||
fModel->SetLanguagesAndPreferred(languages, LocaleUtils::DeriveDefaultLanguage(languages));
|
||||
HDINFO("[%s] did add %" B_PRId32 " supported languages", Name(), count);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ServerReferenceDataUpdateProcess::_ProcessPkgCategories(
|
||||
DumpExportReference* data)
|
||||
ServerReferenceDataUpdateProcess::_ProcessPkgCategories(DumpExportReference* data)
|
||||
{
|
||||
HDINFO("[%s] will populate %" B_PRId32 " pkg categories",
|
||||
Name(), data->CountPkgCategories());
|
||||
HDINFO("[%s] will populate %" B_PRId32 " pkg categories", Name(), data->CountPkgCategories());
|
||||
|
||||
std::vector<CategoryRef> assembledCategories;
|
||||
|
||||
for (int32 i = 0; i < data->CountPkgCategories(); i++) {
|
||||
DumpExportReferencePkgCategory* pkgCategory =
|
||||
data->PkgCategoriesItemAt(i);
|
||||
assembledCategories.push_back(CategoryRef(
|
||||
new PackageCategory(
|
||||
*(pkgCategory->Code()),
|
||||
*(pkgCategory->Name())
|
||||
),
|
||||
true));
|
||||
DumpExportReferencePkgCategory* pkgCategory = data->PkgCategoriesItemAt(i);
|
||||
assembledCategories.push_back(
|
||||
CategoryRef(new PackageCategory(*(pkgCategory->Code()), *(pkgCategory->Name())), true));
|
||||
}
|
||||
|
||||
{
|
||||
AutoLocker<BLocker> locker(fModel->Lock());
|
||||
fModel->AddCategories(assembledCategories);
|
||||
}
|
||||
fModel->SetCategories(assembledCategories);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ServerReferenceDataUpdateProcess::_ProcessRatingStabilities(
|
||||
DumpExportReference* data)
|
||||
ServerReferenceDataUpdateProcess::_ProcessRatingStabilities(DumpExportReference* data)
|
||||
{
|
||||
HDINFO("[%s] will populate %" B_PRId32 " rating stabilities",
|
||||
Name(), data->CountUserRatingStabilities());
|
||||
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));
|
||||
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);
|
||||
}
|
||||
fModel->SetRatingStabilities(assembledRatingStabilities);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -218,8 +191,7 @@ ServerReferenceDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const
|
||||
|
||||
|
||||
void
|
||||
ServerReferenceDataUpdateProcess::GetStandardMetaDataJsonPath(
|
||||
BString& jsonPath) const
|
||||
ServerReferenceDataUpdateProcess::GetStandardMetaDataJsonPath(BString& jsonPath) const
|
||||
{
|
||||
jsonPath.SetTo("$.info");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2017-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "ServerRepositoryDataUpdateProcess.h"
|
||||
@@ -17,10 +17,10 @@
|
||||
#include "DumpExportRepository.h"
|
||||
#include "DumpExportRepositoryJsonListener.h"
|
||||
#include "DumpExportRepositorySource.h"
|
||||
#include "Logger.h"
|
||||
#include "PackageInfo.h"
|
||||
#include "ServerSettings.h"
|
||||
#include "StorageUtils.h"
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
@@ -28,13 +28,12 @@
|
||||
|
||||
|
||||
/*! This repository listener (not at the JSON level) is feeding in the
|
||||
repositories as they are parsed and processing them. Processing
|
||||
includes finding the matching depot record and coupling the data
|
||||
from the server with the data about the depot.
|
||||
repositories as they are parsed and processing them. Processing
|
||||
includes finding the matching depot record and coupling the data
|
||||
from the server with the data about the depot.
|
||||
*/
|
||||
|
||||
class DepotMatchingRepositoryListener :
|
||||
public DumpExportRepositoryListener {
|
||||
class DepotMatchingRepositoryListener : public DumpExportRepositoryListener {
|
||||
public:
|
||||
DepotMatchingRepositoryListener(Model* model,
|
||||
Stoppable* stoppable);
|
||||
@@ -60,14 +59,16 @@ private:
|
||||
private:
|
||||
Model* fModel;
|
||||
Stoppable* fStoppable;
|
||||
std::vector<DepotInfoRef>
|
||||
fDepots;
|
||||
};
|
||||
|
||||
|
||||
DepotMatchingRepositoryListener::DepotMatchingRepositoryListener(
|
||||
Model* model, Stoppable* stoppable)
|
||||
DepotMatchingRepositoryListener::DepotMatchingRepositoryListener(Model* model, Stoppable* stoppable)
|
||||
:
|
||||
fModel(model),
|
||||
fStoppable(stoppable)
|
||||
fStoppable(stoppable),
|
||||
fDepots()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -79,43 +80,41 @@ DepotMatchingRepositoryListener::~DepotMatchingRepositoryListener()
|
||||
|
||||
void
|
||||
DepotMatchingRepositoryListener::_SetupRepositoryData(DepotInfoRef& depot,
|
||||
DumpExportRepository* repository,
|
||||
DumpExportRepositorySource* repositorySource)
|
||||
DumpExportRepository* repository, DumpExportRepositorySource* repositorySource)
|
||||
{
|
||||
BString* repositoryCode = repository->Code();
|
||||
BString* repositorySourceCode = repositorySource->Code();
|
||||
|
||||
depot->SetWebAppRepositoryCode(*repositoryCode);
|
||||
depot->SetWebAppRepositorySourceCode(*repositorySourceCode);
|
||||
DepotInfoBuilder depotBuilder(depot);
|
||||
|
||||
depotBuilder.WithWebAppRepositoryCode(*repositoryCode);
|
||||
depotBuilder.WithWebAppRepositorySourceCode(*repositorySourceCode);
|
||||
|
||||
DepotInfoRef depotInfo = depotBuilder.BuildRef();
|
||||
fDepots.push_back(depotInfo);
|
||||
|
||||
if (Logger::IsDebugEnabled()) {
|
||||
HDDEBUG("[DepotMatchingRepositoryListener] associated depot [%s] (%s) "
|
||||
"with server repository source [%s] (%s)",
|
||||
depot->Name().String(),
|
||||
depot->Identifier().String(),
|
||||
repositorySourceCode->String(),
|
||||
"with server repository source [%s] (%s)",
|
||||
depot->Name().String(), depot->Identifier().String(), repositorySourceCode->String(),
|
||||
repositorySource->Identifier()->String());
|
||||
} else {
|
||||
HDINFO("[DepotMatchingRepositoryListener] associated depot [%s] with "
|
||||
"server repository source [%s]",
|
||||
depot->Name().String(),
|
||||
repositorySourceCode->String());
|
||||
"server repository source [%s]",
|
||||
depot->Name().String(), repositorySourceCode->String());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DepotMatchingRepositoryListener::Handle(const BString& identifier,
|
||||
DumpExportRepository* repository,
|
||||
DepotMatchingRepositoryListener::Handle(const BString& identifier, DumpExportRepository* repository,
|
||||
DumpExportRepositorySource* repositorySource)
|
||||
{
|
||||
if (!identifier.IsEmpty()) {
|
||||
AutoLocker<BLocker> locker(fModel->Lock());
|
||||
for (int32 i = 0; i < fModel->CountDepots(); i++) {
|
||||
DepotInfoRef depot = fModel->DepotAtIndex(i);
|
||||
if (identifier == depot->Identifier())
|
||||
_SetupRepositoryData(depot, repository, repositorySource);
|
||||
}
|
||||
DepotInfoRef depotForIdentifier = fModel->DepotForIdentifier(identifier);
|
||||
|
||||
if (depotForIdentifier.IsSet())
|
||||
_SetupRepositoryData(depotForIdentifier, repository, repositorySource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,13 +129,8 @@ DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository,
|
||||
// there may be additional identifiers for the remote repository and
|
||||
// these should also be taken into consideration.
|
||||
|
||||
for(int32 i = 0;
|
||||
i < repositorySource->CountExtraIdentifiers();
|
||||
i++)
|
||||
{
|
||||
Handle(*(repositorySource->ExtraIdentifiersItemAt(i)), repository,
|
||||
repositorySource);
|
||||
}
|
||||
for (int32 i = 0; i < repositorySource->CountExtraIdentifiers(); i++)
|
||||
Handle(*(repositorySource->ExtraIdentifiersItemAt(i)), repository, repositorySource);
|
||||
}
|
||||
|
||||
|
||||
@@ -153,11 +147,11 @@ DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository)
|
||||
void
|
||||
DepotMatchingRepositoryListener::Complete()
|
||||
{
|
||||
fModel->SetDepots(fDepots);
|
||||
}
|
||||
|
||||
|
||||
ServerRepositoryDataUpdateProcess::ServerRepositoryDataUpdateProcess(
|
||||
Model* model,
|
||||
ServerRepositoryDataUpdateProcess::ServerRepositoryDataUpdateProcess(Model* model,
|
||||
uint32 serverProcessOptions)
|
||||
:
|
||||
AbstractSingleFileServerProcess(serverProcessOptions),
|
||||
@@ -189,7 +183,6 @@ BString
|
||||
ServerRepositoryDataUpdateProcess::UrlPathComponent()
|
||||
{
|
||||
BString result;
|
||||
AutoLocker<BLocker> locker(fModel->Lock());
|
||||
result.SetToFormat("/__repository/all-%s.json.gz", fModel->PreferredLanguage()->ID());
|
||||
return result;
|
||||
}
|
||||
@@ -198,7 +191,6 @@ ServerRepositoryDataUpdateProcess::UrlPathComponent()
|
||||
status_t
|
||||
ServerRepositoryDataUpdateProcess::GetLocalPath(BPath& path) const
|
||||
{
|
||||
AutoLocker<BLocker> locker(fModel->Lock());
|
||||
return StorageUtils::DumpExportRepositoryDataPath(path, fModel->PreferredLanguage());
|
||||
}
|
||||
|
||||
@@ -206,15 +198,13 @@ ServerRepositoryDataUpdateProcess::GetLocalPath(BPath& path) const
|
||||
status_t
|
||||
ServerRepositoryDataUpdateProcess::ProcessLocalData()
|
||||
{
|
||||
DepotMatchingRepositoryListener* itemListener =
|
||||
new DepotMatchingRepositoryListener(fModel, this);
|
||||
ObjectDeleter<DepotMatchingRepositoryListener>
|
||||
itemListenerDeleter(itemListener);
|
||||
DepotMatchingRepositoryListener* itemListener
|
||||
= new DepotMatchingRepositoryListener(fModel, this);
|
||||
ObjectDeleter<DepotMatchingRepositoryListener> itemListenerDeleter(itemListener);
|
||||
|
||||
BulkContainerDumpExportRepositoryJsonListener* listener =
|
||||
new BulkContainerDumpExportRepositoryJsonListener(itemListener);
|
||||
ObjectDeleter<BulkContainerDumpExportRepositoryJsonListener>
|
||||
listenerDeleter(listener);
|
||||
BulkContainerDumpExportRepositoryJsonListener* listener
|
||||
= new BulkContainerDumpExportRepositoryJsonListener(itemListener);
|
||||
ObjectDeleter<BulkContainerDumpExportRepositoryJsonListener> listenerDeleter(listener);
|
||||
|
||||
BPath localPath;
|
||||
status_t result = GetLocalPath(localPath);
|
||||
@@ -239,8 +229,7 @@ ServerRepositoryDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const
|
||||
|
||||
|
||||
void
|
||||
ServerRepositoryDataUpdateProcess::GetStandardMetaDataJsonPath(
|
||||
BString& jsonPath) const
|
||||
ServerRepositoryDataUpdateProcess::GetStandardMetaDataJsonPath(BString& jsonPath) const
|
||||
{
|
||||
jsonPath.SetTo("$.info");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2020-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -63,7 +63,7 @@ UserDetailVerifierProcess::RunInternal()
|
||||
case B_OK:
|
||||
if (!userDetail.Agreement().IsLatest()) {
|
||||
HDINFO("the user has not agreed to the latest user usage"
|
||||
" conditions.");
|
||||
" conditions.");
|
||||
fListener->UserUsageConditionsNotLatest(userDetail);
|
||||
}
|
||||
break;
|
||||
@@ -84,12 +84,9 @@ UserDetailVerifierProcess::_ShouldVerify()
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
AutoLocker<BLocker> locker(fModel->Lock());
|
||||
if (fModel->Nickname().IsEmpty()) {
|
||||
HDINFO("no nickname --> will not verify user");
|
||||
return false;
|
||||
}
|
||||
if (fModel->Nickname().IsEmpty()) {
|
||||
HDINFO("no nickname --> will not verify user");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -99,16 +96,14 @@ UserDetailVerifierProcess::_ShouldVerify()
|
||||
status_t
|
||||
UserDetailVerifierProcess::_TryFetchUserDetail(UserDetail& userDetail)
|
||||
{
|
||||
WebAppInterface* interface = fModel->GetWebAppInterface();
|
||||
WebAppInterfaceRef interface = fModel->WebApp();
|
||||
BMessage userDetailResponse;
|
||||
status_t result;
|
||||
|
||||
result = interface->RetrieveCurrentUserDetail(userDetailResponse);
|
||||
|
||||
if (result != B_OK) {
|
||||
HDERROR("a problem has arisen retrieving the current user detail: %s",
|
||||
strerror(result));
|
||||
}
|
||||
if (result != B_OK)
|
||||
HDERROR("a problem has arisen retrieving the current user detail: %s", strerror(result));
|
||||
|
||||
if (result == B_OK) {
|
||||
int32 errorCode = WebAppInterface::ErrorCodeFromResponse(userDetailResponse);
|
||||
@@ -120,7 +115,7 @@ UserDetailVerifierProcess::_TryFetchUserDetail(UserDetail& userDetail)
|
||||
break;
|
||||
default:
|
||||
HDERROR("a problem has arisen retrieving the current user "
|
||||
"detail for user [%s]: jrpc error code %" B_PRId32 "",
|
||||
"detail for user [%s]: jrpc error code %" B_PRId32 "",
|
||||
fModel->Nickname().String(), errorCode);
|
||||
result = B_ERROR;
|
||||
break;
|
||||
@@ -139,4 +134,4 @@ UserDetailVerifierProcess::_TryFetchUserDetail(UserDetail& userDetail)
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* Copyright 2016-2024, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "WebAppInterface.h"
|
||||
@@ -14,8 +14,8 @@
|
||||
#include <HttpHeaders.h>
|
||||
#include <HttpRequest.h>
|
||||
#include <Json.h>
|
||||
#include <JsonTextWriter.h>
|
||||
#include <JsonMessageWriter.h>
|
||||
#include <JsonTextWriter.h>
|
||||
#include <UrlContext.h>
|
||||
#include <UrlProtocolListener.h>
|
||||
#include <UrlProtocolRoster.h>
|
||||
@@ -89,12 +89,10 @@ public:
|
||||
|
||||
|
||||
static BHttpRequest*
|
||||
make_http_request(const BUrl& url, BDataIO* output,
|
||||
BUrlProtocolListener* listener = NULL,
|
||||
make_http_request(const BUrl& url, BDataIO* output, BUrlProtocolListener* listener = NULL,
|
||||
BUrlContext* context = NULL)
|
||||
{
|
||||
BUrlRequest* request = BUrlProtocolRoster::MakeRequest(url, output,
|
||||
listener, context);
|
||||
BUrlRequest* request = BUrlProtocolRoster::MakeRequest(url, output, listener, context);
|
||||
BHttpRequest* httpRequest = dynamic_cast<BHttpRequest*>(request);
|
||||
if (httpRequest == NULL) {
|
||||
delete request;
|
||||
@@ -109,8 +107,9 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
WebAppInterface::WebAppInterface()
|
||||
WebAppInterface::WebAppInterface(const UserCredentials& value)
|
||||
{
|
||||
_SetCredentials(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -120,9 +119,8 @@ WebAppInterface::~WebAppInterface()
|
||||
|
||||
|
||||
void
|
||||
WebAppInterface::SetCredentials(const UserCredentials& value)
|
||||
WebAppInterface::_SetCredentials(const UserCredentials& value)
|
||||
{
|
||||
AutoLocker<BLocker> lock(&fLock);
|
||||
if (fCredentials != value) {
|
||||
fCredentials = value;
|
||||
fAccessToken.Clear();
|
||||
@@ -133,7 +131,6 @@ WebAppInterface::SetCredentials(const UserCredentials& value)
|
||||
const BString&
|
||||
WebAppInterface::Nickname()
|
||||
{
|
||||
AutoLocker<BLocker> lock(&fLock);
|
||||
return fCredentials.Nickname();
|
||||
}
|
||||
|
||||
@@ -212,21 +209,18 @@ WebAppInterface::RetrieveUserRatingsForPackageForDisplay(
|
||||
|
||||
requestEnvelopeWriter.WriteObjectEnd();
|
||||
|
||||
return _SendJsonRequest("user-rating/search-user-ratings",
|
||||
requestEnvelopeData, _LengthAndSeekToZero(requestEnvelopeData),
|
||||
0, message);
|
||||
return _SendJsonRequest("user-rating/search-user-ratings", requestEnvelopeData,
|
||||
_LengthAndSeekToZero(requestEnvelopeData), 0, message);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WebAppInterface::RetrieveUserRatingForPackageAndVersionByUser(
|
||||
const BString& packageName, const BPackageVersion& version,
|
||||
const BString& architecture,
|
||||
const BString& webAppRepositoryCode,
|
||||
const BString& webAppRepositorySourceCode,
|
||||
WebAppInterface::RetrieveUserRatingForPackageAndVersionByUser(const BString& packageName,
|
||||
const BPackageVersion& version, const BString& architecture,
|
||||
const BString& webAppRepositoryCode, const BString& webAppRepositorySourceCode,
|
||||
const BString& userNickname, BMessage& message)
|
||||
{
|
||||
// BHttpRequest later takes ownership of this.
|
||||
// BHttpRequest later takes ownership of this.
|
||||
BMallocIO* requestEnvelopeData = new BMallocIO();
|
||||
BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData);
|
||||
|
||||
@@ -270,10 +264,8 @@ WebAppInterface::RetrieveUserRatingForPackageAndVersionByUser(
|
||||
|
||||
requestEnvelopeWriter.WriteObjectEnd();
|
||||
|
||||
return _SendJsonRequest(
|
||||
"user-rating/get-user-rating-by-user-and-pkg-version",
|
||||
requestEnvelopeData,
|
||||
_LengthAndSeekToZero(requestEnvelopeData), NEEDS_AUTHORIZATION,
|
||||
return _SendJsonRequest("user-rating/get-user-rating-by-user-and-pkg-version",
|
||||
requestEnvelopeData, _LengthAndSeekToZero(requestEnvelopeData), NEEDS_AUTHORIZATION,
|
||||
message);
|
||||
}
|
||||
|
||||
@@ -285,12 +277,12 @@ WebAppInterface::RetrieveUserRatingForPackageAndVersionByUser(
|
||||
*/
|
||||
|
||||
status_t
|
||||
WebAppInterface::RetrieveUserDetailForCredentials(
|
||||
const UserCredentials& credentials, BMessage& message)
|
||||
WebAppInterface::RetrieveUserDetailForCredentials(const UserCredentials& credentials,
|
||||
BMessage& message)
|
||||
{
|
||||
if (!credentials.IsValid()) {
|
||||
debugger("the credentials supplied are invalid so it is not possible "
|
||||
"to obtain the user detail");
|
||||
"to obtain the user detail");
|
||||
}
|
||||
|
||||
status_t result = B_OK;
|
||||
@@ -301,9 +293,7 @@ WebAppInterface::RetrieveUserDetailForCredentials(
|
||||
BMessage authenticateResponseEnvelopeMessage;
|
||||
|
||||
if (result == B_OK) {
|
||||
result = AuthenticateUser(
|
||||
credentials.Nickname(),
|
||||
credentials.PasswordClear(),
|
||||
result = AuthenticateUser(credentials.Nickname(), credentials.PasswordClear(),
|
||||
authenticateResponseEnvelopeMessage);
|
||||
}
|
||||
|
||||
@@ -313,7 +303,7 @@ WebAppInterface::RetrieveUserDetailForCredentials(
|
||||
result = UnpackAccessToken(authenticateResponseEnvelopeMessage, accessToken);
|
||||
|
||||
if (result == B_OK) {
|
||||
// BHttpRequest later takes ownership of this.
|
||||
// BHttpRequest later takes ownership of this.
|
||||
BMallocIO* requestEnvelopeData = new BMallocIO();
|
||||
BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData);
|
||||
|
||||
@@ -322,9 +312,8 @@ WebAppInterface::RetrieveUserDetailForCredentials(
|
||||
requestEnvelopeWriter.WriteString(credentials.Nickname().String());
|
||||
requestEnvelopeWriter.WriteObjectEnd();
|
||||
|
||||
result = _SendJsonRequest("user/get-user", accessToken,
|
||||
requestEnvelopeData, _LengthAndSeekToZero(requestEnvelopeData),
|
||||
NEEDS_AUTHORIZATION, message);
|
||||
result = _SendJsonRequest("user/get-user", accessToken, requestEnvelopeData,
|
||||
_LengthAndSeekToZero(requestEnvelopeData), NEEDS_AUTHORIZATION, message);
|
||||
// note that the credentials used here are passed in as args.
|
||||
}
|
||||
|
||||
@@ -350,12 +339,10 @@ WebAppInterface::RetrieveCurrentUserDetail(BMessage& message)
|
||||
*/
|
||||
|
||||
/*static*/ status_t
|
||||
WebAppInterface::UnpackUserDetail(BMessage& responseEnvelopeMessage,
|
||||
UserDetail& userDetail)
|
||||
WebAppInterface::UnpackUserDetail(BMessage& responseEnvelopeMessage, UserDetail& userDetail)
|
||||
{
|
||||
BMessage resultMessage;
|
||||
status_t result = responseEnvelopeMessage.FindMessage(
|
||||
"result", &resultMessage);
|
||||
status_t result = responseEnvelopeMessage.FindMessage("result", &resultMessage);
|
||||
|
||||
if (result != B_OK) {
|
||||
HDERROR("bad response envelope missing 'result' entry");
|
||||
@@ -367,29 +354,24 @@ WebAppInterface::UnpackUserDetail(BMessage& responseEnvelopeMessage,
|
||||
userDetail.SetNickname(nickname);
|
||||
|
||||
BMessage agreementMessage;
|
||||
if (resultMessage.FindMessage("userUsageConditionsAgreement",
|
||||
&agreementMessage) == B_OK) {
|
||||
if (resultMessage.FindMessage("userUsageConditionsAgreement", &agreementMessage) == B_OK) {
|
||||
BString code;
|
||||
BDateTime agreedToTimestamp;
|
||||
BString userUsageConditionsCode;
|
||||
UserUsageConditionsAgreement agreement = userDetail.Agreement();
|
||||
bool isLatest;
|
||||
|
||||
if (agreementMessage.FindString("userUsageConditionsCode",
|
||||
&userUsageConditionsCode) == B_OK) {
|
||||
if (agreementMessage.FindString("userUsageConditionsCode", &userUsageConditionsCode)
|
||||
== B_OK) {
|
||||
agreement.SetCode(userUsageConditionsCode);
|
||||
}
|
||||
|
||||
double timestampAgreedMillis;
|
||||
if (agreementMessage.FindDouble("timestampAgreed",
|
||||
×tampAgreedMillis) == B_OK) {
|
||||
agreement.SetTimestampAgreed((uint64) timestampAgreedMillis);
|
||||
}
|
||||
if (agreementMessage.FindDouble("timestampAgreed", ×tampAgreedMillis) == B_OK)
|
||||
agreement.SetTimestampAgreed((uint64)timestampAgreedMillis);
|
||||
|
||||
if (agreementMessage.FindBool("isLatest", &isLatest)
|
||||
== B_OK) {
|
||||
if (agreementMessage.FindBool("isLatest", &isLatest) == B_OK)
|
||||
agreement.SetIsLatest(isLatest);
|
||||
}
|
||||
|
||||
userDetail.SetAgreement(agreement);
|
||||
}
|
||||
@@ -399,20 +381,18 @@ WebAppInterface::UnpackUserDetail(BMessage& responseEnvelopeMessage,
|
||||
|
||||
|
||||
/*! When an authentication API call is made, the response (if successful) will
|
||||
return an access token in the response. This method will take the response
|
||||
from the server and will parse out the access token data into the supplied
|
||||
object.
|
||||
return an access token in the response. This method will take the response
|
||||
from the server and will parse out the access token data into the supplied
|
||||
object.
|
||||
*/
|
||||
|
||||
/*static*/ status_t
|
||||
WebAppInterface::UnpackAccessToken(BMessage& responseEnvelopeMessage,
|
||||
AccessToken& accessToken)
|
||||
WebAppInterface::UnpackAccessToken(BMessage& responseEnvelopeMessage, AccessToken& accessToken)
|
||||
{
|
||||
status_t result;
|
||||
|
||||
BMessage resultMessage;
|
||||
result = responseEnvelopeMessage.FindMessage(
|
||||
"result", &resultMessage);
|
||||
result = responseEnvelopeMessage.FindMessage("result", &resultMessage);
|
||||
|
||||
if (result != B_OK) {
|
||||
HDERROR("bad response envelope missing 'result' entry");
|
||||
@@ -469,12 +449,10 @@ WebAppInterface::UnpackAccessToken(BMessage& responseEnvelopeMessage,
|
||||
*/
|
||||
|
||||
status_t
|
||||
WebAppInterface::RetrieveUserUsageConditions(const BString& code,
|
||||
UserUsageConditions& conditions)
|
||||
WebAppInterface::RetrieveUserUsageConditions(const BString& code, UserUsageConditions& conditions)
|
||||
{
|
||||
BMessage responseEnvelopeMessage;
|
||||
status_t result = _RetrieveUserUsageConditionsMeta(code,
|
||||
responseEnvelopeMessage);
|
||||
status_t result = _RetrieveUserUsageConditionsMeta(code, responseEnvelopeMessage);
|
||||
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
@@ -489,11 +467,10 @@ WebAppInterface::RetrieveUserUsageConditions(const BString& code,
|
||||
double metaDataMinimumAge;
|
||||
BString copyMarkdown;
|
||||
|
||||
if ( (resultMessage.FindString("code", &metaDataCode) != B_OK)
|
||||
|| (resultMessage.FindDouble(
|
||||
"minimumAge", &metaDataMinimumAge) != B_OK) ) {
|
||||
if ((resultMessage.FindString("code", &metaDataCode) != B_OK)
|
||||
|| (resultMessage.FindDouble("minimumAge", &metaDataMinimumAge) != B_OK)) {
|
||||
HDERROR("unexpected response from server with missing user usage "
|
||||
"conditions data");
|
||||
"conditions data");
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
@@ -505,17 +482,15 @@ WebAppInterface::RetrieveUserUsageConditions(const BString& code,
|
||||
|
||||
conditions.SetCode(metaDataCode);
|
||||
conditions.SetMinimumAge(metaDataMinimumAge);
|
||||
conditions.SetCopyMarkdown(
|
||||
BString(static_cast<const char*>(copyMarkdownData->Buffer()),
|
||||
copyMarkdownData->BufferLength()));
|
||||
conditions.SetCopyMarkdown(BString(static_cast<const char*>(copyMarkdownData->Buffer()),
|
||||
copyMarkdownData->BufferLength()));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WebAppInterface::AgreeUserUsageConditions(const BString& code,
|
||||
BMessage& responsePayload)
|
||||
WebAppInterface::AgreeUserUsageConditions(const BString& code, BMessage& responsePayload)
|
||||
{
|
||||
BMallocIO* requestEnvelopeData = new BMallocIO();
|
||||
BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData);
|
||||
@@ -529,15 +504,13 @@ WebAppInterface::AgreeUserUsageConditions(const BString& code,
|
||||
|
||||
// now fetch this information into an object.
|
||||
|
||||
return _SendJsonRequest("user/agree-user-usage-conditions",
|
||||
requestEnvelopeData, _LengthAndSeekToZero(requestEnvelopeData),
|
||||
NEEDS_AUTHORIZATION, responsePayload);
|
||||
return _SendJsonRequest("user/agree-user-usage-conditions", requestEnvelopeData,
|
||||
_LengthAndSeekToZero(requestEnvelopeData), NEEDS_AUTHORIZATION, responsePayload);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WebAppInterface::_RetrieveUserUsageConditionsMeta(const BString& code,
|
||||
BMessage& message)
|
||||
WebAppInterface::_RetrieveUserUsageConditionsMeta(const BString& code, BMessage& message)
|
||||
{
|
||||
BMallocIO* requestEnvelopeData = new BMallocIO();
|
||||
BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData);
|
||||
@@ -553,33 +526,26 @@ WebAppInterface::_RetrieveUserUsageConditionsMeta(const BString& code,
|
||||
|
||||
// now fetch this information into an object.
|
||||
|
||||
return _SendJsonRequest("user/get-user-usage-conditions",
|
||||
requestEnvelopeData, _LengthAndSeekToZero(requestEnvelopeData),
|
||||
0, message);
|
||||
return _SendJsonRequest("user/get-user-usage-conditions", requestEnvelopeData,
|
||||
_LengthAndSeekToZero(requestEnvelopeData), 0, message);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WebAppInterface::_RetrieveUserUsageConditionsCopy(const BString& code,
|
||||
BDataIO* stream)
|
||||
WebAppInterface::_RetrieveUserUsageConditionsCopy(const BString& code, BDataIO* stream)
|
||||
{
|
||||
return _SendRawGetRequest(
|
||||
BString("/__user/usageconditions/") << code << "/document.md",
|
||||
return _SendRawGetRequest(BString("/__user/usageconditions/") << code << "/document.md",
|
||||
stream);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WebAppInterface::CreateUserRating(const BString& packageName,
|
||||
const BPackageVersion& version,
|
||||
const BString& architecture,
|
||||
const BString& webAppRepositoryCode,
|
||||
const BString& webAppRepositorySourceCode,
|
||||
const BString& naturalLanguageCode,
|
||||
// This is the "ID" in the ICU system; the term `code` is used with the
|
||||
// server system.
|
||||
const BString& comment,
|
||||
const BString& stability, int rating, BMessage& message)
|
||||
WebAppInterface::CreateUserRating(const BString& packageName, const BPackageVersion& version,
|
||||
const BString& architecture, const BString& webAppRepositoryCode,
|
||||
const BString& webAppRepositorySourceCode, const BString& naturalLanguageCode,
|
||||
// This is the "ID" in the ICU system; the term `code` is used with the
|
||||
// server system.
|
||||
const BString& comment, const BString& stability, int rating, BMessage& message)
|
||||
{
|
||||
BMallocIO* requestEnvelopeData = new BMallocIO();
|
||||
// BHttpRequest later takes ownership of this.
|
||||
@@ -628,7 +594,7 @@ WebAppInterface::CreateUserRating(const BString& packageName,
|
||||
|
||||
if (rating > 0.0f) {
|
||||
requestEnvelopeWriter.WriteObjectName("rating");
|
||||
requestEnvelopeWriter.WriteInteger(rating);
|
||||
requestEnvelopeWriter.WriteInteger(rating);
|
||||
}
|
||||
|
||||
if (stability.Length() > 0) {
|
||||
@@ -643,19 +609,16 @@ WebAppInterface::CreateUserRating(const BString& packageName,
|
||||
|
||||
requestEnvelopeWriter.WriteObjectEnd();
|
||||
|
||||
return _SendJsonRequest("user-rating/create-user-rating",
|
||||
requestEnvelopeData, _LengthAndSeekToZero(requestEnvelopeData),
|
||||
NEEDS_AUTHORIZATION, message);
|
||||
return _SendJsonRequest("user-rating/create-user-rating", requestEnvelopeData,
|
||||
_LengthAndSeekToZero(requestEnvelopeData), NEEDS_AUTHORIZATION, message);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WebAppInterface::UpdateUserRating(const BString& ratingID,
|
||||
const BString& naturalLanguageCode,
|
||||
// This is the "ID" in the ICU system; the term `code` is used with the
|
||||
// server system.
|
||||
const BString& comment,
|
||||
const BString& stability, int rating, bool active, BMessage& message)
|
||||
WebAppInterface::UpdateUserRating(const BString& ratingID, const BString& naturalLanguageCode,
|
||||
// This is the "ID" in the ICU system; the term `code` is used with the
|
||||
// server system.
|
||||
const BString& comment, const BString& stability, int rating, bool active, BMessage& message)
|
||||
{
|
||||
BMallocIO* requestEnvelopeData = new BMallocIO();
|
||||
// BHttpRequest later takes ownership of this.
|
||||
@@ -696,23 +659,21 @@ WebAppInterface::UpdateUserRating(const BString& ratingID,
|
||||
|
||||
requestEnvelopeWriter.WriteObjectEnd();
|
||||
|
||||
return _SendJsonRequest("user-rating/update-user-rating",
|
||||
requestEnvelopeData, _LengthAndSeekToZero(requestEnvelopeData),
|
||||
NEEDS_AUTHORIZATION, message);
|
||||
return _SendJsonRequest("user-rating/update-user-rating", requestEnvelopeData,
|
||||
_LengthAndSeekToZero(requestEnvelopeData), NEEDS_AUTHORIZATION, message);
|
||||
}
|
||||
|
||||
|
||||
/*! This method will call to the server to get a screenshot that will fit into
|
||||
the specified width and height.
|
||||
the specified width and height.
|
||||
*/
|
||||
|
||||
status_t
|
||||
WebAppInterface::RetrieveScreenshot(const BString& code,
|
||||
int32 width, int32 height, BDataIO* stream)
|
||||
WebAppInterface::RetrieveScreenshot(const BString& code, int32 width, int32 height, BDataIO* stream)
|
||||
{
|
||||
return _SendRawGetRequest(
|
||||
BString("/__pkgscreenshot/") << code << ".png" << "?tw="
|
||||
<< width << "&th=" << height, stream);
|
||||
return _SendRawGetRequest(BString("/__pkgscreenshot/")
|
||||
<< code << ".png" << "?tw=" << width << "&th=" << height,
|
||||
stream);
|
||||
}
|
||||
|
||||
|
||||
@@ -726,25 +687,20 @@ WebAppInterface::RequestCaptcha(BMessage& message)
|
||||
requestEnvelopeWriter.WriteObjectStart();
|
||||
requestEnvelopeWriter.WriteObjectEnd();
|
||||
|
||||
return _SendJsonRequest("captcha/generate-captcha",
|
||||
requestEnvelopeData, _LengthAndSeekToZero(requestEnvelopeData),
|
||||
0, message);
|
||||
return _SendJsonRequest("captcha/generate-captcha", requestEnvelopeData,
|
||||
_LengthAndSeekToZero(requestEnvelopeData), 0, message);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WebAppInterface::CreateUser(const BString& nickName,
|
||||
const BString& passwordClear,
|
||||
const BString& email,
|
||||
const BString& captchaToken,
|
||||
const BString& captchaResponse,
|
||||
WebAppInterface::CreateUser(const BString& nickName, const BString& passwordClear,
|
||||
const BString& email, const BString& captchaToken, const BString& captchaResponse,
|
||||
const BString& naturalLanguageCode,
|
||||
// This is the "ID" in the ICU system; the term `code` is used with the
|
||||
// server system.
|
||||
const BString& userUsageConditionsCode,
|
||||
BMessage& message)
|
||||
// This is the "ID" in the ICU system; the term `code` is used with the
|
||||
// server system.
|
||||
const BString& userUsageConditionsCode, BMessage& message)
|
||||
{
|
||||
// BHttpRequest later takes ownership of this.
|
||||
// BHttpRequest later takes ownership of this.
|
||||
BMallocIO* requestEnvelopeData = new BMallocIO();
|
||||
BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData);
|
||||
|
||||
@@ -776,7 +732,7 @@ WebAppInterface::CreateUser(const BString& nickName,
|
||||
|
||||
|
||||
/*! This method will authenticate the user set in the credentials and will
|
||||
retain the resultant access token for authenticating any latter API calls.
|
||||
retain the resultant access token for authenticating any latter API calls.
|
||||
*/
|
||||
|
||||
status_t
|
||||
@@ -796,7 +752,8 @@ WebAppInterface::AuthenticateUserRetainingAccessToken()
|
||||
|
||||
status_t
|
||||
WebAppInterface::_AuthenticateUserRetainingAccessToken(const BString& nickName,
|
||||
const BString& passwordClear) {
|
||||
const BString& passwordClear)
|
||||
{
|
||||
AutoLocker<BLocker> lock(&fLock);
|
||||
|
||||
fAccessToken.Clear();
|
||||
@@ -817,8 +774,8 @@ WebAppInterface::_AuthenticateUserRetainingAccessToken(const BString& nickName,
|
||||
|
||||
|
||||
status_t
|
||||
WebAppInterface::AuthenticateUser(const BString& nickName,
|
||||
const BString& passwordClear, BMessage& message)
|
||||
WebAppInterface::AuthenticateUser(const BString& nickName, const BString& passwordClear,
|
||||
BMessage& message)
|
||||
{
|
||||
BMallocIO* requestEnvelopeData = new BMallocIO();
|
||||
// BHttpRequest later takes ownership of this.
|
||||
@@ -833,9 +790,8 @@ WebAppInterface::AuthenticateUser(const BString& nickName,
|
||||
|
||||
requestEnvelopeWriter.WriteObjectEnd();
|
||||
|
||||
return _SendJsonRequest("user/authenticate-user",
|
||||
requestEnvelopeData, _LengthAndSeekToZero(requestEnvelopeData),
|
||||
0, message);
|
||||
return _SendJsonRequest("user/authenticate-user", requestEnvelopeData,
|
||||
_LengthAndSeekToZero(requestEnvelopeData), 0, message);
|
||||
}
|
||||
|
||||
|
||||
@@ -893,19 +849,16 @@ WebAppInterface::IncrementViewCounter(const PackageInfoRef package, const DepotI
|
||||
|
||||
requestEnvelopeWriter.WriteObjectEnd();
|
||||
|
||||
return _SendJsonRequest("pkg/increment-view-counter",
|
||||
requestEnvelopeData, _LengthAndSeekToZero(requestEnvelopeData),
|
||||
0, message);
|
||||
return _SendJsonRequest("pkg/increment-view-counter", requestEnvelopeData,
|
||||
_LengthAndSeekToZero(requestEnvelopeData), 0, message);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WebAppInterface::RetrievePasswordRequirements(
|
||||
PasswordRequirements& passwordRequirements)
|
||||
WebAppInterface::RetrievePasswordRequirements(PasswordRequirements& passwordRequirements)
|
||||
{
|
||||
BMessage responseEnvelopeMessage;
|
||||
status_t result = _RetrievePasswordRequirementsMeta(
|
||||
responseEnvelopeMessage);
|
||||
status_t result = _RetrievePasswordRequirementsMeta(responseEnvelopeMessage);
|
||||
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
@@ -922,13 +875,13 @@ WebAppInterface::RetrievePasswordRequirements(
|
||||
double value;
|
||||
|
||||
if (resultMessage.FindDouble("minPasswordLength", &value) == B_OK)
|
||||
passwordRequirements.SetMinPasswordLength((uint32) value);
|
||||
passwordRequirements.SetMinPasswordLength((uint32)value);
|
||||
|
||||
if (resultMessage.FindDouble("minPasswordUppercaseChar", &value) == B_OK)
|
||||
passwordRequirements.SetMinPasswordUppercaseChar((uint32) value);
|
||||
passwordRequirements.SetMinPasswordUppercaseChar((uint32)value);
|
||||
|
||||
if (resultMessage.FindDouble("minPasswordDigitsChar", &value) == B_OK)
|
||||
passwordRequirements.SetMinPasswordDigitsChar((uint32) value);
|
||||
passwordRequirements.SetMinPasswordDigitsChar((uint32)value);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -944,9 +897,8 @@ WebAppInterface::_RetrievePasswordRequirementsMeta(BMessage& message)
|
||||
requestEnvelopeWriter.WriteObjectStart();
|
||||
requestEnvelopeWriter.WriteObjectEnd();
|
||||
|
||||
return _SendJsonRequest("user/get-password-requirements",
|
||||
requestEnvelopeData, _LengthAndSeekToZero(requestEnvelopeData),
|
||||
0, message);
|
||||
return _SendJsonRequest("user/get-password-requirements", requestEnvelopeData,
|
||||
_LengthAndSeekToZero(requestEnvelopeData), 0, message);
|
||||
}
|
||||
|
||||
|
||||
@@ -966,7 +918,7 @@ WebAppInterface::ErrorCodeFromResponse(BMessage& responseEnvelopeMessage)
|
||||
|
||||
if (responseEnvelopeMessage.FindMessage("error", &error) == B_OK
|
||||
&& error.FindDouble("code", &code) == B_OK) {
|
||||
return (int32) code;
|
||||
return (int32)code;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -977,9 +929,8 @@ WebAppInterface::ErrorCodeFromResponse(BMessage& responseEnvelopeMessage)
|
||||
|
||||
|
||||
status_t
|
||||
WebAppInterface::_SendJsonRequest(const char* urlPathComponents,
|
||||
BPositionIO* requestData, size_t requestDataSize, uint32 flags,
|
||||
BMessage& reply)
|
||||
WebAppInterface::_SendJsonRequest(const char* urlPathComponents, BPositionIO* requestData,
|
||||
size_t requestDataSize, uint32 flags, BMessage& reply)
|
||||
{
|
||||
bool needsAuthorization = (flags & NEEDS_AUTHORIZATION) != 0;
|
||||
AccessToken accessToken;
|
||||
@@ -987,15 +938,14 @@ WebAppInterface::_SendJsonRequest(const char* urlPathComponents,
|
||||
if (needsAuthorization)
|
||||
accessToken = _ObtainValidAccessToken();
|
||||
|
||||
return _SendJsonRequest(urlPathComponents, accessToken, requestData,
|
||||
requestDataSize, flags, reply);
|
||||
return _SendJsonRequest(urlPathComponents, accessToken, requestData, requestDataSize, flags,
|
||||
reply);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ status_t
|
||||
WebAppInterface::_SendJsonRequest(const char* urlPathComponents,
|
||||
const AccessToken& accessToken, BPositionIO* requestData,
|
||||
size_t requestDataSize, uint32 flags, BMessage& reply)
|
||||
WebAppInterface::_SendJsonRequest(const char* urlPathComponents, const AccessToken& accessToken,
|
||||
BPositionIO* requestData, size_t requestDataSize, uint32 flags, BMessage& reply)
|
||||
{
|
||||
if (requestDataSize == 0) {
|
||||
HDINFO("%s; empty request payload", PROTOCOL_NAME);
|
||||
@@ -1004,14 +954,15 @@ WebAppInterface::_SendJsonRequest(const char* urlPathComponents,
|
||||
|
||||
if (!ServerHelper::IsNetworkAvailable()) {
|
||||
HDDEBUG("%s; dropping request to ...[%s] as network is not"
|
||||
" available", PROTOCOL_NAME, urlPathComponents);
|
||||
" available",
|
||||
PROTOCOL_NAME, urlPathComponents);
|
||||
delete requestData;
|
||||
return HD_NETWORK_INACCESSIBLE;
|
||||
}
|
||||
|
||||
if (ServerSettings::IsClientTooOld()) {
|
||||
HDDEBUG("%s; dropping request to ...[%s] as client is too old",
|
||||
PROTOCOL_NAME, urlPathComponents);
|
||||
HDDEBUG("%s; dropping request to ...[%s] as client is too old", PROTOCOL_NAME,
|
||||
urlPathComponents);
|
||||
delete requestData;
|
||||
return HD_CLIENT_TOO_OLD;
|
||||
}
|
||||
@@ -1019,16 +970,14 @@ WebAppInterface::_SendJsonRequest(const char* urlPathComponents,
|
||||
bool needsAuthorization = (flags & NEEDS_AUTHORIZATION) != 0;
|
||||
|
||||
if (needsAuthorization && !accessToken.IsValid()) {
|
||||
HDDEBUG("%s; dropping request to ...[%s] as access token is not valid",
|
||||
PROTOCOL_NAME, urlPathComponents);
|
||||
HDDEBUG("%s; dropping request to ...[%s] as access token is not valid", PROTOCOL_NAME,
|
||||
urlPathComponents);
|
||||
delete requestData;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
BUrl url = ServerSettings::CreateFullUrl(BString("/__api/v2/")
|
||||
<< urlPathComponents);
|
||||
HDDEBUG("%s; will make request to [%s]", PROTOCOL_NAME,
|
||||
url.UrlString().String());
|
||||
BUrl url = ServerSettings::CreateFullUrl(BString("/__api/v2/") << urlPathComponents);
|
||||
HDDEBUG("%s; will make request to [%s]", PROTOCOL_NAME, url.UrlString().String());
|
||||
|
||||
// If the request payload is logged then it must be copied to local memory
|
||||
// from the stream. This then requires that the request data is then
|
||||
@@ -1071,13 +1020,12 @@ WebAppInterface::_SendJsonRequest(const char* urlPathComponents,
|
||||
thread_id thread = request->Run();
|
||||
wait_for_thread(thread, NULL);
|
||||
|
||||
const BHttpResult& result = dynamic_cast<const BHttpResult&>(
|
||||
request->Result());
|
||||
const BHttpResult& result = dynamic_cast<const BHttpResult&>(request->Result());
|
||||
|
||||
int32 statusCode = result.StatusCode();
|
||||
|
||||
HDDEBUG("%s; did receive http-status [%" B_PRId32 "] from [%s]",
|
||||
PROTOCOL_NAME, statusCode, url.UrlString().String());
|
||||
HDDEBUG("%s; did receive http-status [%" B_PRId32 "] from [%s]", PROTOCOL_NAME, statusCode,
|
||||
url.UrlString().String());
|
||||
|
||||
switch (statusCode) {
|
||||
case B_HTTP_STATUS_OK:
|
||||
@@ -1089,8 +1037,8 @@ WebAppInterface::_SendJsonRequest(const char* urlPathComponents,
|
||||
|
||||
default:
|
||||
HDERROR("%s; request to endpoint [.../%s] failed with http "
|
||||
"status [%" B_PRId32 "]\n", PROTOCOL_NAME, urlPathComponents,
|
||||
statusCode);
|
||||
"status [%" B_PRId32 "]\n",
|
||||
PROTOCOL_NAME, urlPathComponents, statusCode);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
@@ -1108,7 +1056,7 @@ WebAppInterface::_SendJsonRequest(const char* urlPathComponents,
|
||||
status_t status = jsonMessageWriter.ErrorStatus();
|
||||
|
||||
if (Logger::IsTraceEnabled() && status == B_BAD_DATA) {
|
||||
BString resultString(static_cast<const char *>(replyData.Buffer()),
|
||||
BString resultString(static_cast<const char*>(replyData.Buffer()),
|
||||
replyData.BufferLength());
|
||||
HDERROR("Parser choked on JSON:\n%s", resultString.String());
|
||||
}
|
||||
@@ -1117,33 +1065,29 @@ WebAppInterface::_SendJsonRequest(const char* urlPathComponents,
|
||||
|
||||
|
||||
status_t
|
||||
WebAppInterface::_SendJsonRequest(const char* urlPathComponents,
|
||||
const BString& jsonString, uint32 flags, BMessage& reply)
|
||||
WebAppInterface::_SendJsonRequest(const char* urlPathComponents, const BString& jsonString,
|
||||
uint32 flags, BMessage& reply)
|
||||
{
|
||||
// gets 'adopted' by the subsequent http request.
|
||||
BMemoryIO* data = new BMemoryIO(jsonString.String(),
|
||||
jsonString.Length() - 1);
|
||||
BMemoryIO* data = new BMemoryIO(jsonString.String(), jsonString.Length() - 1);
|
||||
|
||||
return _SendJsonRequest(urlPathComponents, data, jsonString.Length() - 1,
|
||||
flags, reply);
|
||||
return _SendJsonRequest(urlPathComponents, data, jsonString.Length() - 1, flags, reply);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WebAppInterface::_SendRawGetRequest(const BString urlPathComponents,
|
||||
BDataIO* stream)
|
||||
WebAppInterface::_SendRawGetRequest(const BString urlPathComponents, BDataIO* stream)
|
||||
{
|
||||
BUrl url = ServerSettings::CreateFullUrl(urlPathComponents);
|
||||
|
||||
HDDEBUG("http-get; will make request to [%s]",
|
||||
url.UrlString().String());
|
||||
HDDEBUG("http-get; will make request to [%s]", url.UrlString().String());
|
||||
|
||||
ProtocolListener listener;
|
||||
|
||||
BHttpHeaders headers;
|
||||
ServerSettings::AugmentHeaders(headers);
|
||||
|
||||
BHttpRequest *request = make_http_request(url, stream, &listener);
|
||||
BHttpRequest* request = make_http_request(url, stream, &listener);
|
||||
ObjectDeleter<BHttpRequest> _(request);
|
||||
if (request == NULL)
|
||||
return B_ERROR;
|
||||
@@ -1153,19 +1097,17 @@ WebAppInterface::_SendRawGetRequest(const BString urlPathComponents,
|
||||
thread_id thread = request->Run();
|
||||
wait_for_thread(thread, NULL);
|
||||
|
||||
const BHttpResult& result = dynamic_cast<const BHttpResult&>(
|
||||
request->Result());
|
||||
const BHttpResult& result = dynamic_cast<const BHttpResult&>(request->Result());
|
||||
|
||||
int32 statusCode = result.StatusCode();
|
||||
|
||||
HDDEBUG("http-get; did receive http-status [%" B_PRId32 "] from [%s]",
|
||||
statusCode, url.UrlString().String());
|
||||
HDDEBUG("http-get; did receive http-status [%" B_PRId32 "] from [%s]", statusCode,
|
||||
url.UrlString().String());
|
||||
|
||||
if (statusCode == 200)
|
||||
return B_OK;
|
||||
|
||||
HDERROR("failed to get data from '%s': %" B_PRIi32 "",
|
||||
url.UrlString().String(), statusCode);
|
||||
HDERROR("failed to get data from '%s': %" B_PRIi32 "", url.UrlString().String(), statusCode);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
@@ -1183,17 +1125,16 @@ WebAppInterface::_LogPayload(BPositionIO* requestData, size_t size)
|
||||
printf("%s; error logging payload", PROTOCOL_NAME);
|
||||
} else {
|
||||
for (uint32 i = 0; i < size; i++) {
|
||||
bool esc = buffer[i] > 126 ||
|
||||
(buffer[i] < 0x20 && buffer[i] != 0x0a);
|
||||
bool esc = buffer[i] > 126 || (buffer[i] < 0x20 && buffer[i] != 0x0a);
|
||||
|
||||
if (esc)
|
||||
printf("\\u%02x", buffer[i]);
|
||||
else
|
||||
putchar(buffer[i]);
|
||||
}
|
||||
if (esc)
|
||||
printf("\\u%02x", buffer[i]);
|
||||
else
|
||||
putchar(buffer[i]);
|
||||
}
|
||||
|
||||
if (size == LOG_PAYLOAD_LIMIT)
|
||||
printf("...(continues)");
|
||||
if (size == LOG_PAYLOAD_LIMIT)
|
||||
printf("...(continues)");
|
||||
}
|
||||
|
||||
requestData->Seek(requestDataOffset, SEEK_SET);
|
||||
@@ -1209,15 +1150,14 @@ off_t
|
||||
WebAppInterface::_LengthAndSeekToZero(BPositionIO* data)
|
||||
{
|
||||
off_t dataSize = data->Position();
|
||||
data->Seek(0, SEEK_SET);
|
||||
return dataSize;
|
||||
data->Seek(0, SEEK_SET);
|
||||
return dataSize;
|
||||
}
|
||||
|
||||
|
||||
UserCredentials
|
||||
WebAppInterface::_Credentials()
|
||||
{
|
||||
AutoLocker<BLocker> lock(&fLock);
|
||||
return fCredentials;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* Copyright 2016-2024, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2016-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef WEB_APP_INTERFACE_H
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <Application.h>
|
||||
#include <JsonWriter.h>
|
||||
#include <Locker.h>
|
||||
#include <Referenceable.h>
|
||||
#include <String.h>
|
||||
#include <package/PackageVersion.h>
|
||||
|
||||
@@ -43,12 +44,12 @@ using BPackageKit::BPackageVersion;
|
||||
#define RATING_NONE -1
|
||||
|
||||
|
||||
class WebAppInterface {
|
||||
class WebAppInterface : public BReferenceable
|
||||
{
|
||||
public:
|
||||
WebAppInterface();
|
||||
WebAppInterface(const UserCredentials& value);
|
||||
virtual ~WebAppInterface();
|
||||
|
||||
void SetCredentials(const UserCredentials& value);
|
||||
const BString& Nickname();
|
||||
|
||||
status_t GetChangelog(
|
||||
@@ -157,6 +158,7 @@ public:
|
||||
BMessage& responseEnvelopeMessage,
|
||||
AccessToken& accessToken);
|
||||
private:
|
||||
void _SetCredentials(const UserCredentials& value);
|
||||
UserCredentials _Credentials();
|
||||
|
||||
AccessToken _ObtainValidAccessToken();
|
||||
@@ -199,4 +201,7 @@ private:
|
||||
};
|
||||
|
||||
|
||||
typedef BReference<WebAppInterface> WebAppInterfaceRef;
|
||||
|
||||
|
||||
#endif // WEB_APP_INTERFACE_H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2020, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2017-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "TarArchiveService.h"
|
||||
@@ -30,7 +30,7 @@
|
||||
data for the parsed entry.
|
||||
*/
|
||||
|
||||
/*static*/ status_t
|
||||
/*static*/ status_t
|
||||
TarArchiveService::GetEntry(BPositionIO& tarIo, TarArchiveHeader& header)
|
||||
{
|
||||
uint8 buffer[LENGTH_BLOCK];
|
||||
@@ -46,7 +46,7 @@ TarArchiveService::GetEntry(BPositionIO& tarIo, TarArchiveHeader& header)
|
||||
useful for obtaining a catalog of items in the tar file for example.
|
||||
*/
|
||||
|
||||
/*status*/ status_t
|
||||
/*status*/ status_t
|
||||
TarArchiveService::ForEachEntry(BPositionIO& tarIo, TarEntryListener* listener)
|
||||
{
|
||||
uint8 buffer[LENGTH_BLOCK];
|
||||
@@ -58,21 +58,17 @@ TarArchiveService::ForEachEntry(BPositionIO& tarIo, TarEntryListener* listener)
|
||||
memset(zero_buffer, 0, sizeof zero_buffer);
|
||||
tarIo.Seek(offset, SEEK_SET);
|
||||
|
||||
while (result == B_OK
|
||||
&& B_OK == (result = tarIo.ReadExactly(
|
||||
buffer, LENGTH_BLOCK))) {
|
||||
while (result == B_OK && B_OK == (result = tarIo.ReadExactly(buffer, LENGTH_BLOCK))) {
|
||||
|
||||
if (memcmp(zero_buffer, buffer, sizeof zero_buffer) == 0) {
|
||||
HDDEBUG("detected end of tar-ball after %" B_PRIu32 " items",
|
||||
countItemsRead);
|
||||
HDTRACE("detected end of tar-ball after %" B_PRIu32 " items", countItemsRead);
|
||||
return B_OK; // end of tar-ball.
|
||||
}
|
||||
|
||||
TarArchiveHeader header;
|
||||
result = _ReadHeader(buffer, header);
|
||||
|
||||
HDTRACE("did read tar entry header for [%s]",
|
||||
header.FileName().String());
|
||||
HDTRACE("did read tar entry header for [%s]", header.FileName().String());
|
||||
|
||||
if (result == B_OK) {
|
||||
countItemsRead++;
|
||||
@@ -81,8 +77,7 @@ TarArchiveService::ForEachEntry(BPositionIO& tarIo, TarEntryListener* listener)
|
||||
// and/or just process the header information.
|
||||
|
||||
if (listener != NULL) {
|
||||
BDataIO *entryData = new ConstraintedDataIO(&tarIo,
|
||||
header.Length());
|
||||
BDataIO* entryData = new ConstraintedDataIO(&tarIo, header.Length());
|
||||
ObjectDeleter<BDataIO> entryDataDeleter(entryData);
|
||||
result = listener->Handle(header, offset, entryData);
|
||||
}
|
||||
@@ -105,7 +100,8 @@ TarArchiveService::ForEachEntry(BPositionIO& tarIo, TarEntryListener* listener)
|
||||
|
||||
|
||||
tar_file_type
|
||||
TarArchiveService::_ReadHeaderFileType(unsigned char data) {
|
||||
TarArchiveService::_ReadHeaderFileType(unsigned char data)
|
||||
{
|
||||
switch (data) {
|
||||
case 0:
|
||||
case '0':
|
||||
@@ -117,22 +113,20 @@ TarArchiveService::_ReadHeaderFileType(unsigned char data) {
|
||||
|
||||
|
||||
/*static*/ int32
|
||||
TarArchiveService::_ReadHeaderStringLength(const uint8* data,
|
||||
size_t maxStringLength)
|
||||
TarArchiveService::_ReadHeaderStringLength(const uint8* data, size_t maxStringLength)
|
||||
{
|
||||
int32 actualLength = 0;
|
||||
while (actualLength < (int32) maxStringLength && data[actualLength] != 0)
|
||||
size_t actualLength = 0;
|
||||
|
||||
while (actualLength < maxStringLength && data[actualLength] != 0)
|
||||
actualLength++;
|
||||
return actualLength;
|
||||
return static_cast<int32>(actualLength);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TarArchiveService::_ReadHeaderString(const uint8 *data, size_t maxStringLength,
|
||||
BString& result)
|
||||
TarArchiveService::_ReadHeaderString(const uint8* data, size_t maxStringLength, BString& result)
|
||||
{
|
||||
result.SetTo((const char *) data,
|
||||
_ReadHeaderStringLength(data, maxStringLength));
|
||||
result.SetTo((const char*)data, _ReadHeaderStringLength(data, maxStringLength));
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +134,8 @@ TarArchiveService::_ReadHeaderString(const uint8 *data, size_t maxStringLength,
|
||||
character in an number expressed in octal.
|
||||
*/
|
||||
|
||||
static bool tar_is_octal_digit(unsigned char c)
|
||||
static bool
|
||||
tar_is_octal_digit(unsigned char c)
|
||||
{
|
||||
switch (c) {
|
||||
case '0':
|
||||
@@ -159,7 +154,7 @@ static bool tar_is_octal_digit(unsigned char c)
|
||||
|
||||
|
||||
/*static*/ uint32
|
||||
TarArchiveService::_ReadHeaderNumeric(const uint8 *data, size_t dataLength)
|
||||
TarArchiveService::_ReadHeaderNumeric(const uint8* data, size_t dataLength)
|
||||
{
|
||||
uint32 actualLength = 0;
|
||||
|
||||
@@ -187,7 +182,7 @@ TarArchiveService::_CalculateBlockChecksum(const uint8* block)
|
||||
if (i >= OFFSET_CHECKSUM && i < OFFSET_CHECKSUM + LENGTH_CHECKSUM)
|
||||
result += 32;
|
||||
else
|
||||
result += (uint32) block[i];
|
||||
result += static_cast<uint32>(block[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -198,12 +193,10 @@ TarArchiveService::_CalculateBlockChecksum(const uint8* block)
|
||||
TarArchiveService::_ReadHeader(const uint8* block, TarArchiveHeader& header)
|
||||
{
|
||||
uint32 actualChecksum = _CalculateBlockChecksum(block);
|
||||
uint32 expectedChecksum = _ReadHeaderNumeric(&block[OFFSET_CHECKSUM],
|
||||
LENGTH_CHECKSUM);
|
||||
uint32 expectedChecksum = _ReadHeaderNumeric(&block[OFFSET_CHECKSUM], LENGTH_CHECKSUM);
|
||||
|
||||
if(actualChecksum != expectedChecksum) {
|
||||
HDERROR("tar archive header has bad checksum;"
|
||||
"expected %" B_PRIu32 " actual %" B_PRIu32,
|
||||
if (actualChecksum != expectedChecksum) {
|
||||
HDERROR("tar archive header has bad checksum; expected %" B_PRIu32 " actual %" B_PRIu32,
|
||||
expectedChecksum, actualChecksum);
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
@@ -212,10 +205,8 @@ TarArchiveService::_ReadHeader(const uint8* block, TarArchiveHeader& header)
|
||||
_ReadHeaderString(&block[OFFSET_FILENAME], LENGTH_FILENAME, fileName);
|
||||
|
||||
header.SetFileName(fileName);
|
||||
header.SetLength(
|
||||
_ReadHeaderNumeric(&block[OFFSET_LENGTH], LENGTH_LENGTH));
|
||||
header.SetFileType(
|
||||
_ReadHeaderFileType(block[OFFSET_FILETYPE]));
|
||||
header.SetLength(_ReadHeaderNumeric(&block[OFFSET_LENGTH], LENGTH_LENGTH));
|
||||
header.SetFileType(_ReadHeaderFileType(block[OFFSET_FILETYPE]));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
+80
-113
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* Copyright 2017-2024, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2017-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -13,19 +13,20 @@
|
||||
#include <Catalog.h>
|
||||
#include <Entry.h>
|
||||
#include <Message.h>
|
||||
#include <package/PackageDefs.h>
|
||||
#include <package/PackageInfo.h>
|
||||
#include <package/PackageRoster.h>
|
||||
#include <Path.h>
|
||||
#include <Roster.h>
|
||||
#include <Screen.h>
|
||||
#include <String.h>
|
||||
#include <package/PackageDefs.h>
|
||||
#include <package/PackageInfo.h>
|
||||
#include <package/PackageRoster.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#include "AppUtils.h"
|
||||
#include "Logger.h"
|
||||
#include "MainWindow.h"
|
||||
#include "PackageKitUtils.h"
|
||||
#include "PackageUtils.h"
|
||||
#include "ServerHelper.h"
|
||||
#include "ServerSettings.h"
|
||||
@@ -44,7 +45,7 @@ App::App()
|
||||
fWindowCount(0),
|
||||
fSettingsRead(false)
|
||||
{
|
||||
srand((unsigned int) time(NULL));
|
||||
srand(static_cast<unsigned int>(time(NULL)));
|
||||
_CheckPackageDaemonRuns();
|
||||
fIsFirstRun = _CheckIsFirstRun();
|
||||
}
|
||||
@@ -62,13 +63,10 @@ App::~App()
|
||||
bool
|
||||
App::QuitRequested()
|
||||
{
|
||||
if (fMainWindow != NULL
|
||||
&& fMainWindow->LockLooperWithTimeout(1500000) == B_OK) {
|
||||
if (fMainWindow != NULL && fMainWindow->LockLooperWithTimeout(1500000) == B_OK) {
|
||||
BMessage windowSettings;
|
||||
fMainWindow->StoreSettings(windowSettings);
|
||||
|
||||
fMainWindow->UnlockLooper();
|
||||
|
||||
_StoreSettings(windowSettings);
|
||||
}
|
||||
|
||||
@@ -111,10 +109,8 @@ App::MessageReceived(BMessage* message)
|
||||
case MSG_MAIN_WINDOW_CLOSED:
|
||||
{
|
||||
BMessage windowSettings;
|
||||
if (message->FindMessage(KEY_WINDOW_SETTINGS,
|
||||
&windowSettings) == B_OK) {
|
||||
if (message->FindMessage(KEY_WINDOW_SETTINGS, &windowSettings) == B_OK)
|
||||
_StoreSettings(windowSettings);
|
||||
}
|
||||
|
||||
fWindowCount--;
|
||||
if (fWindowCount == 0)
|
||||
@@ -199,7 +195,7 @@ app_print_help()
|
||||
|
||||
|
||||
static arg_switch
|
||||
app_resolve_switch(char *arg)
|
||||
app_resolve_switch(char* arg)
|
||||
{
|
||||
int arglen = strlen(arg);
|
||||
|
||||
@@ -223,18 +219,14 @@ app_resolve_switch(char *arg)
|
||||
|
||||
if (0 == strcmp(&arg[2], "dropcache"))
|
||||
return DROP_CACHE_SWITCH;
|
||||
} else {
|
||||
if (arglen == 2) { // short form
|
||||
switch (arg[1]) {
|
||||
case 'u':
|
||||
return WEB_APP_BASE_URL_SWITCH;
|
||||
|
||||
case 'h':
|
||||
return HELP_SWITCH;
|
||||
|
||||
case 'v':
|
||||
return VERBOSITY_SWITCH;
|
||||
}
|
||||
} else if (arglen == 2) { // short form
|
||||
switch (arg[1]) {
|
||||
case 'h':
|
||||
return HELP_SWITCH;
|
||||
case 'u':
|
||||
return WEB_APP_BASE_URL_SWITCH;
|
||||
case 'v':
|
||||
return VERBOSITY_SWITCH;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,15 +242,14 @@ App::ArgvReceived(int32 argc, char* argv[])
|
||||
{
|
||||
for (int i = 1; i < argc;) {
|
||||
|
||||
// check to make sure that if there is a value for the switch,
|
||||
// that the value is in fact supplied.
|
||||
// check to make sure that if there is a value for the switch,
|
||||
// that the value is in fact supplied.
|
||||
|
||||
switch (app_resolve_switch(argv[i])) {
|
||||
case VERBOSITY_SWITCH:
|
||||
case WEB_APP_BASE_URL_SWITCH:
|
||||
if (i == argc-1) {
|
||||
fprintf(stdout, "unexpected end of arguments; missing "
|
||||
"value for switch [%s]\n", argv[i]);
|
||||
if (i == argc - 1) {
|
||||
HDERROR("unexpected end of arguments; missing value for switch [%s]", argv[i]);
|
||||
Quit();
|
||||
return;
|
||||
}
|
||||
@@ -268,12 +259,12 @@ App::ArgvReceived(int32 argc, char* argv[])
|
||||
break;
|
||||
}
|
||||
|
||||
// now process each switch.
|
||||
// now process each switch.
|
||||
|
||||
switch (app_resolve_switch(argv[i])) {
|
||||
|
||||
case VERBOSITY_SWITCH:
|
||||
if (!Logger::SetLevelByName(argv[i+1])) {
|
||||
if (!Logger::SetLevelByName(argv[i + 1])) {
|
||||
fprintf(stdout, "unknown log level [%s]\n", argv[i + 1]);
|
||||
Quit();
|
||||
}
|
||||
@@ -287,13 +278,10 @@ App::ArgvReceived(int32 argc, char* argv[])
|
||||
|
||||
case WEB_APP_BASE_URL_SWITCH:
|
||||
if (ServerSettings::SetBaseUrl(BUrl(argv[i + 1])) != B_OK) {
|
||||
fprintf(stdout, "malformed web app base url; %s\n",
|
||||
argv[i + 1]);
|
||||
HDERROR("malformed web app base url; %s", argv[i + 1]);
|
||||
Quit();
|
||||
}
|
||||
else {
|
||||
fprintf(stdout, "did configure the web base url; %s\n",
|
||||
argv[i + 1]);
|
||||
} else {
|
||||
HDERROR("did configure the web base url; %s", argv[i + 1]);
|
||||
}
|
||||
|
||||
i++; // also move past the url value
|
||||
@@ -330,8 +318,8 @@ App::ArgvReceived(int32 argc, char* argv[])
|
||||
}
|
||||
|
||||
|
||||
/*! This method will display an alert based on a message. This message arrives
|
||||
from a number of possible background threads / processes in the application.
|
||||
/*! This method will display an alert based on a message. This message arrives
|
||||
from a number of possible background threads / processes in the application.
|
||||
*/
|
||||
|
||||
void
|
||||
@@ -350,8 +338,8 @@ App::_AlertSimpleError(BMessage* message)
|
||||
if (message->FindInt32(KEY_ALERT_TYPE, &typeInt) != B_OK)
|
||||
typeInt = B_INFO_ALERT;
|
||||
|
||||
BAlert* alert = new BAlert(alertTitle, alertText, B_TRANSLATE("OK"),
|
||||
NULL, NULL, B_WIDTH_AS_USUAL, static_cast<alert_type>(typeInt));
|
||||
BAlert* alert = new BAlert(alertTitle, alertText, B_TRANSLATE("OK"), NULL, NULL,
|
||||
B_WIDTH_AS_USUAL, static_cast<alert_type>(typeInt));
|
||||
|
||||
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
|
||||
alert->Go();
|
||||
@@ -366,7 +354,7 @@ App::_Open(const BEntry& entry)
|
||||
{
|
||||
BPath path;
|
||||
if (!entry.Exists() || entry.GetPath(&path) != B_OK) {
|
||||
fprintf(stderr, "Package file not found: %s\n", path.Path());
|
||||
HDERROR("package file not found: %s", path.Path());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -374,20 +362,16 @@ App::_Open(const BEntry& entry)
|
||||
BPackageKit::BPackageInfo info;
|
||||
status_t status = info.ReadFromPackageFile(path.Path());
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr, "Failed to parse package file: %s\n",
|
||||
strerror(status));
|
||||
HDERROR("failed to parse package file: %s", strerror(status));
|
||||
return;
|
||||
}
|
||||
|
||||
// Transfer information into PackageInfo
|
||||
PackageInfoRef package(new(std::nothrow) PackageInfo(info), true);
|
||||
if (!package.IsSet()) {
|
||||
fprintf(stderr, "Could not allocate PackageInfo\n");
|
||||
return;
|
||||
}
|
||||
PackageInfoRef filePackageInfo = PackageKitUtils::CreatePackageInfo(info);
|
||||
PackageInfoBuilder packageBuilder(filePackageInfo);
|
||||
|
||||
PackageLocalInfoRef localInfo = PackageUtils::NewLocalInfo(package);
|
||||
localInfo->SetLocalFilePath(path.Path());
|
||||
PackageLocalInfoBuilder localInfoBuilder(filePackageInfo->LocalInfo());
|
||||
localInfoBuilder.WithLocalFilePath(path.Path());
|
||||
|
||||
// Set if the package is active
|
||||
//
|
||||
@@ -396,33 +380,30 @@ App::_Open(const BEntry& entry)
|
||||
// package kit have to know about these locations?
|
||||
bool active = false;
|
||||
BPackageKit::BPackageRoster roster;
|
||||
status = roster.IsPackageActive(
|
||||
BPackageKit::B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, info, &active);
|
||||
status = roster.IsPackageActive(BPackageKit::B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, info,
|
||||
&active);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr, "Could not check if package was active in system: %s\n",
|
||||
strerror(status));
|
||||
HDERROR("could not check if package was active in system: %s", strerror(status));
|
||||
return;
|
||||
}
|
||||
if (!active) {
|
||||
status = roster.IsPackageActive(
|
||||
BPackageKit::B_PACKAGE_INSTALLATION_LOCATION_HOME, info, &active);
|
||||
status = roster.IsPackageActive(BPackageKit::B_PACKAGE_INSTALLATION_LOCATION_HOME, info,
|
||||
&active);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr,
|
||||
"Could not check if package was active in home: %s\n",
|
||||
strerror(status));
|
||||
HDERROR("could not check if package was active in home: %s", strerror(status));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (active)
|
||||
localInfo->SetState(ACTIVATED);
|
||||
localInfoBuilder.WithState(ACTIVATED);
|
||||
|
||||
package->SetLocalInfo(localInfo);
|
||||
packageBuilder.WithLocalInfo(localInfoBuilder.BuildRef());
|
||||
|
||||
BMessage settings;
|
||||
_LoadSettings(settings);
|
||||
|
||||
MainWindow* window = new MainWindow(settings, package);
|
||||
MainWindow* window = new MainWindow(settings, packageBuilder.BuildRef());
|
||||
_ShowWindow(window);
|
||||
}
|
||||
|
||||
@@ -478,21 +459,19 @@ App::_StoreSettings(const BMessage& settings)
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
static const char* kPackageDaemonSignature
|
||||
= "application/x-vnd.haiku-package_daemon";
|
||||
static const char* kPackageDaemonSignature = "application/x-vnd.haiku-package_daemon";
|
||||
|
||||
|
||||
void
|
||||
App::_CheckPackageDaemonRuns()
|
||||
{
|
||||
while (!be_roster->IsRunning(kPackageDaemonSignature)) {
|
||||
BAlert* alert = new BAlert(
|
||||
B_TRANSLATE("Start package daemon"),
|
||||
BAlert* alert = new BAlert(B_TRANSLATE("Start package daemon"),
|
||||
B_TRANSLATE("HaikuDepot needs the package daemon to function, "
|
||||
"and it appears to be not running.\n"
|
||||
"Would you like to start it now?"),
|
||||
B_TRANSLATE("No, quit HaikuDepot"),
|
||||
B_TRANSLATE("Start package daemon"), NULL, B_WIDTH_AS_USUAL,
|
||||
B_WARNING_ALERT);
|
||||
"and it appears to be not running.\n"
|
||||
"Would you like to start it now?"),
|
||||
B_TRANSLATE("No, quit HaikuDepot"), B_TRANSLATE("Start package daemon"), NULL,
|
||||
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
|
||||
alert->SetShortcut(0, B_ESCAPE);
|
||||
|
||||
if (alert->Go() == 0)
|
||||
@@ -509,14 +488,11 @@ App::_LaunchPackageDaemon()
|
||||
{
|
||||
status_t ret = be_roster->Launch(kPackageDaemonSignature);
|
||||
if (ret != B_OK) {
|
||||
BString errorMessage
|
||||
= B_TRANSLATE("Starting the package daemon failed:\n\n%Error%");
|
||||
BString errorMessage = B_TRANSLATE("Starting the package daemon failed:\n\n%Error%");
|
||||
errorMessage.ReplaceAll("%Error%", strerror(ret));
|
||||
|
||||
BAlert* alert = new BAlert(
|
||||
B_TRANSLATE("Package daemon problem"), errorMessage,
|
||||
B_TRANSLATE("Quit HaikuDepot"),
|
||||
B_TRANSLATE("Try again"), NULL, B_WIDTH_AS_USUAL,
|
||||
BAlert* alert = new BAlert(B_TRANSLATE("Package daemon problem"), errorMessage,
|
||||
B_TRANSLATE("Quit HaikuDepot"), B_TRANSLATE("Try again"), NULL, B_WIDTH_AS_USUAL,
|
||||
B_WARNING_ALERT);
|
||||
alert->SetShortcut(0, B_ESCAPE);
|
||||
|
||||
@@ -535,20 +511,18 @@ App::_CheckIsFirstRun()
|
||||
{
|
||||
BPath testFilePath;
|
||||
bool exists = false;
|
||||
status_t status = StorageUtils::LocalWorkingFilesPath("testfile.txt",
|
||||
testFilePath, false);
|
||||
if (status != B_OK) {
|
||||
status_t status = StorageUtils::LocalWorkingFilesPath("testfile.txt", testFilePath, false);
|
||||
if (status != B_OK)
|
||||
HDERROR("unable to establish the location of the test file");
|
||||
}
|
||||
else
|
||||
status = StorageUtils::ExistsObject(testFilePath, &exists, NULL, NULL);
|
||||
return !exists;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Checks to ensure that a working file is able to be written.
|
||||
\return false if the startup should be stopped and the application should
|
||||
quit.
|
||||
/*! \brief Checks to ensure that a working file is able to be written.
|
||||
\return false if the startup should be stopped and the application should
|
||||
quit.
|
||||
*/
|
||||
|
||||
bool
|
||||
@@ -556,8 +530,7 @@ App::_CheckTestFile()
|
||||
{
|
||||
BPath testFilePath;
|
||||
BString pathDescription = "???";
|
||||
status_t result = StorageUtils::LocalWorkingFilesPath("testfile.txt",
|
||||
testFilePath, false);
|
||||
status_t result = StorageUtils::LocalWorkingFilesPath("testfile.txt", testFilePath, false);
|
||||
|
||||
if (result == B_OK) {
|
||||
pathDescription = testFilePath.Path();
|
||||
@@ -567,19 +540,18 @@ App::_CheckTestFile()
|
||||
if (result != B_OK) {
|
||||
StorageUtils::SetWorkingFilesUnavailable();
|
||||
|
||||
BString msg = B_TRANSLATE("This application writes and reads some"
|
||||
" working files on your computer in order to function. It appears"
|
||||
" that there are problems writing a test file at [%TestFilePath%]."
|
||||
" Check that there are no issues with your local disk or"
|
||||
" permissions that might prevent this application from writing"
|
||||
" files into that directory location. You may choose to acknowledge"
|
||||
" this problem and continue, but some functionality may be"
|
||||
" disabled.");
|
||||
BString msg
|
||||
= B_TRANSLATE("This application writes and reads some"
|
||||
" working files on your computer in order to function. It appears"
|
||||
" that there are problems writing a test file at [%TestFilePath%]."
|
||||
" Check that there are no issues with your local disk or"
|
||||
" permissions that might prevent this application from writing"
|
||||
" files into that directory location. You may choose to acknowledge"
|
||||
" this problem and continue, but some functionality may be"
|
||||
" disabled.");
|
||||
msg.ReplaceAll("%TestFilePath%", pathDescription);
|
||||
|
||||
BAlert* alert = new(std::nothrow) BAlert(
|
||||
B_TRANSLATE("Problem with working files"),
|
||||
msg,
|
||||
BAlert* alert = new(std::nothrow) BAlert(B_TRANSLATE("Problem with working files"), msg,
|
||||
B_TRANSLATE("Quit"), B_TRANSLATE("Continue"));
|
||||
|
||||
if (alert->Go() == 0)
|
||||
@@ -611,8 +583,7 @@ App::_ClearCacheOnVersionChange()
|
||||
}
|
||||
|
||||
BPath lastVersionPath;
|
||||
if (StorageUtils::LocalWorkingFilesPath(
|
||||
"version.txt", lastVersionPath) != B_OK) {
|
||||
if (StorageUtils::LocalWorkingFilesPath("version.txt", lastVersionPath) != B_OK) {
|
||||
HDERROR("clear cache; unable to get version file path");
|
||||
return;
|
||||
}
|
||||
@@ -620,30 +591,26 @@ App::_ClearCacheOnVersionChange()
|
||||
bool exists;
|
||||
off_t size;
|
||||
|
||||
if (StorageUtils::ExistsObject(
|
||||
lastVersionPath, &exists, NULL, &size) != B_OK) {
|
||||
if (StorageUtils::ExistsObject(lastVersionPath, &exists, NULL, &size) != B_OK) {
|
||||
HDERROR("clear cache; unable to check version file exists");
|
||||
return;
|
||||
}
|
||||
|
||||
BString lastVersion;
|
||||
|
||||
if (exists && StorageUtils::AppendToString(lastVersionPath, lastVersion)
|
||||
!= B_OK) {
|
||||
HDERROR("clear cache; unable to read the version from [%s]",
|
||||
lastVersionPath.Path());
|
||||
if (exists && StorageUtils::AppendToString(lastVersionPath, lastVersion) != B_OK) {
|
||||
HDERROR("clear cache; unable to read the version from [%s]", lastVersionPath.Path());
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastVersion != version) {
|
||||
HDINFO("last version [%s] and current version [%s] do not match"
|
||||
" -> will flush cache", lastVersion.String(), version.String());
|
||||
HDINFO("last version [%s] and current version [%s] do not match -> will flush cache",
|
||||
lastVersion.String(), version.String());
|
||||
StorageUtils::RemoveWorkingDirectoryContents();
|
||||
HDINFO("will write version [%s] to [%s]",
|
||||
version.String(), lastVersionPath.Path());
|
||||
HDINFO("will write version [%s] to [%s]", version.String(), lastVersionPath.Path());
|
||||
StorageUtils::AppendToFile(version, lastVersionPath);
|
||||
} else {
|
||||
HDINFO("last version [%s] and current version [%s] match"
|
||||
" -> cache retained", lastVersion.String(), version.String());
|
||||
HDINFO("last version [%s] and current version [%s] match -> cache retained",
|
||||
lastVersion.String(), version.String());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright 2013-214, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>.
|
||||
* Copyright 2020-2024, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2020-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "Logger.h"
|
||||
#include "MainWindow.h"
|
||||
#include "MarkupTextView.h"
|
||||
#include "MessagePackageListener.h"
|
||||
#include "PackageUtils.h"
|
||||
#include "RatingUtils.h"
|
||||
#include "RatingView.h"
|
||||
@@ -55,8 +54,7 @@
|
||||
// #pragma mark - PackageView
|
||||
|
||||
|
||||
class StackedFeaturesPackageBandMetrics
|
||||
{
|
||||
class StackedFeaturesPackageBandMetrics {
|
||||
public:
|
||||
StackedFeaturesPackageBandMetrics(float width, BFont* titleFont, BFont* metadataFont)
|
||||
{
|
||||
@@ -69,8 +67,7 @@ public:
|
||||
metadataFont->GetHeight(&metadataFontHeight);
|
||||
|
||||
float totalTitleAndMetadataHeight = titleFontHeight.ascent + titleFontHeight.descent
|
||||
+ titleFontHeight.leading
|
||||
+ metadataFontHeight.leading
|
||||
+ titleFontHeight.leading + metadataFontHeight.leading
|
||||
+ 2.0 * (metadataFontHeight.ascent + metadataFontHeight.descent);
|
||||
|
||||
fHeight = fmaxf(totalTitleAndMetadataHeight, iconSize.Height()) + 2.0 * padding;
|
||||
@@ -85,41 +82,43 @@ public:
|
||||
float titleWidthM = titleFont->StringWidth("M");
|
||||
|
||||
float leftTitlePublisherAndChronologicalInfo = fIconRect.right + padding;
|
||||
float rightTitlePublisherAndChronologicalInfo = fminf(width, fIconRect.Size().Width()
|
||||
+ (2.0 * padding) + (titleWidthM * M_COUNT_TITLE));
|
||||
float rightTitlePublisherAndChronologicalInfo = fminf(width,
|
||||
fIconRect.Size().Width() + (2.0 * padding) + (titleWidthM * M_COUNT_TITLE));
|
||||
|
||||
// left, top, right bottom
|
||||
|
||||
// left, top, right bottom
|
||||
fTitleRect = BRect(leftTitlePublisherAndChronologicalInfo,
|
||||
(fHeight - totalTitleAndMetadataHeight) / 2.0,
|
||||
rightTitlePublisherAndChronologicalInfo,
|
||||
((fHeight - totalTitleAndMetadataHeight) / 2.0)
|
||||
+ titleFontHeight.ascent + titleFontHeight.descent);
|
||||
((fHeight - totalTitleAndMetadataHeight) / 2.0) + titleFontHeight.ascent
|
||||
+ titleFontHeight.descent);
|
||||
|
||||
fPublisherRect = BRect(leftTitlePublisherAndChronologicalInfo,
|
||||
fTitleRect.bottom + titleFontHeight.leading,
|
||||
rightTitlePublisherAndChronologicalInfo,
|
||||
fTitleRect.bottom + titleFontHeight.leading
|
||||
+ metadataFontHeight.ascent + metadataFontHeight.descent);
|
||||
fTitleRect.bottom + titleFontHeight.leading + metadataFontHeight.ascent
|
||||
+ metadataFontHeight.descent);
|
||||
|
||||
fChronologicalInfoRect = BRect(leftTitlePublisherAndChronologicalInfo,
|
||||
fPublisherRect.bottom + metadataFontHeight.leading,
|
||||
rightTitlePublisherAndChronologicalInfo,
|
||||
fPublisherRect.bottom + metadataFontHeight.leading
|
||||
+ metadataFontHeight.ascent + metadataFontHeight.descent);
|
||||
}
|
||||
fPublisherRect.bottom + metadataFontHeight.leading + metadataFontHeight.ascent
|
||||
+ metadataFontHeight.descent);
|
||||
}
|
||||
|
||||
// sort out the ratings display
|
||||
// sort out the ratings display
|
||||
|
||||
{
|
||||
BSize ratingStarSize = SharedIcons::IconStarBlue16Scaled()->Bitmap()->Bounds().Size();
|
||||
RatingStarsMetrics ratingStarsMetrics(ratingStarSize);
|
||||
|
||||
fRatingStarsRect = BRect(BPoint(fTitleRect.right + padding,
|
||||
(fHeight - ratingStarsMetrics.Size().Height()) / 2), ratingStarsMetrics.Size());
|
||||
(fHeight - ratingStarsMetrics.Size().Height()) / 2),
|
||||
ratingStarsMetrics.Size());
|
||||
|
||||
if (fRatingStarsRect.right > width)
|
||||
if (fRatingStarsRect.right > width) {
|
||||
fRatingStarsRect = BRect();
|
||||
else {
|
||||
} else {
|
||||
// Now sort out the position for the summary. This is reckoned as a container
|
||||
// rect because it would be nice to layout the text with newlines and not just a
|
||||
// single line.
|
||||
@@ -190,10 +189,7 @@ public:
|
||||
:
|
||||
BView("stacked featured packages view", B_WILL_DRAW | B_FRAME_EVENTS),
|
||||
fModel(model),
|
||||
fSelectedIndex(-1),
|
||||
fPackageListener(
|
||||
new(std::nothrow) OnePackageMessagePackageListener(this)),
|
||||
fLowestIndexAddedOrRemoved(-1)
|
||||
fSelectedIndex(-1)
|
||||
{
|
||||
SetEventMask(B_POINTER_EVENTS);
|
||||
|
||||
@@ -208,29 +204,17 @@ public:
|
||||
|
||||
virtual ~StackedFeaturedPackagesView()
|
||||
{
|
||||
fPackageListener->SetPackage(PackageInfoRef(NULL));
|
||||
fPackageListener->ReleaseReference();
|
||||
delete fBandMetrics;
|
||||
delete fTitleFont;
|
||||
delete fMetadataFont;
|
||||
delete fSummaryFont;
|
||||
}
|
||||
|
||||
// #pragma mark - message handling and events
|
||||
// #pragma mark - message handling and events
|
||||
|
||||
virtual void MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case MSG_UPDATE_PACKAGE:
|
||||
{
|
||||
BString name;
|
||||
if (message->FindString("name", &name) != B_OK)
|
||||
HDINFO("expected 'name' key on package update message");
|
||||
else
|
||||
_HandleUpdatePackage(name);
|
||||
break;
|
||||
}
|
||||
|
||||
case B_COLORS_UPDATED:
|
||||
{
|
||||
Invalidate();
|
||||
@@ -268,16 +252,14 @@ public:
|
||||
case B_DOWN_ARROW:
|
||||
{
|
||||
int32 lastIndex = static_cast<int32>(fPackages.size()) - 1;
|
||||
if (!IsEmpty() && fSelectedIndex != -1
|
||||
&& fSelectedIndex < lastIndex) {
|
||||
if (!IsEmpty() && fSelectedIndex != -1 && fSelectedIndex < lastIndex)
|
||||
_MessageSelectIndex(fSelectedIndex + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case B_LEFT_ARROW:
|
||||
case B_UP_ARROW:
|
||||
if (fSelectedIndex > 0)
|
||||
_MessageSelectIndex( fSelectedIndex - 1);
|
||||
_MessageSelectIndex(fSelectedIndex - 1);
|
||||
break;
|
||||
case B_PAGE_UP:
|
||||
{
|
||||
@@ -328,13 +310,26 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - update / add / remove / clear data
|
||||
// #pragma mark - update / add / remove / clear data
|
||||
|
||||
|
||||
void UpdatePackage(uint32 changeMask, const PackageInfoRef& package)
|
||||
void HandlePackagesChanged(const PackageInfoEvents& events)
|
||||
{
|
||||
// TODO; could optimize the invalidation?
|
||||
for (int32 i = events.CountEvents() - 1; i >= 0; i--)
|
||||
_HandlePackageChanged(events.EventAtIndex(i));
|
||||
}
|
||||
|
||||
|
||||
void _HandlePackageChanged(const PackageInfoEvent& event)
|
||||
{
|
||||
uint32 changes = event.Changes();
|
||||
PackageInfoRef package = event.Package();
|
||||
|
||||
if (!package.IsSet() || 0 == changes)
|
||||
return;
|
||||
|
||||
int32 index = _IndexOfPackage(package);
|
||||
|
||||
if (index >= 0) {
|
||||
fPackages[index] = package;
|
||||
Invalidate(_RectOfIndex(index));
|
||||
@@ -344,10 +339,6 @@ public:
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for (std::vector<PackageInfoRef>::iterator it = fPackages.begin();
|
||||
it != fPackages.end(); it++) {
|
||||
(*it)->RemoveListener(fPackageListener);
|
||||
}
|
||||
fPackages.clear();
|
||||
fSelectedIndex = -1;
|
||||
|
||||
@@ -367,8 +358,8 @@ public:
|
||||
}
|
||||
|
||||
|
||||
static BFont* CreateMetadataFont()
|
||||
{
|
||||
static BFont* CreateMetadataFont()
|
||||
{
|
||||
BFont* font = new BFont(be_plain_font);
|
||||
font_family family;
|
||||
font_style style;
|
||||
@@ -396,14 +387,6 @@ public:
|
||||
}
|
||||
|
||||
|
||||
void _HandleUpdatePackage(const BString& name)
|
||||
{
|
||||
int32 index = _IndexOfName(name);
|
||||
if (index != -1)
|
||||
Invalidate(_RectOfIndex(index));
|
||||
}
|
||||
|
||||
|
||||
static int _CmpProminences(int64 a, int64 b)
|
||||
{
|
||||
if (a <= 0)
|
||||
@@ -456,68 +439,110 @@ public:
|
||||
}
|
||||
|
||||
|
||||
void BeginAddRemove()
|
||||
void _InvalidateFromIndex(int32 index)
|
||||
{
|
||||
fLowestIndexAddedOrRemoved = INT32_MAX;
|
||||
}
|
||||
|
||||
|
||||
void EndAddRemove()
|
||||
{
|
||||
if (fLowestIndexAddedOrRemoved < INT32_MAX) {
|
||||
if (fPackages.empty())
|
||||
if (index != -1) {
|
||||
if (fPackages.empty()) {
|
||||
Invalidate();
|
||||
else {
|
||||
} else {
|
||||
BRect invalidRect = Bounds();
|
||||
invalidRect.top = _YOfIndex(fLowestIndexAddedOrRemoved);
|
||||
invalidRect.top = _YOfIndex(index);
|
||||
Invalidate(invalidRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AddPackage(const PackageInfoRef& package)
|
||||
/*! Finds the index of the first difference between the current list of
|
||||
packages and the provided list of packages. Returns -1 if there is
|
||||
no difference. This is used with the `RetainPackages` method.
|
||||
*/
|
||||
int32 _IndexOfFirstDifference(const std::vector<PackageInfoRef>& packages)
|
||||
{
|
||||
size_t result = 0;
|
||||
size_t packagesLen = packages.size();
|
||||
size_t currentPackagesLen = fPackages.size();
|
||||
|
||||
while (true) {
|
||||
if (result == packagesLen && result == currentPackagesLen)
|
||||
return -1;
|
||||
if (result >= packagesLen || result >= currentPackagesLen)
|
||||
return static_cast<int32>(result);
|
||||
if (packages[result] != fPackages[result])
|
||||
return static_cast<int32>(result);
|
||||
result++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RetainPackages(const std::vector<PackageInfoRef>& packages)
|
||||
{
|
||||
int32 lowestIndexAddedOrRemoved = _IndexOfFirstDifference(packages);
|
||||
fPackages = packages;
|
||||
_InvalidateFromIndex(lowestIndexAddedOrRemoved);
|
||||
}
|
||||
|
||||
|
||||
void _AddPackage(const PackageInfoRef& package, int32* lowestIndexAddedOrRemoved)
|
||||
{
|
||||
// fPackages is sorted and for this reason it is possible to find the
|
||||
// insertion point by identifying the first item in fPackages that does
|
||||
// not return true from the method '_IsPackageBefore'.
|
||||
|
||||
std::vector<PackageInfoRef>::iterator itInsertionPt
|
||||
= std::lower_bound(fPackages.begin(), fPackages.end(), package,
|
||||
&_IsPackageBefore);
|
||||
= std::lower_bound(fPackages.begin(), fPackages.end(), package, &_IsPackageBefore);
|
||||
|
||||
if (itInsertionPt == fPackages.end() || package->Name() != (*itInsertionPt)->Name()) {
|
||||
int32 insertionIndex = std::distance<std::vector<PackageInfoRef>::const_iterator>(
|
||||
fPackages.begin(), itInsertionPt);
|
||||
|
||||
if (itInsertionPt == fPackages.end()
|
||||
|| package->Name() != (*itInsertionPt)->Name()) {
|
||||
int32 insertionIndex =
|
||||
std::distance<std::vector<PackageInfoRef>::const_iterator>(
|
||||
fPackages.begin(), itInsertionPt);
|
||||
if (fSelectedIndex >= insertionIndex)
|
||||
fSelectedIndex++;
|
||||
|
||||
fPackages.insert(itInsertionPt, package);
|
||||
package->AddListener(fPackageListener);
|
||||
if (insertionIndex < fLowestIndexAddedOrRemoved)
|
||||
fLowestIndexAddedOrRemoved = insertionIndex;
|
||||
|
||||
if (insertionIndex > *lowestIndexAddedOrRemoved)
|
||||
*lowestIndexAddedOrRemoved = insertionIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RemovePackage(const PackageInfoRef& package)
|
||||
void _RemovePackage(const PackageInfoRef& package, int32* lowestIndexAddedOrRemoved)
|
||||
{
|
||||
int32 index = _IndexOfPackage(package);
|
||||
if (index >= 0) {
|
||||
if (fSelectedIndex == index)
|
||||
int32 removalIndex = _IndexOfPackage(package);
|
||||
if (removalIndex >= 0) {
|
||||
|
||||
if (fSelectedIndex == removalIndex)
|
||||
fSelectedIndex = -1;
|
||||
if (fSelectedIndex > index)
|
||||
|
||||
if (fSelectedIndex > removalIndex)
|
||||
fSelectedIndex--;
|
||||
fPackages[index]->RemoveListener(fPackageListener);
|
||||
fPackages.erase(fPackages.begin() + index);
|
||||
if (index < fLowestIndexAddedOrRemoved)
|
||||
fLowestIndexAddedOrRemoved = index;
|
||||
|
||||
fPackages.erase(fPackages.begin() + removalIndex);
|
||||
|
||||
if (removalIndex > *lowestIndexAddedOrRemoved)
|
||||
*lowestIndexAddedOrRemoved = removalIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - selection and index handling
|
||||
void AddRemovePackages(const std::vector<PackageInfoRef>& addedPackages,
|
||||
const std::vector<PackageInfoRef>& removedPackages)
|
||||
{
|
||||
int32 lowestIndexAddedOrRemoved = -1;
|
||||
std::vector<PackageInfoRef>::const_iterator it;
|
||||
|
||||
for (it = addedPackages.begin(); it != addedPackages.end(); it++)
|
||||
_AddPackage(*it, &lowestIndexAddedOrRemoved);
|
||||
|
||||
for (it = removedPackages.begin(); it != removedPackages.end(); it++)
|
||||
_RemovePackage(*it, &lowestIndexAddedOrRemoved);
|
||||
|
||||
_InvalidateFromIndex(lowestIndexAddedOrRemoved);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - selection and index handling
|
||||
|
||||
|
||||
void SelectPackage(const PackageInfoRef& package)
|
||||
@@ -543,11 +568,12 @@ public:
|
||||
int32 _IndexOfPackage(PackageInfoRef package) const
|
||||
{
|
||||
std::vector<PackageInfoRef>::const_iterator it
|
||||
= std::lower_bound(fPackages.begin(), fPackages.end(), package,
|
||||
&_IsPackageBefore);
|
||||
= std::lower_bound(fPackages.begin(), fPackages.end(), package, &_IsPackageBefore);
|
||||
|
||||
return (it == fPackages.end() || (*it)->Name() != package->Name())
|
||||
? -1 : it - fPackages.begin();
|
||||
if (it == fPackages.end() || (*it)->Name() != package->Name())
|
||||
return -1;
|
||||
|
||||
return it - fPackages.begin();
|
||||
}
|
||||
|
||||
|
||||
@@ -564,7 +590,7 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - drawing and rendering
|
||||
// #pragma mark - drawing and rendering
|
||||
|
||||
|
||||
virtual void Draw(BRect updateRect)
|
||||
@@ -626,9 +652,14 @@ public:
|
||||
if (!iconRect.IsValid())
|
||||
return;
|
||||
|
||||
PackageIconRepositoryRef iconRepository = fModel.IconRepository();
|
||||
|
||||
if (!iconRepository.IsSet())
|
||||
return;
|
||||
|
||||
BitmapHolderRef icon;
|
||||
status_t iconResult = fModel.GetPackageIconRepository().GetIcon(pkg->Name(),
|
||||
iconRect.Width(), icon);
|
||||
|
||||
status_t iconResult = iconRepository->GetIcon(pkg->Name(), iconRect.Width(), icon);
|
||||
|
||||
if (iconResult == B_OK) {
|
||||
if (icon.IsSet()) {
|
||||
@@ -659,9 +690,9 @@ public:
|
||||
float trailingIconsWidth = 0.0f;
|
||||
|
||||
for (std::vector<BitmapHolderRef>::iterator it = trailingIconBitmaps.begin();
|
||||
it != trailingIconBitmaps.end(); it++) {
|
||||
trailingIconsWidth += (*it)->Bitmap()->Bounds().Width()
|
||||
* (1.0 + TRAILING_ICON_PADDING_LEFT_FACTOR);
|
||||
it != trailingIconBitmaps.end(); it++) {
|
||||
trailingIconsWidth
|
||||
+= (*it)->Bitmap()->Bounds().Width() * (1.0 + TRAILING_ICON_PADDING_LEFT_FACTOR);
|
||||
}
|
||||
|
||||
SetDrawingMode(B_OP_COPY);
|
||||
@@ -671,20 +702,20 @@ public:
|
||||
float titleRightTrailingIconsPadding = 0.0f;
|
||||
|
||||
if (!trailingIconBitmaps.empty()) {
|
||||
titleRightTrailingIconsPadding = StringWidth("M")
|
||||
* TITLE_RIGHT_TRAILING_ICON_PADDING_M_FACTOR;
|
||||
titleRightTrailingIconsPadding
|
||||
= StringWidth("M") * TITLE_RIGHT_TRAILING_ICON_PADDING_M_FACTOR;
|
||||
}
|
||||
|
||||
font_height fontHeight;
|
||||
fTitleFont->GetHeight(&fontHeight);
|
||||
BPoint pt = textRect.LeftTop() + BPoint(0.0, + fontHeight.ascent);
|
||||
BPoint pt = textRect.LeftTop() + BPoint(0.0, +fontHeight.ascent);
|
||||
|
||||
BString title;
|
||||
PackageUtils::TitleOrName(pkg, title);
|
||||
|
||||
BString renderedText = title;
|
||||
TruncateString(&renderedText, B_TRUNCATE_END, textRect.Width()
|
||||
- (titleRightTrailingIconsPadding + trailingIconsWidth));
|
||||
TruncateString(&renderedText, B_TRUNCATE_END,
|
||||
textRect.Width() - (titleRightTrailingIconsPadding + trailingIconsWidth));
|
||||
|
||||
DrawString(renderedText, pt);
|
||||
|
||||
@@ -697,14 +728,15 @@ public:
|
||||
SetDrawingMode(B_OP_ALPHA);
|
||||
|
||||
for (std::vector<BitmapHolderRef>::iterator it = trailingIconBitmaps.begin();
|
||||
it != trailingIconBitmaps.end(); it++) {
|
||||
it != trailingIconBitmaps.end(); it++) {
|
||||
const BBitmap* bitmap = (*it)->Bitmap();
|
||||
BRect bitmapBounds = bitmap->Bounds();
|
||||
|
||||
float trailingIconTopLeftPtX = ceilf(
|
||||
trailingIconX + (bitmapBounds.Width() * TRAILING_ICON_PADDING_LEFT_FACTOR)) + 0.5;
|
||||
float trailingIconTopLeftPtY = ceilf(
|
||||
trailingIconMidY - (bitmapBounds.Height() / 2.0)) + 0.5;
|
||||
float trailingIconTopLeftPtX
|
||||
= ceilf(trailingIconX + (bitmapBounds.Width() * TRAILING_ICON_PADDING_LEFT_FACTOR))
|
||||
+ 0.5;
|
||||
float trailingIconTopLeftPtY
|
||||
= ceilf(trailingIconMidY - (bitmapBounds.Height() / 2.0)) + 0.5;
|
||||
|
||||
BRect trailingIconRect(BPoint(trailingIconTopLeftPtX, trailingIconTopLeftPtY),
|
||||
bitmap->Bounds().Size());
|
||||
@@ -727,7 +759,7 @@ public:
|
||||
|
||||
font_height fontHeight;
|
||||
fMetadataFont->GetHeight(&fontHeight);
|
||||
BPoint pt = textRect.LeftTop() + BPoint(0.0, + fontHeight.ascent);
|
||||
BPoint pt = textRect.LeftTop() + BPoint(0.0, +fontHeight.ascent);
|
||||
|
||||
BString renderedText(text);
|
||||
TruncateString(&renderedText, B_TRUNCATE_END, textRect.Width());
|
||||
@@ -762,7 +794,7 @@ public:
|
||||
if (!ratingRect.IsValid())
|
||||
return;
|
||||
|
||||
UserRatingInfoRef userRatingInfo = pkg->UserRatingInfo();
|
||||
PackageUserRatingInfoRef userRatingInfo = pkg->UserRatingInfo();
|
||||
|
||||
if (userRatingInfo.IsSet()) {
|
||||
UserRatingSummaryRef userRatingSummary = userRatingInfo->Summary();
|
||||
@@ -789,9 +821,10 @@ public:
|
||||
// The text rect is a container into which later text can be made to flow multi-line. For
|
||||
// now just draw one line of the summary.
|
||||
|
||||
BPoint pt = textRect.LeftTop() + BPoint(0.0,
|
||||
(textRect.Size().Height() / 2.0) - ((fontHeight.ascent + fontHeight.descent) / 2.0)
|
||||
+ fontHeight.ascent);
|
||||
BPoint pt = textRect.LeftTop()
|
||||
+ BPoint(0.0,
|
||||
(textRect.Size().Height() / 2.0) - ((fontHeight.ascent + fontHeight.descent) / 2.0)
|
||||
+ fontHeight.ascent);
|
||||
|
||||
BString summary;
|
||||
PackageUtils::Summary(pkg, summary);
|
||||
@@ -801,7 +834,7 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - geometry and scrolling
|
||||
// #pragma mark - geometry and scrolling
|
||||
|
||||
|
||||
/*! This method will make sure that the package at the given index is
|
||||
@@ -816,9 +849,9 @@ public:
|
||||
if (!_IsIndexEntirelyVisible(index)) {
|
||||
BRect bounds = Bounds();
|
||||
int32 indexOfCentreVisible = _IndexOfY(bounds.top + bounds.Height() / 2);
|
||||
if (index < indexOfCentreVisible)
|
||||
if (index < indexOfCentreVisible) {
|
||||
ScrollTo(0, _YOfIndex(index));
|
||||
else {
|
||||
} else {
|
||||
float scrollPointY = (_YOfIndex(index) + fBandMetrics->Height()) - bounds.Height();
|
||||
ScrollTo(0, scrollPointY);
|
||||
}
|
||||
@@ -902,7 +935,7 @@ public:
|
||||
int32 i = static_cast<int32>(y / fBandMetrics->Height());
|
||||
if (i < 0)
|
||||
return 0;
|
||||
return std::min(i, (int32) (fPackages.size() - 1));
|
||||
return std::min(i, (int32)(fPackages.size() - 1));
|
||||
}
|
||||
|
||||
|
||||
@@ -918,9 +951,6 @@ private:
|
||||
std::vector<PackageInfoRef>
|
||||
fPackages;
|
||||
int32 fSelectedIndex;
|
||||
OnePackageMessagePackageListener*
|
||||
fPackageListener;
|
||||
int32 fLowestIndexAddedOrRemoved;
|
||||
StackedFeaturesPackageBandMetrics*
|
||||
fBandMetrics;
|
||||
|
||||
@@ -940,11 +970,10 @@ FeaturedPackagesView::FeaturedPackagesView(Model& model)
|
||||
{
|
||||
fPackagesView = new StackedFeaturedPackagesView(fModel);
|
||||
|
||||
fScrollView = new BScrollView("featured packages scroll view",
|
||||
fPackagesView, 0, false, true, B_FANCY_BORDER);
|
||||
fScrollView = new BScrollView("featured packages scroll view", fPackagesView, 0, false, true,
|
||||
B_FANCY_BORDER);
|
||||
|
||||
BLayoutBuilder::Group<>(this)
|
||||
.Add(fScrollView, 1.0f);
|
||||
BLayoutBuilder::Group<>(this).Add(fScrollView, 1.0f);
|
||||
}
|
||||
|
||||
|
||||
@@ -954,35 +983,21 @@ FeaturedPackagesView::~FeaturedPackagesView()
|
||||
|
||||
|
||||
void
|
||||
FeaturedPackagesView::BeginAddRemove()
|
||||
FeaturedPackagesView::RetainPackages(const std::vector<PackageInfoRef>& packages)
|
||||
{
|
||||
fPackagesView->BeginAddRemove();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FeaturedPackagesView::EndAddRemove()
|
||||
{
|
||||
fPackagesView->EndAddRemove();
|
||||
fPackagesView->RetainPackages(packages);
|
||||
_AdjustViews();
|
||||
}
|
||||
|
||||
|
||||
/*! This method will add the package into the list to be displayed. The
|
||||
insertion will occur in alphabetical order.
|
||||
*/
|
||||
|
||||
void
|
||||
FeaturedPackagesView::AddPackage(const PackageInfoRef& package)
|
||||
FeaturedPackagesView::AddRemovePackages(const std::vector<PackageInfoRef>& addedPackages,
|
||||
const std::vector<PackageInfoRef>& removedPackages)
|
||||
{
|
||||
fPackagesView->AddPackage(package);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FeaturedPackagesView::RemovePackage(const PackageInfoRef& package)
|
||||
{
|
||||
fPackagesView->RemovePackage(package);
|
||||
if (!addedPackages.empty() || !removedPackages.empty()) {
|
||||
fPackagesView->AddRemovePackages(addedPackages, removedPackages);
|
||||
_AdjustViews();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -996,8 +1011,7 @@ FeaturedPackagesView::Clear()
|
||||
|
||||
|
||||
void
|
||||
FeaturedPackagesView::SelectPackage(const PackageInfoRef& package,
|
||||
bool scrollToEntry)
|
||||
FeaturedPackagesView::SelectPackage(const PackageInfoRef& package, bool scrollToEntry)
|
||||
{
|
||||
fPackagesView->SelectPackage(package);
|
||||
|
||||
@@ -1017,9 +1031,22 @@ FeaturedPackagesView::DoLayout()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FeaturedPackagesView::HandleIconsChanged()
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FeaturedPackagesView::HandlePackagesChanged(const PackageInfoEvents& events)
|
||||
{
|
||||
fPackagesView->HandlePackagesChanged(events);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FeaturedPackagesView::_AdjustViews()
|
||||
{
|
||||
fScrollView->FrameResized(fScrollView->Frame().Width(),
|
||||
fScrollView->Frame().Height());
|
||||
fScrollView->FrameResized(fScrollView->Frame().Width(), fScrollView->Frame().Height());
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
/*
|
||||
* Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* Copyright 2020-2024, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2020-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef FEATURED_PACKAGES_VIEW_H
|
||||
#define FEATURED_PACKAGES_VIEW_H
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <View.h>
|
||||
|
||||
#include "Model.h"
|
||||
@@ -24,17 +26,21 @@ public:
|
||||
|
||||
virtual void DoLayout();
|
||||
|
||||
void BeginAddRemove();
|
||||
void EndAddRemove();
|
||||
void AddPackage(const PackageInfoRef& package);
|
||||
void RemovePackage(const PackageInfoRef& package);
|
||||
void RetainPackages(const std::vector<PackageInfoRef>& packages);
|
||||
void AddRemovePackages(const std::vector<PackageInfoRef>& addedPackages,
|
||||
const std::vector<PackageInfoRef>& removedPackages);
|
||||
void Clear();
|
||||
|
||||
void SelectPackage(const PackageInfoRef& package,
|
||||
bool scrollToEntry = false);
|
||||
|
||||
void HandleIconsChanged();
|
||||
|
||||
void HandlePackagesChanged(const PackageInfoEvents& events);
|
||||
|
||||
private:
|
||||
void _AdjustViews();
|
||||
void _HandlePackageChanged(const PackageInfoEvent& event);
|
||||
|
||||
private:
|
||||
Model& fModel;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* Copyright 2019-2020, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2019-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -36,15 +36,12 @@ FilterView::FilterView()
|
||||
fShowField = new BMenuField("category", B_TRANSLATE("Category:"), showMenu);
|
||||
|
||||
// Construct search terms field
|
||||
fSearchTermsText = new BTextControl("search terms",
|
||||
B_TRANSLATE("Search terms:"), "", NULL);
|
||||
fSearchTermsText->SetModificationMessage(
|
||||
new BMessage(MSG_SEARCH_TERMS_MODIFIED));
|
||||
fSearchTermsText = new BTextControl("search terms", B_TRANSLATE("Search terms:"), "", NULL);
|
||||
fSearchTermsText->SetModificationMessage(new BMessage(MSG_SEARCH_TERMS_MODIFIED));
|
||||
|
||||
BSize minSearchSize = fSearchTermsText->MinSize();
|
||||
float minSearchWidth
|
||||
= be_plain_font->StringWidth(fSearchTermsText->Label())
|
||||
+ be_plain_font->StringWidth("XXX") * 6;
|
||||
float minSearchWidth = be_plain_font->StringWidth(fSearchTermsText->Label())
|
||||
+ be_plain_font->StringWidth("XXX") * 6;
|
||||
minSearchWidth = std::max(minSearchSize.width, minSearchWidth);
|
||||
minSearchSize.width = minSearchWidth;
|
||||
fSearchTermsText->SetExplicitMinSize(minSearchSize);
|
||||
@@ -107,27 +104,25 @@ FilterView::AdoptModel(Model& model)
|
||||
BMenu* showMenu = fShowField->Menu();
|
||||
showMenu->RemoveItems(0, showMenu->CountItems(), true);
|
||||
|
||||
showMenu->AddItem(new BMenuItem(B_TRANSLATE("All categories"),
|
||||
new BMessage(MSG_CATEGORY_SELECTED)));
|
||||
showMenu->AddItem(
|
||||
new BMenuItem(B_TRANSLATE("All categories"), new BMessage(MSG_CATEGORY_SELECTED)));
|
||||
|
||||
AutoLocker<BLocker> locker(model.Lock());
|
||||
int32 categoryCount = model.CountCategories();
|
||||
|
||||
if (categoryCount > 0) {
|
||||
if (model.HasCategories()) {
|
||||
showMenu->AddItem(new BSeparatorItem());
|
||||
_AddCategoriesToMenu(model, showMenu);
|
||||
showMenu->SetEnabled(true);
|
||||
} else {
|
||||
showMenu->SetEnabled(false);
|
||||
}
|
||||
|
||||
showMenu->SetEnabled(categoryCount > 0);
|
||||
|
||||
if (!_SelectCategoryCode(showMenu, model.PackageFilter()->Category()))
|
||||
if (!_SelectCategoryCode(showMenu, model.FilterSpecification()->Category()))
|
||||
showMenu->ItemAt(0)->SetMarked(true);
|
||||
}
|
||||
|
||||
|
||||
/*! Tries to mark the menu item that corresponds to the supplied
|
||||
category code. If the supplied code was found and the item marked
|
||||
then the method will return true.
|
||||
category code. If the supplied code was found and the item marked
|
||||
then the method will return true.
|
||||
*/
|
||||
|
||||
/*static*/ bool
|
||||
@@ -159,9 +154,10 @@ FilterView::_MatchesCategoryCode(BMenuItem* item, const BString& 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);
|
||||
std::vector<CategoryRef> categories = model.Categories();
|
||||
std::vector<CategoryRef>::const_iterator it;
|
||||
for (it = categories.begin(); it != categories.end(); it++) {
|
||||
const CategoryRef& category = *it;
|
||||
BMessage* message = new BMessage(MSG_CATEGORY_SELECTED);
|
||||
message->AddString("code", category->Code());
|
||||
BMenuItem* item = new BMenuItem(category->Name(), message);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* Copyright 2013, Rene Gollent <rene@gollent.com>.
|
||||
* Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>.
|
||||
* Copyright 2017-2024, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2017-2025, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef MAIN_WINDOW_H
|
||||
@@ -41,7 +41,7 @@ class MainWindow :
|
||||
public:
|
||||
MainWindow(const BMessage& settings);
|
||||
MainWindow(const BMessage& settings,
|
||||
PackageInfoRef& package);
|
||||
const PackageInfoRef package);
|
||||
virtual ~MainWindow();
|
||||
|
||||
// BWindow interface
|
||||
@@ -63,12 +63,13 @@ public:
|
||||
const UserDetail& userDetail);
|
||||
|
||||
// services PackageInfoListener via MainWindowPackageInfoListener
|
||||
void PackageChanged(
|
||||
const PackageInfoEvent& event);
|
||||
void PackagesChanged(const PackageInfoEvents& events);
|
||||
|
||||
private:
|
||||
static const BString _WindowTitleForPackage(const PackageInfoRef& pkg);
|
||||
|
||||
const std::vector<PackageInfoRef>
|
||||
_CreateSnapshotOfFilteredPackages();
|
||||
std::vector<DepotInfoRef>
|
||||
_CreateSnapshotOfDepots();
|
||||
|
||||
@@ -95,8 +96,6 @@ private:
|
||||
|
||||
void _AdoptModelControls();
|
||||
void _AdoptModel();
|
||||
void _AddRemovePackageFromLists(
|
||||
const PackageInfoRef& package);
|
||||
|
||||
void _AdoptPackage(const PackageInfoRef& package);
|
||||
void _ClearPackage();
|
||||
@@ -128,6 +127,9 @@ private:
|
||||
void _HandleProcessCoordinatorChanged(
|
||||
ProcessCoordinatorState& coordinatorState);
|
||||
|
||||
void _HandlePackagesChanged(const BMessage* message);
|
||||
void _HandlePackagesChanged(const PackageInfoEvents& events);
|
||||
|
||||
static status_t _RefreshModelThreadWorker(void* arg);
|
||||
static status_t _PopulatePackageWorker(void* arg);
|
||||
static status_t _PackagesToShowWorker(void* arg);
|
||||
@@ -148,6 +150,11 @@ private:
|
||||
const UserDetail& userDetail);
|
||||
|
||||
void _HandleScreenshotCached(const BMessage* message);
|
||||
void _HandleIconsChanged();
|
||||
|
||||
void _SetStateForPackagesByName(
|
||||
BStringList& packageNames,
|
||||
PackageState state);
|
||||
|
||||
private:
|
||||
FilterView* fFilterView;
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "MessagePackageListener.h"
|
||||
|
||||
#include <Messenger.h>
|
||||
#include <View.h>
|
||||
|
||||
#include "PackageInfo.h"
|
||||
|
||||
|
||||
// #pragma mark - MessagePackageListener
|
||||
|
||||
|
||||
MessagePackageListener::MessagePackageListener(BHandler* target)
|
||||
:
|
||||
fTarget(target),
|
||||
fChangesMask(0xffffffff)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
MessagePackageListener::~MessagePackageListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MessagePackageListener::PackageChanged(const PackageInfoEvent& event)
|
||||
{
|
||||
if ((event.Changes() & fChangesMask) == 0)
|
||||
return;
|
||||
|
||||
BMessenger messenger(fTarget);
|
||||
if (!messenger.IsValid())
|
||||
return;
|
||||
|
||||
BMessage message(MSG_UPDATE_PACKAGE);
|
||||
message.AddString("name", event.Package()->Name());
|
||||
message.AddUInt32("changes", event.Changes());
|
||||
|
||||
messenger.SendMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MessagePackageListener::SetChangesMask(uint32 mask)
|
||||
{
|
||||
fChangesMask = mask;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - OnePackageMessagePackageListener
|
||||
|
||||
|
||||
OnePackageMessagePackageListener::OnePackageMessagePackageListener(BHandler* target)
|
||||
:
|
||||
MessagePackageListener(target)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
OnePackageMessagePackageListener::~OnePackageMessagePackageListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
OnePackageMessagePackageListener::SetPackage(const PackageInfoRef& package)
|
||||
{
|
||||
if (fPackage == package)
|
||||
return;
|
||||
|
||||
PackageInfoListenerRef listener(this);
|
||||
|
||||
if (fPackage.IsSet())
|
||||
fPackage->RemoveListener(listener);
|
||||
|
||||
fPackage = package;
|
||||
|
||||
if (fPackage.IsSet())
|
||||
fPackage->AddListener(listener);
|
||||
}
|
||||
|
||||
|
||||
const PackageInfoRef&
|
||||
OnePackageMessagePackageListener::Package() const
|
||||
{
|
||||
return fPackage;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user