Merge pull request #1576 from csoler/v0.6-ImprovedGUI

attempt to use a cache for user-defined avatars. Should reduce memory…
This commit is contained in:
csoler 2019-06-18 09:17:03 +02:00 committed by GitHub
commit 2f81b11dee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 254 additions and 209 deletions

View File

@ -322,8 +322,8 @@ void ChatLobbyWidget::lobbyTreeWidgetCustomPopupMenu(QPoint)
QPixmap pixmap ;
if(idd.mAvatar.mSize == 0 || !pixmap.loadFromData(idd.mAvatar.mData, idd.mAvatar.mSize, "PNG"))
pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(*it)) ;
if(idd.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idd.mAvatar.mData, idd.mAvatar.mSize, pixmap, GxsIdDetails::SMALL))
pixmap = GxsIdDetails::makeDefaultIcon(*it,GxsIdDetails::SMALL) ;
QAction *action = mnu->addAction(QIcon(pixmap), QString("%1 (%2)").arg(QString::fromUtf8(idd.mNickname.c_str()), QString::fromStdString((*it).toStdString())), this, SLOT(subscribeChatLobbyAs()));
action->setData(QString::fromStdString((*it).toStdString())) ;

View File

@ -270,8 +270,8 @@ void CreateCircleDialog::addMember(const RsGxsIdGroup &idGroup)
QPixmap pixmap ;
if(idGroup.mImage.mSize == 0 || !pixmap.loadFromData(idGroup.mImage.mData, idGroup.mImage.mSize, "PNG"))
pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(RsGxsId(idGroup.mMeta.mGroupId)));
if(idGroup.mImage.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idGroup.mImage.mData, idGroup.mImage.mSize, pixmap, GxsIdDetails::SMALL))
pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(idGroup.mMeta.mGroupId),GxsIdDetails::SMALL);
if (idGroup.mPgpKnown){
RsPeerDetails details;
@ -331,8 +331,8 @@ void CreateCircleDialog::addCircle(const RsGxsCircleDetails &cirDetails)
QPixmap pixmap ;
if(gxs_details.mAvatar.mSize == 0 || !pixmap.loadFromData(gxs_details.mAvatar.mData, gxs_details.mAvatar.mSize, "PNG"))
pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(gxs_details.mId));
if(gxs_details.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(gxs_details.mAvatar.mData, gxs_details.mAvatar.mSize, pixmap, GxsIdDetails::SMALL))
pixmap = GxsIdDetails::makeDefaultIcon(gxs_details.mId,GxsIdDetails::SMALL);
addMember(keyId, idtype, nickname, QIcon(pixmap));
@ -814,8 +814,8 @@ void CreateCircleDialog::loadIdentities(uint32_t token)
QPixmap pixmap ;
if(idGroup.mImage.mSize == 0 || !pixmap.loadFromData(idGroup.mImage.mData, idGroup.mImage.mSize, "PNG"))
pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(RsGxsId(idGroup.mMeta.mGroupId))) ;
if(idGroup.mImage.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idGroup.mImage.mData, idGroup.mImage.mSize, pixmap, GxsIdDetails::SMALL))
pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(idGroup.mMeta.mGroupId),GxsIdDetails::SMALL) ;
if (idGroup.mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID_kept_for_compatibility)
{

View File

@ -183,11 +183,11 @@ void IdDetailsDialog::insertIdDetails(uint32_t token)
QPixmap pixmap;
if(data.mImage.mSize > 0 && pixmap.loadFromData(data.mImage.mData, data.mImage.mSize, "PNG"))
ui->avatarLabel->setPixmap(pixmap) ;
if(data.mImage.mSize > 0 && GxsIdDetails::loadPixmapFromData(data.mImage.mData, data.mImage.mSize, pixmap, GxsIdDetails::LARGE))
ui->avatarLabel->setPixmap(pixmap);
else
{
pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId)) ) ;
pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId),GxsIdDetails::LARGE) ;
ui->avatarLabel->setPixmap(pixmap) ; // we need to use the default pixmap here, generated from the ID
}

View File

@ -752,8 +752,8 @@ void IdDialog::loadCircleGroupMeta(const uint32_t &token)
QPixmap pixmap ;
if(idd.mAvatar.mSize == 0 || !pixmap.loadFromData(idd.mAvatar.mData, idd.mAvatar.mSize, "PNG"))
pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(it->first)) ;
if(idd.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idd.mAvatar.mData, idd.mAvatar.mSize, pixmap,GxsIdDetails::SMALL))
pixmap = GxsIdDetails::makeDefaultIcon(it->first,GxsIdDetails::SMALL) ;
if(has_id)
subitem->setText(CIRCLEGROUP_CIRCLE_COL_GROUPNAME, QString::fromUtf8(idd.mNickname.c_str())) ;
@ -1551,8 +1551,8 @@ bool IdDialog::fillIdListItem(const RsGxsIdGroup& data, QTreeWidgetItem *&item,
QPixmap pixmap ;
if(data.mImage.mSize == 0 || !pixmap.loadFromData(data.mImage.mData, data.mImage.mSize, "PNG"))
pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId))) ;
if(data.mImage.mSize == 0 || !GxsIdDetails::loadPixmapFromData(data.mImage.mData, data.mImage.mSize, pixmap,GxsIdDetails::SMALL))
pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId),GxsIdDetails::SMALL) ;
item->setIcon(RSID_COL_NICKNAME, QIcon(pixmap));
@ -1797,8 +1797,8 @@ void IdDialog::insertIdDetails(uint32_t token)
QPixmap pixmap ;
if(data.mImage.mSize == 0 || !pixmap.loadFromData(data.mImage.mData, data.mImage.mSize, "PNG"))
pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId))) ;
if(data.mImage.mSize == 0 || !GxsIdDetails::loadPixmapFromData(data.mImage.mData, data.mImage.mSize, pixmap,GxsIdDetails::LARGE))
pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId),GxsIdDetails::LARGE) ;
#ifdef ID_DEBUG
std::cerr << "Setting header frame image : " << pixmap.width() << " x " << pixmap.height() << std::endl;
@ -2470,8 +2470,8 @@ void IdDialog::IdListCustomPopupMenu( QPoint )
QPixmap pixmap ;
if(idd.mAvatar.mSize == 0 || !pixmap.loadFromData(idd.mAvatar.mData, idd.mAvatar.mSize, "PNG"))
pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(*it)) ;
if(idd.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idd.mAvatar.mData, idd.mAvatar.mSize, pixmap,GxsIdDetails::SMALL))
pixmap = GxsIdDetails::makeDefaultIcon(*it,GxsIdDetails::SMALL) ;
QAction *action = mnu->addAction(QIcon(pixmap), QString("%1 (%2)").arg(QString::fromUtf8(idd.mNickname.c_str()), QString::fromStdString((*it).toStdString())), this, SLOT(chatIdentity()));
action->setData(QString::fromStdString((*it).toStdString())) ;

