695 lines
12 KiB
C++
695 lines
12 KiB
C++
/*
|
|
* Copyright 2013, Stephan Aßmus <[email protected]>.
|
|
* All rights reserved. Distributed under the terms of the MIT License.
|
|
*/
|
|
|
|
#include "PackageInfo.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <Application.h>
|
|
#include <Bitmap.h>
|
|
#include <DataIO.h>
|
|
#include <IconUtils.h>
|
|
#include <MimeType.h>
|
|
#include <Resources.h>
|
|
|
|
#include "support.h"
|
|
|
|
|
|
// #pragma mark - SharedBitmap
|
|
|
|
|
|
SharedBitmap::SharedBitmap(BBitmap* bitmap)
|
|
:
|
|
BReferenceable(),
|
|
fResourceID(-1),
|
|
fMimeType()
|
|
{
|
|
fBitmap[0] = bitmap;
|
|
fBitmap[1] = NULL;
|
|
fBitmap[2] = NULL;
|
|
}
|
|
|
|
|
|
SharedBitmap::SharedBitmap(int32 resourceID)
|
|
:
|
|
BReferenceable(),
|
|
fResourceID(resourceID),
|
|
fMimeType()
|
|
{
|
|
fBitmap[0] = NULL;
|
|
fBitmap[1] = NULL;
|
|
fBitmap[2] = NULL;
|
|
}
|
|
|
|
|
|
SharedBitmap::SharedBitmap(const char* mimeType)
|
|
:
|
|
BReferenceable(),
|
|
fResourceID(-1),
|
|
fMimeType(mimeType)
|
|
{
|
|
fBitmap[0] = NULL;
|
|
fBitmap[1] = NULL;
|
|
fBitmap[2] = NULL;
|
|
}
|
|
|
|
|
|
SharedBitmap::~SharedBitmap()
|
|
{
|
|
delete fBitmap[0];
|
|
delete fBitmap[1];
|
|
delete fBitmap[2];
|
|
}
|
|
|
|
|
|
const BBitmap*
|
|
SharedBitmap::Bitmap(Size which)
|
|
{
|
|
if (fResourceID == -1 && fMimeType.Length() == 0)
|
|
return fBitmap[0];
|
|
|
|
int32 index = 0;
|
|
int32 size = 16;
|
|
|
|
switch (which) {
|
|
default:
|
|
case SIZE_16:
|
|
break;
|
|
|
|
case SIZE_32:
|
|
index = 1;
|
|
size = 32;
|
|
break;
|
|
case SIZE_64:
|
|
index = 2;
|
|
size = 64;
|
|
break;
|
|
}
|
|
|
|
if (fBitmap[index] == NULL) {
|
|
if (fResourceID >= 0)
|
|
fBitmap[index] = _CreateBitmapFromResource(size);
|
|
else if (fMimeType.Length() > 0)
|
|
fBitmap[index] = _CreateBitmapFromMimeType(size);
|
|
}
|
|
|
|
return fBitmap[index];
|
|
}
|
|
|
|
|
|
BBitmap*
|
|
SharedBitmap::_CreateBitmapFromResource(int32 size) const
|
|
{
|
|
BResources resources;
|
|
status_t status = get_app_resources(resources);
|
|
if (status != B_OK)
|
|
return NULL;
|
|
|
|
size_t dataSize;
|
|
const void* data = resources.LoadResource(B_VECTOR_ICON_TYPE, fResourceID,
|
|
&dataSize);
|
|
if (data != NULL) {
|
|
BBitmap* bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0,
|
|
B_RGBA32);
|
|
status = bitmap->InitCheck();
|
|
if (status == B_OK) {
|
|
status = BIconUtils::GetVectorIcon(
|
|
reinterpret_cast<const uint8*>(data), dataSize, bitmap);
|
|
};
|
|
|
|
if (status != B_OK) {
|
|
delete bitmap;
|
|
bitmap = NULL;
|
|
}
|
|
|
|
return bitmap;
|
|
}
|
|
|
|
data = resources.LoadResource(B_MESSAGE_TYPE, fResourceID, &dataSize);
|
|
if (data != NULL) {
|
|
BMemoryIO stream(data, dataSize);
|
|
|
|
// Try to read as an archived bitmap.
|
|
BMessage archive;
|
|
status = archive.Unflatten(&stream);
|
|
if (status != B_OK)
|
|
return NULL;
|
|
|
|
BBitmap* bitmap = new BBitmap(&archive);
|
|
|
|
status = bitmap->InitCheck();
|
|
if (status != B_OK) {
|
|
delete bitmap;
|
|
bitmap = NULL;
|
|
}
|
|
|
|
return bitmap;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
BBitmap*
|
|
SharedBitmap::_CreateBitmapFromMimeType(int32 size) const
|
|
{
|
|
BMimeType mimeType(fMimeType.String());
|
|
status_t status = mimeType.InitCheck();
|
|
if (status != B_OK)
|
|
return NULL;
|
|
|
|
BBitmap* bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0, B_RGBA32);
|
|
status = bitmap->InitCheck();
|
|
if (status == B_OK)
|
|
status = mimeType.GetIcon(bitmap, B_MINI_ICON);
|
|
|
|
if (status != B_OK) {
|
|
delete bitmap;
|
|
bitmap = NULL;
|
|
}
|
|
|
|
return bitmap;
|
|
}
|
|
|
|
|
|
// #pragma mark - UserInfo
|
|
|
|
|
|
UserInfo::UserInfo()
|
|
:
|
|
fAvatar(),
|
|
fNickName()
|
|
{
|
|
}
|
|
|
|
|
|
UserInfo::UserInfo(const BString& nickName)
|
|
:
|
|
fAvatar(),
|
|
fNickName(nickName)
|
|
{
|
|
}
|
|
|
|
|
|
UserInfo::UserInfo(const BitmapRef& avatar, const BString& nickName)
|
|
:
|
|
fAvatar(avatar),
|
|
fNickName(nickName)
|
|
{
|
|
}
|
|
|
|
|
|
UserInfo::UserInfo(const UserInfo& other)
|
|
:
|
|
fAvatar(other.fAvatar),
|
|
fNickName(other.fNickName)
|
|
{
|
|
}
|
|
|
|
|
|
UserInfo&
|
|
UserInfo::operator=(const UserInfo& other)
|
|
{
|
|
fAvatar = other.fAvatar;
|
|
fNickName = other.fNickName;
|
|
return *this;
|
|
}
|
|
|
|
|
|
bool
|
|
UserInfo::operator==(const UserInfo& other) const
|
|
{
|
|
return fAvatar == other.fAvatar
|
|
&& fNickName == other.fNickName;
|
|
}
|
|
|
|
|
|
bool
|
|
UserInfo::operator!=(const UserInfo& other) const
|
|
{
|
|
return !(*this == other);
|
|
}
|
|
|
|
|
|
// #pragma mark - UserRating
|
|
|
|
|
|
UserRating::UserRating()
|
|
:
|
|
fUserInfo(),
|
|
fRating(0.0f),
|
|
fComment(),
|
|
fLanguage(),
|
|
fPackageVersion(),
|
|
fUpVotes(0),
|
|
fDownVotes(0)
|
|
{
|
|
}
|
|
|
|
|
|
UserRating::UserRating(const UserInfo& userInfo, float rating,
|
|
const BString& comment, const BString& language,
|
|
const BString& packageVersion, int32 upVotes, int32 downVotes)
|
|
:
|
|
fUserInfo(userInfo),
|
|
fRating(rating),
|
|
fComment(comment),
|
|
fLanguage(language),
|
|
fPackageVersion(packageVersion),
|
|
fUpVotes(upVotes),
|
|
fDownVotes(downVotes)
|
|
{
|
|
}
|
|
|
|
|
|
UserRating::UserRating(const UserRating& other)
|
|
:
|
|
fUserInfo(other.fUserInfo),
|
|
fRating(other.fRating),
|
|
fComment(other.fComment),
|
|
fLanguage(other.fLanguage),
|
|
fPackageVersion(other.fPackageVersion),
|
|
fUpVotes(other.fUpVotes),
|
|
fDownVotes(other.fDownVotes)
|
|
{
|
|
}
|
|
|
|
|
|
UserRating&
|
|
UserRating::operator=(const UserRating& other)
|
|
{
|
|
fUserInfo = other.fUserInfo;
|
|
fRating = other.fRating;
|
|
fComment = other.fComment;
|
|
fLanguage = other.fLanguage;
|
|
fPackageVersion = other.fPackageVersion;
|
|
fUpVotes = other.fUpVotes;
|
|
fDownVotes = other.fDownVotes;
|
|
return *this;
|
|
}
|
|
|
|
|
|
bool
|
|
UserRating::operator==(const UserRating& other) const
|
|
{
|
|
return fUserInfo == other.fUserInfo
|
|
&& fRating == other.fRating
|
|
&& fComment == other.fComment
|
|
&& fLanguage == other.fLanguage
|
|
&& fPackageVersion == other.fPackageVersion
|
|
&& fUpVotes == other.fUpVotes
|
|
&& fDownVotes == other.fDownVotes;
|
|
}
|
|
|
|
|
|
bool
|
|
UserRating::operator!=(const UserRating& other) const
|
|
{
|
|
return !(*this == other);
|
|
}
|
|
|
|
|
|
// #pragma mark - PublisherInfo
|
|
|
|
|
|
PublisherInfo::PublisherInfo()
|
|
:
|
|
fLogo(),
|
|
fName(),
|
|
fEmail(),
|
|
fWebsite()
|
|
{
|
|
}
|
|
|
|
|
|
PublisherInfo::PublisherInfo(const BitmapRef& logo, const BString& name,
|
|
const BString& email, const BString& website)
|
|
:
|
|
fLogo(logo),
|
|
fName(name),
|
|
fEmail(email),
|
|
fWebsite(website)
|
|
{
|
|
}
|
|
|
|
|
|
PublisherInfo::PublisherInfo(const PublisherInfo& other)
|
|
:
|
|
fLogo(other.fLogo),
|
|
fName(other.fName),
|
|
fEmail(other.fEmail),
|
|
fWebsite(other.fWebsite)
|
|
{
|
|
}
|
|
|
|
|
|
PublisherInfo&
|
|
PublisherInfo::operator=(const PublisherInfo& other)
|
|
{
|
|
fLogo = other.fLogo;
|
|
fName = other.fName;
|
|
fEmail = other.fEmail;
|
|
fWebsite = other.fWebsite;
|
|
return *this;
|
|
}
|
|
|
|
|
|
bool
|
|
PublisherInfo::operator==(const PublisherInfo& other) const
|
|
{
|
|
return fLogo == other.fLogo
|
|
&& fName == other.fName
|
|
&& fEmail == other.fEmail
|
|
&& fWebsite == other.fWebsite;
|
|
}
|
|
|
|
|
|
bool
|
|
PublisherInfo::operator!=(const PublisherInfo& other) const
|
|
{
|
|
return !(*this == other);
|
|
}
|
|
|
|
|
|
// #pragma mark - PackageCategory
|
|
|
|
|
|
PackageCategory::PackageCategory()
|
|
:
|
|
BReferenceable(),
|
|
fIcon(),
|
|
fName()
|
|
{
|
|
}
|
|
|
|
|
|
PackageCategory::PackageCategory(const BitmapRef& icon, const BString& label,
|
|
const BString& name)
|
|
:
|
|
BReferenceable(),
|
|
fIcon(icon),
|
|
fLabel(label),
|
|
fName(name)
|
|
{
|
|
}
|
|
|
|
|
|
PackageCategory::PackageCategory(const PackageCategory& other)
|
|
:
|
|
BReferenceable(),
|
|
fIcon(other.fIcon),
|
|
fLabel(other.fLabel),
|
|
fName(other.fName)
|
|
{
|
|
}
|
|
|
|
|
|
PackageCategory&
|
|
PackageCategory::operator=(const PackageCategory& other)
|
|
{
|
|
fIcon = other.fIcon;
|
|
fName = other.fName;
|
|
fLabel = other.fLabel;
|
|
return *this;
|
|
}
|
|
|
|
|
|
bool
|
|
PackageCategory::operator==(const PackageCategory& other) const
|
|
{
|
|
return fIcon == other.fIcon
|
|
&& fLabel == other.fLabel
|
|
&& fName == other.fName;
|
|
}
|
|
|
|
|
|
bool
|
|
PackageCategory::operator!=(const PackageCategory& other) const
|
|
{
|
|
return !(*this == other);
|
|
}
|
|
|
|
|
|
// #pragma mark - PackageInfo
|
|
|
|
|
|
PackageInfo::PackageInfo()
|
|
:
|
|
fIcon(),
|
|
fTitle(),
|
|
fVersion(),
|
|
fPublisher(),
|
|
fShortDescription(),
|
|
fFullDescription(),
|
|
fChangelog(),
|
|
fUserRatings(),
|
|
fScreenshots()
|
|
{
|
|
}
|
|
|
|
|
|
PackageInfo::PackageInfo(const BitmapRef& icon, const BString& title,
|
|
const BString& version, const PublisherInfo& publisher,
|
|
const BString& shortDescription, const BString& fullDescription,
|
|
const BString& changelog)
|
|
:
|
|
fIcon(icon),
|
|
fTitle(title),
|
|
fVersion(version),
|
|
fPublisher(publisher),
|
|
fShortDescription(shortDescription),
|
|
fFullDescription(fullDescription),
|
|
fChangelog(changelog),
|
|
fCategories(),
|
|
fUserRatings(),
|
|
fScreenshots()
|
|
{
|
|
}
|
|
|
|
|
|
PackageInfo::PackageInfo(const PackageInfo& other)
|
|
:
|
|
fIcon(other.fIcon),
|
|
fTitle(other.fTitle),
|
|
fVersion(other.fVersion),
|
|
fPublisher(other.fPublisher),
|
|
fShortDescription(other.fShortDescription),
|
|
fFullDescription(other.fFullDescription),
|
|
fChangelog(other.fChangelog),
|
|
fCategories(other.fCategories),
|
|
fUserRatings(other.fUserRatings),
|
|
fScreenshots(other.fScreenshots)
|
|
{
|
|
}
|
|
|
|
|
|
PackageInfo&
|
|
PackageInfo::operator=(const PackageInfo& other)
|
|
{
|
|
fIcon = other.fIcon;
|
|
fTitle = other.fTitle;
|
|
fVersion = other.fVersion;
|
|
fPublisher = other.fPublisher;
|
|
fShortDescription = other.fShortDescription;
|
|
fFullDescription = other.fFullDescription;
|
|
fChangelog = other.fChangelog;
|
|
fCategories = other.fCategories;
|
|
fUserRatings = other.fUserRatings;
|
|
fScreenshots = other.fScreenshots;
|
|
return *this;
|
|
}
|
|
|
|
|
|
bool
|
|
PackageInfo::operator==(const PackageInfo& other) const
|
|
{
|
|
return fIcon == other.fIcon
|
|
&& fTitle == other.fTitle
|
|
&& fVersion == other.fVersion
|
|
&& fPublisher == other.fPublisher
|
|
&& fShortDescription == other.fShortDescription
|
|
&& fFullDescription == other.fFullDescription
|
|
&& fChangelog == other.fChangelog
|
|
&& fCategories == other.fCategories
|
|
&& fUserRatings == other.fUserRatings
|
|
&& fScreenshots == other.fScreenshots;
|
|
}
|
|
|
|
|
|
bool
|
|
PackageInfo::operator!=(const PackageInfo& other) const
|
|
{
|
|
return !(*this == other);
|
|
}
|
|
|
|
|
|
bool
|
|
PackageInfo::AddCategory(const CategoryRef& category)
|
|
{
|
|
return fCategories.Add(category);
|
|
}
|
|
|
|
|
|
bool
|
|
PackageInfo::AddUserRating(const UserRating& rating)
|
|
{
|
|
if (!fUserRatings.Add(rating))
|
|
return false;
|
|
|
|
_NotifyListeners(PKG_CHANGED_RATINGS);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
RatingSummary
|
|
PackageInfo::CalculateRatingSummary() const
|
|
{
|
|
RatingSummary summary;
|
|
summary.ratingCount = fUserRatings.CountItems();
|
|
summary.averageRating = 0.0f;
|
|
int starRatingCount = sizeof(summary.ratingCountByStar) / sizeof(int);
|
|
for (int i = 0; i < starRatingCount; i++)
|
|
summary.ratingCountByStar[i] = 0;
|
|
|
|
if (summary.ratingCount <= 0)
|
|
return summary;
|
|
|
|
float ratingSum = 0.0f;
|
|
|
|
for (int i = 0; i < summary.ratingCount; i++) {
|
|
float rating = fUserRatings.ItemAtFast(i).Rating();
|
|
|
|
if (rating < 0.0f)
|
|
rating = 0.0f;
|
|
else if (rating > 5.0f)
|
|
rating = 5.0f;
|
|
|
|
ratingSum += rating;
|
|
|
|
if (rating <= 1.0f)
|
|
summary.ratingCountByStar[0]++;
|
|
else if (rating <= 2.0f)
|
|
summary.ratingCountByStar[1]++;
|
|
else if (rating <= 3.0f)
|
|
summary.ratingCountByStar[2]++;
|
|
else if (rating <= 4.0f)
|
|
summary.ratingCountByStar[3]++;
|
|
else if (rating <= 5.0f)
|
|
summary.ratingCountByStar[4]++;
|
|
}
|
|
|
|
summary.averageRating = ratingSum / summary.ratingCount;
|
|
return summary;
|
|
}
|
|
|
|
|
|
bool
|
|
PackageInfo::AddScreenshot(const BitmapRef& screenshot)
|
|
{
|
|
if (!fScreenshots.Add(screenshot))
|
|
return false;
|
|
|
|
_NotifyListeners(PKG_CHANGED_SCREENSHOTS);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool
|
|
PackageInfo::AddListener(const PackageInfoListenerRef& listener)
|
|
{
|
|
return fListeners.Add(listener);
|
|
}
|
|
|
|
|
|
void
|
|
PackageInfo::RemoveListener(const PackageInfoListenerRef& listener)
|
|
{
|
|
fListeners.Remove(listener);
|
|
}
|
|
|
|
|
|
void
|
|
PackageInfo::_NotifyListeners(uint32 changes)
|
|
{
|
|
int count = fListeners.CountItems();
|
|
if (count == 0)
|
|
return;
|
|
|
|
// Clone list to avoid listeners detaching themselves in notifications
|
|
// to screw up the list while iterating it.
|
|
PackageListenerList listeners(fListeners);
|
|
// Check if it worked:
|
|
if (listeners.CountItems () != count)
|
|
return;
|
|
|
|
PackageInfoEvent event(PackageInfoRef(this), changes);
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
const PackageInfoListenerRef& listener = listeners.ItemAtFast(i);
|
|
if (listener.Get() != NULL)
|
|
listener->PackageChanged(event);
|
|
}
|
|
}
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
DepotInfo::DepotInfo()
|
|
:
|
|
fName(),
|
|
fPackages()
|
|
{
|
|
}
|
|
|
|
|
|
DepotInfo::DepotInfo(const BString& name)
|
|
:
|
|
fName(name),
|
|
fPackages()
|
|
{
|
|
}
|
|
|
|
|
|
DepotInfo::DepotInfo(const DepotInfo& other)
|
|
:
|
|
fName(other.fName),
|
|
fPackages(other.fPackages)
|
|
{
|
|
}
|
|
|
|
|
|
DepotInfo&
|
|
DepotInfo::operator=(const DepotInfo& other)
|
|
{
|
|
fName = other.fName;
|
|
fPackages = other.fPackages;
|
|
return *this;
|
|
}
|
|
|
|
|
|
bool
|
|
DepotInfo::operator==(const DepotInfo& other) const
|
|
{
|
|
return fName == other.fName
|
|
&& fPackages == other.fPackages;
|
|
}
|
|
|
|
|
|
bool
|
|
DepotInfo::operator!=(const DepotInfo& other) const
|
|
{
|
|
return !(*this == other);
|
|
}
|
|
|
|
|
|
bool
|
|
DepotInfo::AddPackage(const PackageInfoRef& package)
|
|
{
|
|
return fPackages.Add(package);
|
|
}
|