View File

@ -195,7 +195,7 @@ void IdEditDialog::setAvatar(const QPixmap &avatar)
ui->avatarLabel->setPixmap(mAvatar);
} else {
// we need to use the default pixmap here, generated from the ID
ui->avatarLabel->setPixmap(QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(RsGxsId(mEditGroup.mMeta.mGroupId))));
ui->avatarLabel->setPixmap(GxsIdDetails::makeDefaultIcon(RsGxsId(mEditGroup.mMeta.mGroupId)));
}
}
@ -257,9 +257,8 @@ void IdEditDialog::loadExistingId(uint32_t token)
mGroupId = mEditGroup.mMeta.mGroupId;
QPixmap avatar;
if (mEditGroup.mImage.mSize > 0) {
avatar.loadFromData(mEditGroup.mImage.mData, mEditGroup.mImage.mSize, "PNG");
}
if (mEditGroup.mImage.mSize > 0)
GxsIdDetails::loadPixmapFromData(mEditGroup.mImage.mData, mEditGroup.mImage.mSize, avatar,GxsIdDetails::LARGE);
setAvatar(avatar);

View File

@ -100,7 +100,8 @@ void IdentityWidget::updateData(const RsGxsIdGroup &gxs_group_info)
ui->labelPositive->setText(QString::number(info.mFriendsPositiveVotes));
ui->labelNegative->setText(QString::number(info.mFriendsNegativeVotes));
if (!_havePGPDetail) {
if (!_havePGPDetail)
{
QFont font = ui->labelName->font();
font.setItalic(false);
ui->labelName->setFont(font);
@ -111,20 +112,16 @@ void IdentityWidget::updateData(const RsGxsIdGroup &gxs_group_info)
ui->labelKeyId->setVisible(false);
/// (TODO) Get real ident icon
QImage image;
QPixmap pixmap;
if(!( (_group_info.mImage.mSize > 0) && image.loadFromData(_group_info.mImage.mData, _group_info.mImage.mSize, "PNG") ))
image = GxsIdDetails::makeDefaultIcon(RsGxsId(_group_info.mMeta.mGroupId));
if (_avatar != image) {
_avatar = image;
_scene->clear();
_scene->addPixmap(QPixmap::fromImage(image.scaled(ui->graphicsView->width(),ui->graphicsView->height())));
emit imageUpdated();
}//if (_avatar != image)
}//if (!_havePGPDetail)
if(!( (_group_info.mImage.mSize > 0) && GxsIdDetails::loadPixmapFromData(_group_info.mImage.mData, _group_info.mImage.mSize, pixmap) ))
pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(_group_info.mMeta.mGroupId));
//}//if (_group_info != gxs_group_info)
_avatar = pixmap.toImage();
_scene->clear();
_scene->addPixmap(pixmap.scaled(ui->graphicsView->width(),ui->graphicsView->height()));
emit imageUpdated();
}
}
void IdentityWidget::updateData(const RsPeerDetails &pgp_details)
@ -136,12 +133,10 @@ void IdentityWidget::updateData(const RsPeerDetails &pgp_details)
_nickname = QString::fromUtf8(_details.name.c_str());
if (!_haveGXSId) m_myName = _nickname;
ui->labelName->setText(m_myName);
if (_haveGXSId) {
ui->labelName->setToolTip(tr("GXS name:") + (" "+m_myName) + ("\n")
+(tr("PGP name:")+(" "+_nickname)));
} else {//if (m_myName != _nickname)
if (_haveGXSId)
ui->labelName->setToolTip(tr("GXS name:") + (" "+m_myName) + ("\n") +(tr("PGP name:")+(" "+_nickname)));
else
ui->labelName->setToolTip(tr("PGP name:")+(" "+_nickname));
}//else (m_myName != _nickname)
QFont font = ui->labelName->font();
font.setItalic(true);
@ -210,11 +205,6 @@ void IdentityWidget::setIsSelected(bool value)
font.setBold(value);
ui->labelName->setFont(font);
}
/*
bool IdentityWidget::isSelected()
{
return m_isSelected;
}*/
void IdentityWidget::setIsCurrent(bool value)
{
@ -227,11 +217,6 @@ void IdentityWidget::setIsCurrent(bool value)
ui->label_NegIcon_2->setVisible(value);
ui->pbAdd->setVisible(value);
}
/*
bool IdentityWidget::isCurrent()
{
return m_isCurrent;
}*/
void IdentityWidget::pbAdd_clicked()
{

View File

@ -426,15 +426,15 @@ void PeopleDialog::iw_AddButtonClickedExt()
{
IdentityWidget *dest=
qobject_cast<IdentityWidget *>(QObject::sender());
if (dest) {
if (dest)
{
QMenu contextMnu( this );
QMenu *mnu = contextMnu.addMenu(QIcon(":/icons/png/circles.png"),tr("Invite to Circle")) ;
std::map<RsGxsGroupId, CircleWidget*>::iterator itCurs;
for( itCurs =_ext_circles_widgets.begin();
itCurs != _ext_circles_widgets.end();
++itCurs) {
for( itCurs =_ext_circles_widgets.begin(); itCurs != _ext_circles_widgets.end(); ++itCurs)
{
CircleWidget *curs = itCurs->second;
QIcon icon = QIcon(curs->getImage());
QString name = curs->getName();
@ -442,7 +442,7 @@ void PeopleDialog::iw_AddButtonClickedExt()
QAction *action = mnu->addAction(icon, name, this, SLOT(addToCircleExt()));
action->setData(QString::fromStdString(curs->groupInfo().mGroupId.toStdString())
+ ";" + QString::fromStdString(dest->groupInfo().mMeta.mGroupId.toStdString()));
}//for( itCurs =_ext_circles_widgets.begin();
}
std::list<RsGxsId> own_identities ;
rsIdentity->getOwnIds(own_identities) ;
@ -467,8 +467,8 @@ void PeopleDialog::iw_AddButtonClickedExt()
QPixmap pixmap ;
if(idd.mAvatar.mSize == 0 || !pixmap.loadFromData(idd.mAvatar.mData, idd.mAvatar.mSize, "PNG"))
pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(*it)) ;
if(idd.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idd.mAvatar.mData, idd.mAvatar.mSize, pixmap,GxsIdDetails::SMALL))
pixmap = GxsIdDetails::makeDefaultIcon(*it,GxsIdDetails::SMALL) ;
QAction *action = mnu->addAction(QIcon(pixmap), QString("%1 (%2)").arg(QString::fromUtf8(idd.mNickname.c_str()), QString::fromStdString((*it).toStdString())), this, SLOT(chatIdentity()));
action->setData(QString::fromStdString((*it).toStdString()) + ";" + QString::fromStdString(dest->groupInfo().mMeta.mGroupId.toStdString())) ;
@ -492,7 +492,7 @@ void PeopleDialog::iw_AddButtonClickedExt()
actionDetails->setData( QString::fromStdString(dest->groupInfo().mMeta.mGroupId.toStdString()));
contextMnu.exec(QCursor::pos());
}//if (dest)
}
}
void PeopleDialog::iw_AddButtonClickedInt()
@ -513,10 +513,10 @@ void PeopleDialog::iw_AddButtonClickedInt()
QAction *action = contextMnu.addAction(icon, name, this, SLOT(addToCircleInt()));
action->setData(QString::fromStdString(curs->groupInfo().mGroupId.toStdString())
+ ";" + QString::fromStdString(dest->details().gpg_id.toStdString()));
}//for( itCurs =_int_circles_widgets.begin();
}
contextMnu.exec(QCursor::pos());
}//if (dest)
}
}
void PeopleDialog::addToCircleExt()

View File

@ -21,6 +21,7 @@
#include <QPixmap>
#include "AlbumDialog.h"
#include "gui/gxs/GxsIdDetails.h"
#include "ui_AlbumDialog.h"
#include "retroshare/rsgxsflags.h"
@ -60,7 +61,7 @@ void AlbumDialog::setUp()
QPixmap qtn;
qtn.loadFromData(mAlbum.mThumbnail.data, mAlbum.mThumbnail.size, mAlbum.mThumbnail.type.c_str());
GxsIdDetails::loadPixmapFromData(mAlbum.mThumbnail.data, mAlbum.mThumbnail.size, mAlbum.mThumbnail.type.c_str(),qtn);
if(mAlbum.mThumbnail.size != 0)
{

View File

@ -165,7 +165,7 @@ void PostedDialog::loadGroupSummaryToken(const uint32_t &token, std::list<RsGrou
if (group.mGroupImage.mData != NULL) {
QPixmap image;
image.loadFromData(group.mGroupImage.mData, group.mGroupImage.mSize, "PNG");
GxsIdDetails::loadPixmapFromData(group.mGroupImage.mData, group.mGroupImage.mSize, image,GxsIdDetails::ORIGINAL);
postedData->mIcon[group.mMeta.mGroupId] = image;
}

View File

@ -20,6 +20,7 @@
#include <QBuffer>
#include "PostedGroupDialog.h"
#include "gui/gxs/GxsIdDetails.h"
#include <retroshare/rswiki.h>
#include <iostream>
@ -163,9 +164,9 @@ bool PostedGroupDialog::service_loadGroup(uint32_t token, Mode /*mode*/, RsGroup
if (group.mGroupImage.mData) {
QPixmap pixmap;
if (pixmap.loadFromData(group.mGroupImage.mData, group.mGroupImage.mSize, "PNG")) {
if (GxsIdDetails::loadPixmapFromData(group.mGroupImage.mData, group.mGroupImage.mSize, pixmap,GxsIdDetails::ORIGINAL))
setLogo(pixmap);
}
} else {
setLogo(QPixmap(":/icons/png/posted.png"));
}

View File

@ -25,6 +25,7 @@
#include "rshare.h"
#include "PostedItem.h"
#include "gui/feeds/FeedHolder.h"
#include "gui/gxs/GxsIdDetails.h"
#include "util/misc.h"
#include "ui_PostedItem.h"
@ -255,7 +256,7 @@ void PostedItem::fill()
if(mPost.mImage.mData != NULL)
{
QPixmap pixmap;
pixmap.loadFromData(mPost.mImage.mData, mPost.mImage.mSize, "PNG");
GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL);
// Wiping data - as its been passed to thumbnail.
QPixmap sqpixmap = pixmap.scaled(desired_width,desired_height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);

View File

@ -41,7 +41,7 @@ void AvatarDefs::getOwnAvatar(QPixmap &avatar, const QString& defaultImage)
}
/* load image */
avatar.loadFromData(data, size, "PNG") ;
GxsIdDetails::loadPixmapFromData(data, size, avatar,GxsIdDetails::ORIGINAL) ;
free(data);
}
@ -58,7 +58,7 @@ void AvatarDefs::getAvatarFromSslId(const RsPeerId& sslId, QPixmap &avatar, cons
}
/* load image */
avatar.loadFromData(data, size, "PNG") ;
GxsIdDetails::loadPixmapFromData(data, size, avatar, GxsIdDetails::LARGE) ;
free(data);
}
@ -77,8 +77,8 @@ void AvatarDefs::getAvatarFromGxsId(const RsGxsId& gxsId, QPixmap &avatar, const
/* load image */
if(details.mAvatar.mSize == 0 || !avatar.loadFromData(details.mAvatar.mData, details.mAvatar.mSize, "PNG"))
avatar = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(gxsId));
if(details.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(details.mAvatar.mData, details.mAvatar.mSize, avatar,GxsIdDetails::LARGE))
avatar = GxsIdDetails::makeDefaultIcon(gxsId,GxsIdDetails::LARGE);
}
void AvatarDefs::getAvatarFromGpgId(const RsPgpId& gpgId, QPixmap &avatar, const QString& defaultImage)
@ -109,7 +109,7 @@ void AvatarDefs::getAvatarFromGpgId(const RsPgpId& gpgId, QPixmap &avatar, const
}
/* load image */
avatar.loadFromData(data, size, "PNG") ;
GxsIdDetails::loadPixmapFromData(data, size, avatar);
free(data);
}

View File

@ -45,6 +45,9 @@ AvatarDialog::AvatarDialog(QWidget *parent) :
updateInterface();
}
const int AvatarDialog::RS_AVATAR_DEFAULT_IMAGE_W = 64;
const int AvatarDialog::RS_AVATAR_DEFAULT_IMAGE_H = 64;
AvatarDialog::~AvatarDialog()
{
delete(ui);
@ -52,7 +55,7 @@ AvatarDialog::~AvatarDialog()
void AvatarDialog::changeAvatar()
{
QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load Avatar"), 128, 128);
QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load Avatar"), RS_AVATAR_DEFAULT_IMAGE_W,RS_AVATAR_DEFAULT_IMAGE_H);
if (img.isNull())
return;

View File

@ -35,6 +35,9 @@ class AvatarDialog : public QDialog
Q_OBJECT
public:
static const int RS_AVATAR_DEFAULT_IMAGE_W ;
static const int RS_AVATAR_DEFAULT_IMAGE_H ;
AvatarDialog(QWidget *parent = 0);
~AvatarDialog();

View File

@ -18,6 +18,7 @@
* *
*******************************************************************************/
#include "gui/gxs/GxsIdDetails.h"
#include "GxsChannelGroupItem.h"
#include "ui_GxsChannelGroupItem.h"
@ -134,7 +135,7 @@ void GxsChannelGroupItem::fill()
if (mGroup.mImage.mData != NULL) {
QPixmap chanImage;
chanImage.loadFromData(mGroup.mImage.mData, mGroup.mImage.mSize, "PNG");
GxsIdDetails::loadPixmapFromData(mGroup.mImage.mData, mGroup.mImage.mSize, chanImage,GxsIdDetails::ORIGINAL);
ui->logoLabel->setPixmap(QPixmap(chanImage));
}

View File

@ -22,6 +22,7 @@
#include <QFileInfo>
#include <QStyle>
#include "gui/gxs/GxsIdDetails.h"
#include "rshare.h"
#include "GxsChannelPostItem.h"
#include "ui_GxsChannelPostItem.h"
@ -392,7 +393,7 @@ void GxsChannelPostItem::fill()
if(mPost.mThumbnail.mData != NULL)
{
QPixmap thumbnail;
thumbnail.loadFromData(mPost.mThumbnail.mData, mPost.mThumbnail.mSize, "PNG");
GxsIdDetails::loadPixmapFromData(mPost.mThumbnail.mData, mPost.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL);
// Wiping data - as its been passed to thumbnail.
ui->logoLabel->setPixmap(thumbnail);
}

View File

@ -23,6 +23,7 @@
#include "FeedHolder.h"
#include "gui/RetroShareLink.h"
#include "gui/gxs/GxsIdDetails.h"
/****
* #define DEBUG_ITEM 1
@ -137,7 +138,7 @@ void PostedGroupItem::fill()
if (mGroup.mGroupImage.mData != NULL) {
QPixmap postedImage;
postedImage.loadFromData(mGroup.mGroupImage.mData, mGroup.mGroupImage.mSize, "PNG");
GxsIdDetails::loadPixmapFromData(mGroup.mGroupImage.mData, mGroup.mGroupImage.mSize, postedImage,GxsIdDetails::ORIGINAL);
ui->logoLabel->setPixmap(QPixmap(postedImage));
} else {
ui->logoLabel->setPixmap(QPixmap(":/images/posted_64.png"));

View File

@ -24,6 +24,8 @@
#include <QMutexLocker>
#include <math.h>
#include <util/rsdir.h>
#include "gui/common/AvatarDialog.h"
#include "GxsIdDetails.h"
#include "retroshare-gui/RsAutoUpdatePage.h"
@ -66,10 +68,13 @@
uint32_t GxsIdDetails::mImagesAllocated = 0;
time_t GxsIdDetails::mLastIconCacheCleaning = time(NULL);
std::map<RsGxsId,std::pair<time_t,QImage> > GxsIdDetails::mDefaultIconCache ;
std::map<RsGxsId,std::pair<time_t,QPixmap>[4] > GxsIdDetails::mDefaultIconCache ;
#define ICON_CACHE_STORAGE_TIME 600
#define DELAY_BETWEEN_ICON_CACHE_CLEANING 300
QMutex GxsIdDetails::mMutex;
QMutex GxsIdDetails::mIconCacheMutex;
#define ICON_CACHE_STORAGE_TIME 240
#define DELAY_BETWEEN_ICON_CACHE_CLEANING 120
void ReputationItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
@ -184,7 +189,8 @@ void GxsIdDetails::timerEvent(QTimerEvent *event)
killTimer(mCheckTimerId);
mCheckTimerId = 0;
if (rsIdentity) {
if (rsIdentity)
{
QMutexLocker lock(&mMutex);
if (mProcessDisableCount == 0) {
@ -236,14 +242,14 @@ void GxsIdDetails::timerEvent(QTimerEvent *event)
}
}
QMutexLocker lock(&mMutex);
bool empty = false ;
{
QMutexLocker lock(&mMutex);
empty = mPendingData.empty();
}
if (mPendingData.empty()) {
/* All done */
} else {
/* Start timer */
if (!empty) /* Start timer */
doStartTimer();
}
}
}
@ -266,7 +272,7 @@ void GxsIdDetails::enableProcess(bool enable)
return;
}
QMutexLocker lock(&mInstance->mMutex);
QMutexLocker lock(&mMutex);
if (enable) {
--mInstance->mProcessDisableCount;
@ -292,7 +298,7 @@ bool GxsIdDetails::process(const RsGxsId &id, GxsIdDetailsCallbackFunction callb
// remove any existing call for this object. This is needed for when the same widget is used to display IDs that vary in time.
{
QMutexLocker lock(&mInstance->mMutex);
QMutexLocker lock(&mMutex);
// check if a pending request is not already on its way. If so, replace it.
@ -339,7 +345,7 @@ bool GxsIdDetails::process(const RsGxsId &id, GxsIdDetailsCallbackFunction callb
pendingData.mData = data;
{
QMutexLocker lock(&mInstance->mMutex);
QMutexLocker lock(&mMutex);
// check if a pending request is not already on its way. If so, replace it.
@ -376,79 +382,6 @@ static bool findTagIcon(int tag_class, int /*tag_type*/, QIcon &icon)
return true;
}
//QImage GxsIdDetails::makeDefaultIcon(const RsGxsId& id)
//{
// static std::map<RsGxsId,QImage> image_cache ;
//
// std::map<RsGxsId,QImage>::const_iterator it = image_cache.find(id) ;
//
// if(it != image_cache.end())
// return it->second ;
//
// int S = 128 ;
// QImage pix(S,S,QImage::Format_RGB32) ;
//
// uint64_t n = reinterpret_cast<const uint64_t*>(id.toByteArray())[0] ;
//
// uint8_t a[8] ;
// for(int i=0;i<8;++i)
// {
// a[i] = n&0xff ;
// n >>= 8 ;
// }
// QColor val[16] = {
// QColor::fromRgb( 255, 110, 180),
// QColor::fromRgb( 238, 92, 66),
// QColor::fromRgb( 255, 127, 36),
// QColor::fromRgb( 255, 193, 193),
// QColor::fromRgb( 127, 255, 212),
// QColor::fromRgb( 0, 255, 255),
// QColor::fromRgb( 224, 255, 255),
// QColor::fromRgb( 199, 21, 133),
// QColor::fromRgb( 50, 205, 50),
// QColor::fromRgb( 107, 142, 35),
// QColor::fromRgb( 30, 144, 255),
// QColor::fromRgb( 95, 158, 160),
// QColor::fromRgb( 143, 188, 143),
// QColor::fromRgb( 233, 150, 122),
// QColor::fromRgb( 151, 255, 255),
// QColor::fromRgb( 162, 205, 90),
// };
//
// int c1 = (a[0]^a[1]) & 0xf ;
// int c2 = (a[1]^a[2]) & 0xf ;
// int c3 = (a[2]^a[3]) & 0xf ;
// int c4 = (a[3]^a[4]) & 0xf ;
//
// for(int i=0;i<S/2;++i)
// for(int j=0;j<S/2;++j)
// {
// float res1 = 0.0f ;
// float res2 = 0.0f ;
// float f = 1.70;
//
// for(int k1=0;k1<4;++k1)
// for(int k2=0;k2<4;++k2)
// {
// res1 += cos( (2*M_PI*i/(float)S) * k1 * f) * (a[k1 ] & 0xf) + sin( (2*M_PI*j/(float)S) * k2 * f) * (a[k2 ] >> 4) + sin( (2*M_PI*i/(float)S) * k1 * f) * cos( (2*M_PI*j/(float)S) * k2 * f) * (a[k1+k2] >> 4) ;
// res2 += cos( (2*M_PI*i/(float)S) * k2 * f) * (a[k1+2] & 0xf) + sin( (2*M_PI*j/(float)S) * k1 * f) * (a[k2+1] >> 4) + sin( (2*M_PI*i/(float)S) * k2 * f) * cos( (2*M_PI*j/(float)S) * k1 * f) * (a[k1^k2] >> 4) ;
// }
//
// uint32_t q = 0 ;
// if(res1 >= 0.0f) q += val[c1].rgb() ; else q += val[c2].rgb() ;
// if(res2 >= 0.0f) q += val[c3].rgb() ; else q += val[c4].rgb() ;
//
// pix.setPixel( i, j, q) ;
// pix.setPixel( S-1-i, j, q) ;
// pix.setPixel( S-1-i, S-1-j, q) ;
// pix.setPixel( i, S-1-j, q) ;
// }
//
// image_cache[id] = pix.scaled(128,128,Qt::KeepAspectRatio,Qt::SmoothTransformation) ;
//
// return image_cache[id] ;
//}
/**
* @brief GxsIdDetails::makeIdentIcon
* @param id: RsGxsId to compute
@ -457,52 +390,150 @@ static bool findTagIcon(int tag_class, int /*tag_type*/, QIcon &icon)
* Bring the source code from this adaptation:
* http://francisshanahan.com/identicon5/test.html
*/
const QImage& GxsIdDetails::makeDefaultIcon(const RsGxsId& id)
const QPixmap GxsIdDetails::makeDefaultIcon(const RsGxsId& id, AvatarSize size)
{
checkCleanImagesCache();
// We use a cache for images. QImage has its own smart pointer system, but it does not prevent
// the same image to be allocated many times. We do this using a cache. The cache is also cleaned-up
// on a regular time basis so as to get rid of unused images.
time_t now = time(NULL);
// now look for the icon
QMutexLocker lock(&mIconCacheMutex);
auto& it = mDefaultIconCache[id];
if(it[(int)size].second.width() > 0)
{
it[(int)size].first = now;
return it[(int)size].second;
}
int S =0;
switch(size)
{
case SMALL: S = 16*3 ; break;
default:
case MEDIUM: S = 32*3 ; break;
case ORIGINAL:
case LARGE: S = 64*3 ; break;
}
QPixmap image = drawIdentIcon(QString::fromStdString(id.toStdString()),S,true);
it[(int)size] = std::make_pair(now,image);
return image;
}
void GxsIdDetails::checkCleanImagesCache()
{
time_t now = time(NULL);
// cleanup the cache every 10 mins
if(mLastIconCacheCleaning + DELAY_BETWEEN_ICON_CACHE_CLEANING < now)
{
std::cerr << "(II) Cleaning the icons cache." << std::endl;
int nb_deleted = 0;
uint32_t size_deleted = 0;
uint32_t total_size = 0;
QMutexLocker lock(&mIconCacheMutex);
for(auto it(mDefaultIconCache.begin());it!=mDefaultIconCache.end();)
if(it->second.first + ICON_CACHE_STORAGE_TIME < now && it->second.second.isDetached())
{
{
bool all_empty = true ;
for(int i=0;i<4;++i)
if(it->second[i].first + ICON_CACHE_STORAGE_TIME < now && it->second[i].second.isDetached())
{
int s = it->second[i].second.width()*it->second[i].second.height()*4;
std::cerr << "Deleting pixmap " << it->first << " size " << i << " " << s << " bytes." << std::endl;
it->second[i].second = QPixmap();
it = mDefaultIconCache.erase(it);
++nb_deleted;
size_deleted += s;
}
else
{
all_empty = false;
total_size += it->second[i].second.width()*it->second[i].second.height()*4;
}
if(all_empty)
it = mDefaultIconCache.erase(it);
++nb_deleted;
}
else
++it;
}
mLastIconCacheCleaning = now;
std::cerr << "(II) Removed " << nb_deleted << " unused icons. Cache contains " << mDefaultIconCache.size() << " icons"<< std::endl;
std::cerr << "(II) Removed " << nb_deleted << " (" << size_deleted << " bytes) unused icons. Cache contains " << mDefaultIconCache.size() << " icons (" << total_size << " bytes)"<< std::endl;
}
}
bool GxsIdDetails::loadPixmapFromData(const unsigned char *data,size_t data_len,QPixmap& pixmap, AvatarSize size)
{
// The trick below converts the data into an Id that can be read in the image cache. Because this method is mainly dedicated to loading
// avatars, we could also use the GxsId as id, but the avatar may change in time, so we actually need to make the id from the data itself.
assert(Sha1CheckSum::SIZE_IN_BYTES >= RsGxsId::SIZE_IN_BYTES);
Sha1CheckSum chksum = RsDirUtil::sha1sum(data,data_len);
RsGxsId id(chksum.toByteArray());
// We use a cache for images. QImage has its own smart pointer system, but it does not prevent
// the same image to be allocated many times. We do this using a cache. The cache is also cleaned-up
// on a regular time basis so as to get rid of unused images.
checkCleanImagesCache();
// now look for the icon
auto it = mDefaultIconCache.find(id);
QMutexLocker lock(&mIconCacheMutex);
if(it != mDefaultIconCache.end())
time_t now = time(NULL);
auto& it = mDefaultIconCache[id];
if(it[(int)size].second.width() > 0)
{
it->second.first = now;
return it->second.second;
it[(int)size].first = now;
pixmap = it[(int)size].second;
return true;
}
QImage image = drawIdentIcon(QString::fromStdString(id.toStdString()),64*3, true);
if(! pixmap.loadFromData(data,data_len))
return false;
mDefaultIconCache[id] = std::make_pair(now,image);
it = mDefaultIconCache.find(id);
// This resize is here just to prevent someone to explicitely add a huge blank image to screw up the UI
return it->second.second;
int wanted_S=0;
switch(size)
{
case ORIGINAL: wanted_S = 0 ;break;
case SMALL: wanted_S = 32 ;break;
default:
case MEDIUM: wanted_S = 64 ;break;
case LARGE: wanted_S = 128 ;break;
}
if(wanted_S > 0)
pixmap = pixmap.scaled(wanted_S,wanted_S,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
mDefaultIconCache[id][(int)size] = std::make_pair(now,pixmap);
#ifdef DEBUG
std::cerr << "Allocated new icon " << id << " size " << (int)size << std::endl;
#endif
return true;
}
/**
* @brief GxsIdDetails::getSprite
* @param shapeType: type of shape (0 to 15)
@ -820,7 +851,7 @@ void GxsIdDetails::drawRotatedPolygon( QPixmap *pixmap,
* @param rotate: If the shapes could be rotated
* @return QImage of computed hash
*/
QImage GxsIdDetails::drawIdentIcon( QString hash, quint16 width, bool rotate)
QPixmap GxsIdDetails::drawIdentIcon( QString hash, quint16 width, bool rotate)
{
bool ok;
quint8 csh = hash.mid(0, 1).toInt(&ok,16);// Corner sprite shape
@ -881,7 +912,7 @@ QImage GxsIdDetails::drawIdentIcon( QString hash, quint16 width, bool rotate)
}
drawRotatedPolygon(&pixmap, center, size, size, 0, 0, size, fillCenter);
return pixmap.toImage();
return pixmap;
}
//static bool CreateIdIcon(const RsGxsId &id, QIcon &idIcon)
@ -1089,11 +1120,11 @@ void GxsIdDetails::getIcons(const RsIdentityDetails &details, QList<QIcon> &icon
if(icon_types & ICON_TYPE_AVATAR)
{
if(details.mAvatar.mSize == 0 || !pix.loadFromData(details.mAvatar.mData, details.mAvatar.mSize, "PNG"))
if(details.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(details.mAvatar.mData, details.mAvatar.mSize, pix))
#if QT_VERSION < 0x040700
pix = QPixmap::fromImage(makeDefaultIcon(details.mId));
pix = makeDefaultIcon(details.mId);
#else
pix.convertFromImage(makeDefaultIcon(details.mId));
pix = makeDefaultIcon(details.mId);
#endif

View File

@ -74,6 +74,13 @@ public:
GxsIdDetails();
virtual ~GxsIdDetails();
enum AvatarSize {
SMALL = 0x00,
MEDIUM = 0x01,
LARGE = 0x02,
ORIGINAL= 0x03
};
static void initialize();
static void cleanup();
@ -102,8 +109,11 @@ public:
static void GenerateCombinedPixmap(QPixmap &pixmap, const QList<QIcon> &icons, int iconSize);
//static QImage makeDefaultIcon(const RsGxsId& id);
static const QImage& makeDefaultIcon(const RsGxsId& id);
// These two methods use a cache so as to minimize the memory impact of avatars.
static const QPixmap makeDefaultIcon(const RsGxsId& id, AvatarSize size = MEDIUM);
static bool loadPixmapFromData(const unsigned char *data, size_t data_len, QPixmap& pix, AvatarSize size = MEDIUM);
static void checkCleanImagesCache();
/* Processing */
static void enableProcess(bool enable);
@ -127,7 +137,7 @@ private:
quint16 x, quint16 y,
qreal shapeangle, qreal angle,
quint16 size, QColor fillColor);
static QImage drawIdentIcon(QString hash, quint16 width, bool rotate);
static QPixmap drawIdentIcon(QString hash, quint16 width, bool rotate);
private slots:
void objectDestroyed(QObject *object);
@ -159,14 +169,15 @@ protected:
QMap<QObject*,CallbackData>::iterator mPendingDataIterator;
static uint32_t mImagesAllocated;
static std::map<RsGxsId,std::pair<time_t,QImage> > mDefaultIconCache;
static std::map<RsGxsId,std::pair<time_t,QPixmap>[4] > mDefaultIconCache;
static time_t mLastIconCacheCleaning;
int mCheckTimerId;
int mProcessDisableCount;
/* Thread safe */
QMutex mMutex;
static QMutex mMutex;
static QMutex mIconCacheMutex;
};
#endif

View File

@ -154,25 +154,21 @@ QVariant GxsIdRSTreeWidgetItem::data(int column, int role) const
if (role == Qt::ToolTipRole)
{
QString t = RSTreeWidgetItem::data(column, role).toString();
QImage pix;
QPixmap pix;
if(mId.isNull()) return RSTreeWidgetItem::data(column, role);
else if( rsReputations->overallReputationLevel(mId) ==
RsReputationLevel::LOCALLY_NEGATIVE )
pix = QImage(BANNED_IMAGE);
else if ( mAvatar.mSize == 0 ||
!pix.loadFromData(mAvatar.mData, mAvatar.mSize, "PNG") )
pix = GxsIdDetails::makeDefaultIcon(mId);
if(mId.isNull())
return RSTreeWidgetItem::data(column, role);
else if( rsReputations->overallReputationLevel(mId) == RsReputationLevel::LOCALLY_NEGATIVE )
pix = QPixmap(BANNED_IMAGE);
else if ( mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(mAvatar.mData, mAvatar.mSize, pix,GxsIdDetails::LARGE) )
pix = GxsIdDetails::makeDefaultIcon(mId,GxsIdDetails::LARGE);
int S = QFontMetricsF(font(column)).height();
QString embeddedImage;
if ( RsHtml::makeEmbeddedImage(
pix.scaled(QSize(4*S,4*S), Qt::KeepAspectRatio,
Qt::SmoothTransformation ),
embeddedImage, 8*S * 8*S ) )
t = "<table><tr><td>" + embeddedImage + "</td><td>" + t
+ "</td></table>";
if ( RsHtml::makeEmbeddedImage( pix.scaled(QSize(4*S,4*S), Qt::KeepAspectRatio, Qt::SmoothTransformation ).toImage(), embeddedImage, 8*S * 8*S ) )
t = "<table><tr><td>" + embeddedImage + "</td><td>" + t + "</td></table>";
return t;
}

View File

@ -26,6 +26,7 @@
#include <QMimeData>
#include "CreateGxsChannelMsg.h"
#include "gui/gxs/GxsIdDetails.h"
#include "gui/feeds/SubFileItem.h"
#include "gui/RetroShareLink.h"
#include "util/HandleRichText.h"
@ -771,7 +772,7 @@ void CreateGxsChannelMsg::loadChannelPostInfo(const uint32_t &token)
for(std::list<RsGxsFile>::const_iterator it(post.mFiles.begin());it!=post.mFiles.end();++it)
addAttachment(it->mHash,it->mName,it->mSize,true,RsPeerId(),true);
picture.loadFromData(post.mThumbnail.mData,post.mThumbnail.mSize,"PNG");
GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData,post.mThumbnail.mSize,picture,GxsIdDetails::ORIGINAL);
thumbnail_label->setPixmap(picture);
}

View File

@ -326,7 +326,7 @@ void GxsChannelDialog::loadGroupSummaryToken(const uint32_t &token, std::list<Rs
if (group.mImage.mData != NULL) {
QPixmap image;
image.loadFromData(group.mImage.mData, group.mImage.mSize, "PNG");
GxsIdDetails::loadPixmapFromData(group.mImage.mData, group.mImage.mSize, image,GxsIdDetails::ORIGINAL);
channelData->mIcon[group.mMeta.mGroupId] = image;
}

View File

@ -20,6 +20,7 @@
#include <QBuffer>
#include "gui/gxs/GxsIdDetails.h"
#include "GxsChannelGroupDialog.h"
#include <retroshare/rsgxschannels.h>
@ -179,7 +180,8 @@ bool GxsChannelGroupDialog::service_loadGroup(uint32_t token, Mode /*mode*/, RsG
if (group.mImage.mData) {
QPixmap pixmap;
if (pixmap.loadFromData(group.mImage.mData, group.mImage.mSize, "PNG")) {
if (GxsIdDetails::loadPixmapFromData(group.mImage.mData, group.mImage.mSize,pixmap,GxsIdDetails::ORIGINAL)) {
setLogo(pixmap);
}
}

View File

@ -26,6 +26,7 @@
#include "GxsChannelPostsWidget.h"
#include "ui_GxsChannelPostsWidget.h"
#include "gui/feeds/GxsChannelPostItem.h"
#include "gui/gxs/GxsIdDetails.h"
#include "gui/gxschannels/CreateGxsChannelMsg.h"
#include "gui/common/UIStateHelper.h"
#include "gui/settings/rsharesettings.h"
@ -238,7 +239,7 @@ void GxsChannelPostsWidget::insertChannelDetails(const RsGxsChannelGroup &group)
/* IMAGE */
QPixmap chanImage;
if (group.mImage.mData != NULL) {
chanImage.loadFromData(group.mImage.mData, group.mImage.mSize, "PNG");
GxsIdDetails::loadPixmapFromData(group.mImage.mData, group.mImage.mSize, chanImage,GxsIdDetails::ORIGINAL);
} else {
chanImage = QPixmap(CHAN_DEFAULT_IMAGE);
}

View File

@ -18,23 +18,27 @@
* *
*******************************************************************************/
#ifdef UNUSED_CODE
#include <gui/gxs/GxsIdDetails.h>
#include <util/PixmapMerging.h>
#include <QPixmap>
#include <QPainter>
QPixmap PixmapMerging::merge(const std::string & foregroundPixmapData, const std::string & backgroundPixmapFilename) {
QImage foregroundImage;
foregroundImage.loadFromData((uchar *) foregroundPixmapData.c_str(), foregroundPixmapData.size());
QPixmap PixmapMerging::merge(const std::string & foregroundPixmapData, const std::string & backgroundPixmapFilename)
{
QPixmap foregroundImage;
GxsIdDetails::loadPixmapFromData((uchar *) foregroundPixmapData.c_str(), foregroundPixmapData.size(),foregroundImage);
QPixmap backgroundPixmap = QPixmap(QString::fromStdString(backgroundPixmapFilename));
if (!foregroundImage.isNull()) {
QPainter painter(&backgroundPixmap);
painter.drawImage(0, 0,
foregroundImage.scaled(backgroundPixmap.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
painter.drawPixmap(0, 0, foregroundImage.scaled(backgroundPixmap.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
painter.end();
}
return backgroundPixmap;
}
#endif

View File

@ -21,6 +21,7 @@
#ifndef PIXMAPMERGING_H
#define PIXMAPMERGING_H
#ifdef UNUSED_CODE
#include <util/rsqtutildll.h>
#include <util/NonCopyable.h>
@ -49,4 +50,6 @@ public:
RSQTUTIL_API static QPixmap merge(const std::string & foregroundPixmapData, const std::string & backgroundPixmapFilename);
};
#endif
#endif //PIXMAPMERGING_H