Merge pull request #3042 from csoler/v0.6-Feeds
Some checks failed
macOS Build / build (push) Has been cancelled
MINGW64 Qt6 Build / build (push) Has been cancelled
MINGW64 Qt5 Build / build (push) Has been cancelled
UCRT64 Qt5 Build / build (push) Has been cancelled
Ubuntu Qt 5 C/C++ CI / build (push) Has been cancelled
Ubuntu Qt 6 C/C++ CI / build (push) Has been cancelled

improved code consistency in feed item loading/killing
This commit is contained in:
csoler 2025-11-10 14:12:21 +01:00 committed by GitHub
commit 383b1e7d2b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 792 additions and 1262 deletions

@ -1 +1 @@
Subproject commit 0a3997cc1355b2c848161dca015b7e2df039707b Subproject commit 9dd9d7f94a600e8c8478887a4f7784fdc3294034

@ -1 +1 @@
Subproject commit 178aa8ebcef47e3271d5a5ca5c07e45d3b71c81d Subproject commit 634f701d44585e4648b898be99d26e288db1881e

View file

@ -512,6 +512,14 @@ void NewsFeed::handleSecurityEvent(std::shared_ptr<const RsEvent> event)
void NewsFeed::testFeeds(uint /*notifyFlags*/) void NewsFeed::testFeeds(uint /*notifyFlags*/)
{ {
auto feedItem = new GxsChannelPostItem(instance,
NEWSFEED_CHANNELNEWLIST,
RsGxsGroupId ("00000000000000000000000000000000"),
RsGxsMessageId("0000000000000000000000000000000000000000")
, false, true);
instance->addFeedItem(feedItem);
#ifdef TO_REMOVE #ifdef TO_REMOVE
if (!instance) { if (!instance) {
return; return;

View file

@ -942,196 +942,10 @@ void PostedListWidgetWithModel::insertBoardDetails(const RsPostedGroup& group)
} }
ui->infoDistribution->setText(distrib_string); ui->infoDistribution->setText(distrib_string);
#ifdef TODO
ui->infoWidget->show();
ui->feedWidget->hide();
ui->fileWidget->hide();
//ui->feedToolButton->setEnabled(false);
//ui->fileToolButton->setEnabled(false);
#endif
} }
#ifdef TODO
int PostedListWidgetWithModel::viewMode()
{
if (ui->feedToolButton->isChecked()) {
return VIEW_MODE_FEEDS;
} else if (ui->fileToolButton->isChecked()) {
return VIEW_MODE_FILES;
}
/* Default */
return VIEW_MODE_FEEDS;
}
#endif
#ifdef TODO
/*static*/ bool PostedListWidgetWithModel::filterItem(FeedItem *feedItem, const QString &text, int filter)
{
GxsChannelPostItem *item = dynamic_cast<GxsChannelPostItem*>(feedItem);
if (!item) {
return true;
}
bool bVisible = text.isEmpty();
if (!bVisible)
{
switch(filter)
{
case FILTER_TITLE:
bVisible = item->getTitleLabel().contains(text,Qt::CaseInsensitive);
break;
case FILTER_MSG:
bVisible = item->getMsgLabel().contains(text,Qt::CaseInsensitive);
break;
case FILTER_FILE_NAME:
{
std::list<SubFileItem *> fileItems = item->getFileItems();
std::list<SubFileItem *>::iterator lit;
for(lit = fileItems.begin(); lit != fileItems.end(); ++lit)
{
SubFileItem *fi = *lit;
QString fileName = QString::fromUtf8(fi->FileName().c_str());
bVisible = (bVisible || fileName.contains(text,Qt::CaseInsensitive));
}
break;
}
default:
bVisible = true;
break;
}
}
return bVisible;
}
void PostedListWidget::createPostItemFromMetaData(const RsGxsMsgMetaData& meta,bool related)
{
GxsChannelPostItem *item = NULL;
RsGxsChannelPost post;
if(!meta.mOrigMsgId.isNull())
{
FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(meta.mOrigMsgId)) ;
item = dynamic_cast<GxsChannelPostItem*>(feedItem);
if(item)
{
post = feedItem->post();
ui->feedWidget->removeFeedItem(item) ;
post.mOlderVersions.insert(post.mMeta.mMsgId);
GxsChannelPostItem *item = new GxsChannelPostItem(this, 0, post, true, false,post.mOlderVersions);
ui->feedWidget->addFeedItem(item, ROLE_PUBLISH, DateTime::DateTimeFromTime_t(post.mMeta.mPublishTs));
return ;
}
}
if (related)
{
FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(meta.mMsgId)) ;
item = dynamic_cast<GxsChannelPostItem*>(feedItem);
}
if (item)
{
item->setPost(post);
ui->feedWidget->setSort(item, ROLE_PUBLISH, DateTime::DateTimeFromTime_t(meta.mPublishTs));
}
else
{
GxsChannelPostItem *item = new GxsChannelPostItem(this, 0, meta.mGroupId,meta.mMsgId, true, true);
ui->feedWidget->addFeedItem(item, ROLE_PUBLISH, DateTime::DateTimeFromTime_t(post.mMeta.mPublishTs));
}
#ifdef TODO
ui->fileWidget->addFiles(post, related);
#endif
}
void PostedListWidget::createPostItem(const RsGxsChannelPost& post, bool related)
{
GxsChannelPostItem *item = NULL;
const RsMsgMetaData& meta(post.mMeta);
if(!meta.mOrigMsgId.isNull())
{
FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(meta.mOrigMsgId)) ;
item = dynamic_cast<GxsChannelPostItem*>(feedItem);
if(item)
{
std::set<RsGxsMessageId> older_versions(item->olderVersions()); // we make a copy because the item will be deleted
ui->feedWidget->removeFeedItem(item) ;
older_versions.insert(meta.mMsgId);
GxsChannelPostItem *item = new GxsChannelPostItem(this, 0, mGroup.mMeta,meta.mMsgId, true, false,older_versions);
ui->feedWidget->addFeedItem(item, ROLE_PUBLISH, DateTime::DateTimeFromTime_t(meta.mPublishTs));
return ;
}
}
if (related)
{
FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(meta.mMsgId)) ;
item = dynamic_cast<GxsChannelPostItem*>(feedItem);
}
if (item)
{
item->setPost(post);
ui->feedWidget->setSort(item, ROLE_PUBLISH, DateTime::DateTimeFromTime_t(meta.mPublishTs));
}
else
{
GxsChannelPostItem *item = new GxsChannelPostItem(this, 0, mGroup.mMeta,meta.mMsgId, true, true);
ui->feedWidget->addFeedItem(item, ROLE_PUBLISH, DateTime::DateTimeFromTime_t(meta.mPublishTs));
}
ui->fileWidget->addFiles(post, related);
}
void PostedListWidget::fillThreadCreatePost(const QVariant &post, bool related, int current, int count)
{
/* show fill progress */
if (count) {
ui->progressBar->setValue(current * ui->progressBar->maximum() / count);
}
if (!post.canConvert<RsGxsChannelPost>()) {
return;
}
createPostItem(post.value<RsGxsChannelPost>(), related);
}
#endif
void PostedListWidgetWithModel::blank() void PostedListWidgetWithModel::blank()
{ {
#ifdef TODO
ui->postButton->setEnabled(false);
ui->subscribeToolButton->setEnabled(false);
ui->channelName_LB->setText(tr("No Channel Selected"));
ui->logoLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/icons/png/channels.png"));
ui->infoPosts->setText("");
ui->infoLastPost->setText("");
ui->infoAdministrator->setText("");
ui->infoDistribution->setText("");
ui->infoCreated->setText("");
ui->infoDescription->setText("");
mChannelPostsModel->clear();
mChannelPostFilesModel->clear();
ui->postDetails_TE->clear();
ui->postLogo_LB->hide();
ui->postName_LB->hide();
ui->postTime_LB->hide();
#endif
groupNameChanged(QString()); groupNameChanged(QString());
} }

View file

@ -78,7 +78,8 @@ BaseBoardsCommentsItem::BaseBoardsCommentsItem( FeedHolder *feedHolder, uint32_t
BaseBoardsCommentsItem::~BaseBoardsCommentsItem() BaseBoardsCommentsItem::~BaseBoardsCommentsItem()
{ {
auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(200); auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(GROUP_ITEM_LOADING_TIMEOUT_ms);
while( (mIsLoadingGroup || mIsLoadingMessage || mIsLoadingComment) while( (mIsLoadingGroup || mIsLoadingMessage || mIsLoadingComment)
&& std::chrono::steady_clock::now() < timeout) && std::chrono::steady_clock::now() < timeout)
{ {
@ -126,6 +127,7 @@ bool BaseBoardsCommentsItem::setPost(const RsPostedPost &post, bool doFill)
void BaseBoardsCommentsItem::loadGroup() void BaseBoardsCommentsItem::loadGroup()
{ {
mIsLoadingGroup = true; mIsLoadingGroup = true;
RsThread::async([this]() RsThread::async([this]()
{ {
// 1 - get group data // 1 - get group data

View file

@ -49,39 +49,17 @@
* #define DEBUG_ITEM 1 * #define DEBUG_ITEM 1
****/ ****/
// ChannelsCommentsItem::ChannelsCommentsItem(FeedHolder *feedHolder, uint32_t feedId, const RsGroupMetaData& group_meta, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate,const std::set<RsGxsMessageId>& older_versions) :
// GxsFeedItem(feedHolder, feedId, group_meta.mGroupId, messageId, isHome, rsGxsChannels, autoUpdate),
// mGroupMeta(group_meta)
// {
// mLoadingGroup = false;
// mLoadingMessage = false;
// mLoadingComment = false;
//
// mPost.mMeta.mMsgId = messageId; // useful for uniqueIdentifer() before the post is loaded
// mPost.mMeta.mGroupId = mGroupMeta.mGroupId;
//
// QVector<RsGxsMessageId> v;
// //bool self = false;
//
// for(std::set<RsGxsMessageId>::const_iterator it(older_versions.begin());it!=older_versions.end();++it)
// v.push_back(*it) ;
//
// if(older_versions.find(messageId) == older_versions.end())
// v.push_back(messageId);
//
// setMessageVersions(v) ;
// setup();
//
// // no call to loadGroup() here because we have it already.
// }
ChannelsCommentsItem::ChannelsCommentsItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId& groupId, const RsGxsMessageId &commentId, const RsGxsMessageId &threadId, bool isHome, bool autoUpdate) : ChannelsCommentsItem::ChannelsCommentsItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId& groupId, const RsGxsMessageId &commentId, const RsGxsMessageId &threadId, bool isHome, bool autoUpdate) :
GxsFeedItem(feedHolder, feedId, groupId, commentId, isHome, rsGxsChannels, autoUpdate), // this one should be in GxsFeedItem GxsFeedItem(feedHolder, feedId, groupId, commentId, isHome, rsGxsChannels, autoUpdate), // this one should be in GxsFeedItem
mThreadId(threadId) mThreadId(threadId)
{ {
mLoading= false; mGroupMeta.mGroupId.clear(); // safety measure
mComment.mMeta.mMsgId.clear();
QVector<RsGxsMessageId> v; mLoadingStatus = LOADING_STATUS_NO_DATA;
mLoadingComment = false;
mLoadingGroup = false;
mLoadingMessage = false;
setup(); setup();
} }
@ -91,10 +69,28 @@ void ChannelsCommentsItem::paintEvent(QPaintEvent *e)
/* This method employs a trick to trigger a deferred loading. The post and group is requested only /* This method employs a trick to trigger a deferred loading. The post and group is requested only
* when actually displayed on the screen. */ * when actually displayed on the screen. */
if(!mLoaded) if(mLoadingStatus != LOADING_STATUS_FILLED && !mGroupMeta.mGroupId.isNull() && !mComment.mMeta.mMsgId.isNull() && !mPost.mMeta.mMsgId.isNull())
{ mLoadingStatus = LOADING_STATUS_HAS_DATA;
mLoaded = true ;
load(); if(mGroupMeta.mGroupId.isNull() && !mLoadingGroup)
loadGroupData();
if(mComment.mMeta.mMsgId.isNull() && !mLoadingComment)
loadCommentData();
if(mPost.mMeta.mMsgId.isNull() && !mLoadingMessage)
loadMessageData();
switch(mLoadingStatus)
{
case LOADING_STATUS_FILLED:
case LOADING_STATUS_NO_DATA:
default:
break;
case LOADING_STATUS_HAS_DATA:
fill();
mLoadingStatus = LOADING_STATUS_FILLED;
break;
} }
GxsFeedItem::paintEvent(e) ; GxsFeedItem::paintEvent(e) ;
@ -102,11 +98,16 @@ void ChannelsCommentsItem::paintEvent(QPaintEvent *e)
ChannelsCommentsItem::~ChannelsCommentsItem() ChannelsCommentsItem::~ChannelsCommentsItem()
{ {
auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(300); auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(GROUP_ITEM_LOADING_TIMEOUT_ms);
while( mLoading && std::chrono::steady_clock::now() < timeout ) while( (mLoadingGroup || mLoadingComment)
&& std::chrono::steady_clock::now() < timeout )
{ {
RsDbg() << __PRETTY_FUNCTION__ << " is Waiting for data to load " << std::endl; RsDbg() << __PRETTY_FUNCTION__ << " is Waiting for data to load "
<< (mLoadingGroup ? "Group " : "")
<< (mLoadingMessage ? "Message " : "")
<< (mLoadingComment ? "Comment " : "")
<< std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
} }
@ -115,7 +116,7 @@ ChannelsCommentsItem::~ChannelsCommentsItem()
bool ChannelsCommentsItem::isUnread() const bool ChannelsCommentsItem::isUnread() const
{ {
return IS_MSG_UNREAD(mPost.mMeta.mMsgStatus) ; return IS_MSG_UNREAD(mComment.mMeta.mMsgStatus) ;
} }
void ChannelsCommentsItem::setup() void ChannelsCommentsItem::setup()
@ -141,9 +142,7 @@ void ChannelsCommentsItem::setup()
setAttribute(Qt::WA_DeleteOnClose, true); setAttribute(Qt::WA_DeleteOnClose, true);
mInFill = false;
mCloseOnRead = false; mCloseOnRead = false;
mLoaded = false;
/* clear ui */ /* clear ui */
ui->datetimeLabel->clear(); ui->datetimeLabel->clear();
@ -178,33 +177,6 @@ void ChannelsCommentsItem::setup()
ui->expandFrame->hide(); ui->expandFrame->hide();
} }
bool ChannelsCommentsItem::setPost(const RsGxsChannelPost& post, bool doFill)
{
mPost = post;
if (doFill)
fill();
return true;
}
bool ChannelsCommentsItem::setMissingPost()
{
fill(true);
return true;
}
QString ChannelsCommentsItem::getTitleLabel()
{
return QString::fromUtf8(mPost.mMeta.mMsgName.c_str());
}
QString ChannelsCommentsItem::getMsgLabel()
{
//return RsHtml().formatText(NULL, QString::fromUtf8(mPost.mMsg.c_str()), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS);
// Disabled, because emoticon replacement kills performance.
return QString::fromUtf8(mPost.mMsg.c_str());
}
QString ChannelsCommentsItem::groupName() QString ChannelsCommentsItem::groupName()
{ {
return QString::fromUtf8(mGroupMeta.mGroupName.c_str()); return QString::fromUtf8(mGroupMeta.mGroupName.c_str());
@ -219,91 +191,109 @@ void ChannelsCommentsItem::loadComments()
return ; return ;
MainWindow::showWindow(MainWindow::Channels); MainWindow::showWindow(MainWindow::Channels);
channelDialog->navigate(mPost.mMeta.mGroupId, mPost.mMeta.mMsgId); channelDialog->navigate(mComment.mMeta.mGroupId, mComment.mMeta.mMsgId);
} }
void ChannelsCommentsItem::loadGroup() void ChannelsCommentsItem::loadGroupData()
{ {
//#ifdef DEBUG_ITEM std::cerr << "GxsChannelGroupItem::loadGroup()" << std::endl;
// std::cerr << "GxsChannelGroupItem::loadGroup()";
// std::cerr << std::endl;
//#endif
// if(mLoading)
// return;
//
// mLoading= true;
//
// std::cerr << "Loading group" << std::endl;
// RsThread::async([this]()
// {
// // 1 - get group data
//
// std::vector<RsGxsChannelGroup> groups;
// const std::list<RsGxsGroupId> groupIds = { groupId() };
//
// if(!rsGxsChannels->getChannelsInfo(groupIds,groups)) // would be better to call channel Summaries for a single group
// {
// RsErr() << "GxsGxsChannelGroupItem::loadGroup() ERROR getting data" << std::endl;
// return;
// }
//
// if (groups.size() != 1)
// {
// std::cerr << "GxsGxsChannelGroupItem::loadGroup() Wrong number of Items";
// std::cerr << std::endl;
// return;
// }
// RsGxsChannelGroup group(groups[0]);
//
// RsQThreadUtils::postToObject( [group,this]()
// {
// /* Here it goes any code you want to be executed on the Qt Gui
// * thread, for example to update the data model with new information
// * after a blocking call to RetroShare API complete */
//
// mGroupMeta = group.mMeta;
// mLoading= false;
//
// std::cerr << "End loading group" << std::endl;
// }, this );
// });
}
void ChannelsCommentsItem::load()
{
// This function loads everything that's needed:
// - the comment text
// - the comment parent message
#ifdef DEBUG_ITEM mLoadingGroup = true;
std::cerr << "ChannelsCommentsItem::loadMessage()";
std::cerr << std::endl;
#endif
if(mLoading)
return;
mLoading= true;
RsThread::async([this]() RsThread::async([this]()
{ {
// 1 - get group meta data // 1 - get group data
std::vector<RsGxsChannelGroup> groups; std::vector<RsGxsChannelGroup> groups;
const std::list<RsGxsGroupId> groupIds = { groupId() }; const std::list<RsGxsGroupId> groupIds = { groupId() };
if(!rsGxsChannels->getChannelsInfo(groupIds,groups)) // would be better to call channel Summaries for a single group if(!rsGxsChannels->getChannelsInfo(groupIds,groups)) // would be better to call channel Summaries for a single group
{ {
RsErr() << "GxsGxsChannelGroupItem::loadGroup() ERROR getting data" << std::endl; RsErr() << "GxsGxsChannelGroupItem::loadGroup() ERROR getting data for group " << groupId() << std::endl;
mLoadingGroup = false;
return; return;
} }
if (groups.size() != 1) if (groups.size() != 1)
{ {
std::cerr << "GxsGxsChannelGroupItem::loadGroup() Wrong number of Items" << std::endl; std::cerr << "GxsGxsChannelGroupItem::loadGroup() Wrong number of Items for group " << groupId() ;
std::cerr << std::endl;
mLoadingGroup = false;
return; return;
} }
RsGxsChannelGroup group(groups[0]); RsGxsChannelGroup group(groups[0]);
// 2 - get message and comment data RsQThreadUtils::postToObject( [group,this]()
{
/* Here it goes any code you want to be executed on the Qt Gui
* thread, for example to update the data model with new information
* after a blocking call to RetroShare API complete */
mGroupMeta = group.mMeta;
mLoadingGroup = false;
update(); // this triggers a paintEvent if needed.
}, this );
});
}
void ChannelsCommentsItem::loadMessageData()
{
#ifdef DEBUG_ITEM
std::cerr << "ChannelsCommentsItem::loadCommentData()";
std::cerr << std::endl;
#endif
mLoadingMessage = true;
RsThread::async([this]()
{
// 1 - get message and comment data
std::vector<RsGxsChannelPost> posts;
std::vector<RsGxsComment> comments;
std::vector<RsGxsVote> votes;
if(! rsGxsChannels->getChannelContent( groupId(), std::set<RsGxsMessageId>( { mThreadId } ),posts,comments,votes))
{
RsErr() << "GxsGxsChannelGroupItem::loadMessage() ERROR getting data" << std::endl;
mLoadingMessage = false;
return;
}
// now that everything is in place, update the UI
RsQThreadUtils::postToObject( [posts,this]()
{
/* Here it goes any code you want to be executed on the Qt Gui
* thread, for example to update the data model with new information
* after a blocking call to RetroShare API complete */
if(posts.size()!=1) // the original post cannot be found. Removing the comment item.
{
mLoadingMessage = false;
removeItem();
return;
}
mPost = posts[0];
mLoadingMessage = false;
update();
}, this );
});
}
void ChannelsCommentsItem::loadCommentData()
{
#ifdef DEBUG_ITEM
std::cerr << "ChannelsCommentsItem::loadCommentData()";
std::cerr << std::endl;
#endif
mLoadingComment = true;
RsThread::async([this]()
{
// 1 - get message and comment data
std::vector<RsGxsChannelPost> posts; std::vector<RsGxsChannelPost> posts;
std::vector<RsGxsComment> comments; std::vector<RsGxsComment> comments;
@ -311,54 +301,28 @@ void ChannelsCommentsItem::load()
if(! rsGxsChannels->getChannelContent( groupId(), std::set<RsGxsMessageId>( { messageId(),mThreadId } ),posts,comments,votes)) if(! rsGxsChannels->getChannelContent( groupId(), std::set<RsGxsMessageId>( { messageId(),mThreadId } ),posts,comments,votes))
{ {
RsErr() << "GxsGxsChannelGroupItem::loadGroup() ERROR getting data" << std::endl; RsErr() << "GxsGxsChannelGroupItem::loadComment() ERROR getting data" << std::endl;
return; mLoadingComment = false;
return;
} }
if(comments.size()!=1)
{
mLoadingComment = false;
return;
}
// now that everything is in place, update the UI // now that everything is in place, update the UI
RsQThreadUtils::postToObject( [group,posts,comments,this]() RsQThreadUtils::postToObject( [comments,this]()
{ {
/* Here it goes any code you want to be executed on the Qt Gui /* Here it goes any code you want to be executed on the Qt Gui
* thread, for example to update the data model with new information * thread, for example to update the data model with new information
* after a blocking call to RetroShare API complete */ * after a blocking call to RetroShare API complete */
mGroupMeta = group.mMeta; mComment = comments[0];
mLoadingComment = false;
if(comments.size()==1) update();
{
RsGxsComment cmt(comments[0]);
uint32_t autorized_lines = (int)floor( (ui->avatarLabel->height() - ui->button_HL->sizeHint().height())
/ QFontMetricsF(ui->subjectLabel->font()).height());
ui->commLabel->setText(RsHtml().formatText(NULL, RsStringUtil::CopyLines(QString::fromUtf8(cmt.mComment.c_str()), autorized_lines), RSHTML_FORMATTEXT_EMBED_LINKS));
ui->nameLabel->setId(cmt.mMeta.mAuthorId);
ui->datetimeLabel->setText(DateTime::formatLongDateTime(cmt.mMeta.mPublishTs));
RsIdentityDetails idDetails ;
rsIdentity->getIdDetails(cmt.mMeta.mAuthorId,idDetails);
QPixmap pixmap ;
if(idDetails.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idDetails.mAvatar.mData, idDetails.mAvatar.mSize, pixmap,GxsIdDetails::SMALL))
pixmap = GxsIdDetails::makeDefaultIcon(cmt.mMeta.mAuthorId,GxsIdDetails::LARGE);
ui->avatarLabel->setPixmap(pixmap);
//Change this item to be uploaded with thread element. This is really bad practice.
}
else
{
mLoading=false;
removeItem();
}
if (posts.size() == 1)
setPost(posts[0]);
else
setMissingPost();
emit sizeChanged(this);
mLoading=false;
}, this ); }, this );
}); });
@ -367,87 +331,68 @@ void ChannelsCommentsItem::load()
void ChannelsCommentsItem::fill(bool missing_post) void ChannelsCommentsItem::fill(bool missing_post)
{ {
#ifdef DEBUG_ITEM #ifdef DEBUG_ITEM
std::cerr << "ChannelsCommentsItem::fill()"; std::cerr << "ChannelsCommentsItem::fill()";
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
mInFill = true;
if (!mIsHome) if (mCloseOnRead && !IS_MSG_NEW(mComment.mMeta.mMsgStatus)) {
{ removeItem();
if (mCloseOnRead && !IS_MSG_NEW(mPost.mMeta.mMsgStatus)) { }
removeItem();
}
//RetroShareLink link = RetroShareLink::createGxsGroupLink(RetroShareLink::TYPE_CHANNEL, mPost.mMeta.mGroupId, groupName()); RetroShareLink grplink = RetroShareLink::createGxsGroupLink(RetroShareLink::TYPE_CHANNEL, mGroupMeta.mGroupId, groupName());
//title += link.toHtml(); RetroShareLink msgLink = RetroShareLink::createGxsMessageLink(RetroShareLink::TYPE_CHANNEL, mPost.mMeta.mGroupId, mPost.mMeta.mMsgId, messageName());
//ui->titleLabel->setText(title);
RetroShareLink msgLink = RetroShareLink::createGxsMessageLink(RetroShareLink::TYPE_CHANNEL, mPost.mMeta.mGroupId, mPost.mMeta.mMsgId, messageName()); if(missing_post)
ui->subjectLabel->setText("[" + QObject::tr("Missing channel post")+"]");
else
ui->subjectLabel->setText(msgLink.toHtml());
if(missing_post) ui->readButton->hide();
ui->subjectLabel->setText("[" + QObject::tr("Missing channel post")+"]");
else
ui->subjectLabel->setText(msgLink.toHtml());
ui->readButton->hide(); if (IS_MSG_NEW(mComment.mMeta.mMsgStatus)) {
mCloseOnRead = true;
}
if (IS_MSG_NEW(mPost.mMeta.mMsgStatus)) { ui->newCommentLabel->setText(groupName()+": ");
mCloseOnRead = true;
}
}
else
{
if(missing_post)
ui->subjectLabel->setText("[" + QObject::tr("Missing channel post")+"]");
else
ui->subjectLabel->setText(RsStringUtil::CopyLines(QString::fromUtf8(mPost.mMsg.c_str()), 2)) ;
/* disable buttons: deletion facility not enabled with cache services yet */ uint32_t autorized_lines = (int)floor( (ui->avatarLabel->height() - ui->button_HL->sizeHint().height())
ui->clearButton->setEnabled(false); / QFontMetricsF(ui->subjectLabel->font()).height());
ui->clearButton->hide();
ui->readAndClearButton->hide();
ui->copyLinkButton->show();
//ui->titleLabel->hide();
if (IS_GROUP_SUBSCRIBED(mGroupMeta.mSubscribeFlags) || IS_GROUP_ADMIN(mGroupMeta.mSubscribeFlags)) ui->commLabel->setText(RsHtml().formatText(NULL, RsStringUtil::CopyLines(QString::fromUtf8(mComment.mComment.c_str()), autorized_lines), RSHTML_FORMATTEXT_EMBED_LINKS));
{ ui->nameLabel->setId(mComment.mMeta.mAuthorId);
ui->readButton->setVisible(true); ui->datetimeLabel->setText(DateTime::formatLongDateTime(mComment.mMeta.mPublishTs));
setReadStatus(IS_MSG_NEW(mPost.mMeta.mMsgStatus), IS_MSG_UNREAD(mPost.mMeta.mMsgStatus) || IS_MSG_NEW(mPost.mMeta.mMsgStatus)); RsIdentityDetails idDetails ;
} rsIdentity->getIdDetails(mComment.mMeta.mAuthorId,idDetails);
else QPixmap pixmap ;
{
ui->readButton->setVisible(false);
}
mCloseOnRead = false; if(idDetails.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idDetails.mAvatar.mData, idDetails.mAvatar.mSize, pixmap,GxsIdDetails::SMALL))
} pixmap = GxsIdDetails::makeDefaultIcon(mComment.mMeta.mAuthorId,GxsIdDetails::LARGE);
ui->avatarLabel->setPixmap(pixmap);
mInFill = false;
} }
QString ChannelsCommentsItem::messageName() QString ChannelsCommentsItem::messageName()
{ {
return QString::fromUtf8(mPost.mMeta.mMsgName.c_str()); return QString::fromUtf8(mPost.mMeta.mMsgName.c_str());
} }
void ChannelsCommentsItem::setReadStatus(bool isNew, bool isUnread) void ChannelsCommentsItem::setReadStatus(bool isNew, bool isUnread)
{ {
if (isNew) if (isNew)
mPost.mMeta.mMsgStatus |= GXS_SERV::GXS_MSG_STATUS_GUI_NEW; mComment.mMeta.mMsgStatus |= GXS_SERV::GXS_MSG_STATUS_GUI_NEW;
else else
mPost.mMeta.mMsgStatus &= ~GXS_SERV::GXS_MSG_STATUS_GUI_NEW; mComment.mMeta.mMsgStatus &= ~GXS_SERV::GXS_MSG_STATUS_GUI_NEW;
if (isUnread) if (isUnread)
{ {
mPost.mMeta.mMsgStatus |= GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD; mComment.mMeta.mMsgStatus |= GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD;
whileBlocking(ui->readButton)->setChecked(true); whileBlocking(ui->readButton)->setChecked(true);
ui->readButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/images/message-state-unread.png")); ui->readButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/images/message-state-unread.png"));
} }
else else
{ {
mPost.mMeta.mMsgStatus &= ~GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD; mComment.mMeta.mMsgStatus &= ~GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD;
whileBlocking(ui->readButton)->setChecked(false); whileBlocking(ui->readButton)->setChecked(false);
ui->readButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/images/message-state-read.png")); ui->readButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/images/message-state-read.png"));
} }
@ -521,24 +466,18 @@ void ChannelsCommentsItem::unsubscribeChannel()
void ChannelsCommentsItem::readToggled(bool /*checked*/) void ChannelsCommentsItem::readToggled(bool /*checked*/)
{ {
if (mInFill) {
return;
}
mCloseOnRead = false; mCloseOnRead = false;
RsGxsGrpMsgIdPair msgPair = std::make_pair(groupId(), messageId()); RsGxsGrpMsgIdPair msgPair = std::make_pair(groupId(), messageId());
rsGxsChannels->setCommentReadStatus(msgPair, isUnread()); rsGxsChannels->setCommentReadStatus(msgPair, isUnread());
//setReadStatus(false, checked); // Updated by events
} }
void ChannelsCommentsItem::makeDownVote() void ChannelsCommentsItem::makeDownVote()
{ {
RsGxsGrpMsgIdPair msgId; RsGxsGrpMsgIdPair msgId;
msgId.first = mPost.mMeta.mGroupId; msgId.first = mComment.mMeta.mGroupId;
msgId.second = mPost.mMeta.mMsgId; msgId.second = mComment.mMeta.mMsgId;
ui->voteUpButton->setEnabled(false); ui->voteUpButton->setEnabled(false);
ui->voteDownButton->setEnabled(false); ui->voteDownButton->setEnabled(false);
@ -549,8 +488,8 @@ void ChannelsCommentsItem::makeDownVote()
void ChannelsCommentsItem::makeUpVote() void ChannelsCommentsItem::makeUpVote()
{ {
RsGxsGrpMsgIdPair msgId; RsGxsGrpMsgIdPair msgId;
msgId.first = mPost.mMeta.mGroupId; msgId.first = mComment.mMeta.mGroupId;
msgId.second = mPost.mMeta.mMsgId; msgId.second = mComment.mMeta.mMsgId;
ui->voteUpButton->setEnabled(false); ui->voteUpButton->setEnabled(false);
ui->voteDownButton->setEnabled(false); ui->voteDownButton->setEnabled(false);

View file

@ -50,34 +50,20 @@ public:
bool isHome, bool isHome,
bool autoUpdate); bool autoUpdate);
// This one is used in channel thread widget. We don't want the group data to reload at every post, so we load it in the hosting
// GxsChannelsPostsWidget and pass it to created items.
// ChannelsCommentsItem(FeedHolder *feedHolder, uint32_t feedId, const RsGroupMetaData& group, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate, const std::set<RsGxsMessageId>& older_versions = std::set<RsGxsMessageId>());
virtual ~ChannelsCommentsItem(); virtual ~ChannelsCommentsItem();
uint64_t uniqueIdentifier() const override { return hash_64bits("ChannelsCommentsItem " + messageId().toStdString()) ; } uint64_t uniqueIdentifier() const override { return hash_64bits("ChannelsCommentsItem " + messageId().toStdString()) ; }
bool setGroup(const RsGxsChannelGroup& group, bool doFill = true); protected:
bool setPost(const RsGxsChannelPost& post, bool doFill = true);
bool setMissingPost();
QString getTitleLabel();
QString getMsgLabel();
bool isLoaded() const {return mLoaded;};
bool isUnread() const ; bool isUnread() const ;
void setReadStatus(bool isNew, bool isUnread); void setReadStatus(bool isNew, bool isUnread);
const std::set<RsGxsMessageId>& olderVersions() const { return mPost.mOlderVersions; }
static uint64_t computeIdentifier(const RsGxsMessageId& msgid) { return hash64("ChannelsCommentsItem " + msgid.toStdString()) ; } static uint64_t computeIdentifier(const RsGxsMessageId& msgid) { return hash64("ChannelsCommentsItem " + msgid.toStdString()) ; }
protected:
//void init(const RsGxsMessageId& messageId,const std::set<RsGxsMessageId>& older_versions);
/* FeedItem */ /* FeedItem */
virtual void doExpand(bool open); virtual void doExpand(bool open) override;
virtual void expandFill(bool first); virtual void expandFill(bool first) override;
// This does nothing except triggering the loading of the post data and comments. This function is mainly used to detect // This does nothing except triggering the loading of the post data and comments. This function is mainly used to detect
// when the post is actually made visible. // when the post is actually made visible.
@ -85,12 +71,12 @@ protected:
virtual void paintEvent(QPaintEvent *) override; virtual void paintEvent(QPaintEvent *) override;
/* GxsGroupFeedItem */ /* GxsGroupFeedItem */
virtual QString groupName(); virtual QString groupName() override;
virtual void loadGroup() override; virtual void loadGroup() override {}
virtual RetroShareLink::enumType getLinkType() { return RetroShareLink::TYPE_CHANNEL; } virtual RetroShareLink::enumType getLinkType() override { return RetroShareLink::TYPE_CHANNEL; }
/* GxsFeedItem */ /* GxsFeedItem */
virtual QString messageName(); virtual QString messageName() override;
virtual void loadMessage() override {} virtual void loadMessage() override {}
virtual void loadComment() override {} virtual void loadComment() override {}
@ -110,19 +96,23 @@ signals:
void vote(const RsGxsGrpMsgIdPair& msgId, bool up); void vote(const RsGxsGrpMsgIdPair& msgId, bool up);
private: private:
void load();
void setup(); void setup();
void fill(bool missing_post=false); void fill(bool missing_post=false);
void loadGroupData();
void loadMessageData();
void loadCommentData();
private:
bool mInFill;
bool mCloseOnRead; bool mCloseOnRead;
bool mLoaded;
bool mLoading; LoadingStatus mLoadingStatus;
bool mLoadingComment;
bool mLoadingGroup;
bool mLoadingMessage;
RsGroupMetaData mGroupMeta; RsGroupMetaData mGroupMeta;
RsGxsChannelPost mPost; RsGxsComment mComment;
RsGxsChannelPost mPost;
RsGxsMessageId mThreadId; RsGxsMessageId mThreadId;
/** Qt Designer generated object */ /** Qt Designer generated object */

View file

@ -50,202 +50,6 @@
<property name="verticalSpacing"> <property name="verticalSpacing">
<number>3</number> <number>3</number>
</property> </property>
<item row="2" column="1">
<layout class="QHBoxLayout" name="button_HL">
<property name="spacing">
<number>8</number>
</property>
<item>
<layout class="QHBoxLayout" name="vote_HL">
<item>
<widget class="QPushButton" name="voteUpButton">
<property name="toolTip">
<string>I like this</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="scoreLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="voteDownButton">
<property name="toolTip">
<string>I dislike this</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="readButton">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Toggle Message Read Status</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="logoLabel">
<property name="text">
<string>Avatar</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="newCommentLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>New Comment</string>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="subjectLabel">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">POST TITLE</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="button_HSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="copyLinkButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Copy RetroShare Link</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="expandButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Expand</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="readAndClearButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Set as read and remove item</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Remove Item</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1" rowspan="2"> <item row="0" column="1" rowspan="2">
<widget class="QFrame" name="commentFrame"> <widget class="QFrame" name="commentFrame">
<property name="sizePolicy"> <property name="sizePolicy">
@ -257,79 +61,91 @@
<property name="styleSheet"> <property name="styleSheet">
<string notr="true"/> <string notr="true"/>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin"> <item>
<number>3</number> <layout class="QHBoxLayout" name="horizontalLayout">
</property> <item>
<property name="topMargin"> <widget class="QLabel" name="newCommentLabel_2">
<number>0</number> <property name="sizePolicy">
</property> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<property name="rightMargin"> <horstretch>0</horstretch>
<number>9</number> <verstretch>0</verstretch>
</property> </sizepolicy>
<property name="bottomMargin"> </property>
<number>0</number> <property name="font">
</property> <font>
<property name="verticalSpacing"> <pointsize>12</pointsize>
<number>3</number> <weight>75</weight>
</property> <bold>true</bold>
<item row="0" column="2"> </font>
<spacer name="comment_HSpacer"> </property>
<property name="orientation"> <property name="text">
<enum>Qt::Horizontal</enum> <string>New Comment from </string>
</property> </property>
<property name="sizeType"> <property name="scaledContents">
<enum>QSizePolicy::Expanding</enum> <bool>true</bool>
</property> </property>
<property name="sizeHint" stdset="0"> </widget>
<size> </item>
<width>288</width> <item>
<height>17</height> <widget class="GxsIdLabel" name="nameLabel">
</size> <property name="sizePolicy">
</property> <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
</spacer> <horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
<weight>75</weight>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Name</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item>
<spacer name="comment_HSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>288</width>
<height>17</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="datetimeLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">DateTime</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
</layout>
</item> </item>
<item row="0" column="3"> <item>
<widget class="QLabel" name="datetimeLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">DateTime</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="GxsIdLabel" name="nameLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
<weight>75</weight>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Name</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="1" column="0" colspan="4">
<widget class="QLabel" name="commLabel"> <widget class="QLabel" name="commLabel">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -360,6 +176,202 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<layout class="QHBoxLayout" name="button_HL">
<property name="spacing">
<number>8</number>
</property>
<item>
<layout class="QHBoxLayout" name="vote_HL">
<item>
<widget class="QPushButton" name="voteUpButton">
<property name="toolTip">
<string>I like this</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="scoreLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="voteDownButton">
<property name="toolTip">
<string>I dislike this</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="readButton">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Toggle Message Read Status</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="logoLabel">
<property name="text">
<string>Avatar</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="newCommentLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>New Comment</string>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="subjectLabel">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">POST TITLE</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="button_HSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="copyLinkButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Copy RetroShare Link</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="expandButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Expand</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="readAndClearButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Set as read and remove item</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Remove Item</string>
</property>
</widget>
</item>
</layout>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View file

@ -36,16 +36,11 @@
GxsChannelGroupItem::GxsChannelGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, bool autoUpdate) : GxsChannelGroupItem::GxsChannelGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, bool autoUpdate) :
GxsGroupFeedItem(feedHolder, feedId, groupId, isHome, rsGxsChannels, autoUpdate) GxsGroupFeedItem(feedHolder, feedId, groupId, isHome, rsGxsChannels, autoUpdate)
{ {
setup(); mLoadingGroup = false;
requestGroup(); mLoadingStatus = LOADING_STATUS_NO_DATA;
addEventHandler();
}
GxsChannelGroupItem::GxsChannelGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsChannelGroup &group, bool isHome, bool autoUpdate) :
GxsGroupFeedItem(feedHolder, feedId, group.mMeta.mGroupId, isHome, rsGxsChannels, autoUpdate)
{
setup(); setup();
setGroup(group); requestGroup();
addEventHandler(); addEventHandler();
} }
@ -66,7 +61,8 @@ void GxsChannelGroupItem::addEventHandler()
case RsChannelEventCode::SUBSCRIBE_STATUS_CHANGED: case RsChannelEventCode::SUBSCRIBE_STATUS_CHANGED:
case RsChannelEventCode::UPDATED_CHANNEL: case RsChannelEventCode::UPDATED_CHANNEL:
case RsChannelEventCode::RECEIVED_PUBLISH_KEY: case RsChannelEventCode::RECEIVED_PUBLISH_KEY:
loadGroup(); mLoadingStatus = LOADING_STATUS_NO_DATA;
mGroup = RsGxsChannelGroup();
break; break;
default: default:
break; break;
@ -75,8 +71,42 @@ void GxsChannelGroupItem::addEventHandler()
}, mEventHandlerId, RsEventType::GXS_CHANNELS ); }, mEventHandlerId, RsEventType::GXS_CHANNELS );
} }
void GxsChannelGroupItem::paintEvent(QPaintEvent *e)
{
/* This method employs a trick to trigger a deferred loading. The post and group is requested only
* when actually displayed on the screen. */
if(mLoadingStatus != LOADING_STATUS_FILLED && !mGroup.mMeta.mGroupId.isNull())
mLoadingStatus = LOADING_STATUS_HAS_DATA;
if(mGroup.mMeta.mGroupId.isNull() && !mLoadingGroup)
loadGroup();
switch(mLoadingStatus)
{
case LOADING_STATUS_FILLED:
case LOADING_STATUS_NO_DATA:
default:
break;
case LOADING_STATUS_HAS_DATA:
fill();
mLoadingStatus = LOADING_STATUS_FILLED;
break;
}
GxsGroupFeedItem::paintEvent(e) ;
}
GxsChannelGroupItem::~GxsChannelGroupItem() GxsChannelGroupItem::~GxsChannelGroupItem()
{ {
auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(GROUP_ITEM_LOADING_TIMEOUT_ms);
while( mLoadingGroup && std::chrono::steady_clock::now() < timeout )
{
RsDbg() << __PRETTY_FUNCTION__ << " is Waiting for data to load " << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
rsEvents->unregisterEventsHandler(mEventHandlerId); rsEvents->unregisterEventsHandler(mEventHandlerId);
delete(ui); delete(ui);
} }
@ -105,22 +135,10 @@ void GxsChannelGroupItem::setup()
ui->expandFrame->hide(); ui->expandFrame->hide();
} }
bool GxsChannelGroupItem::setGroup(const RsGxsChannelGroup &group)
{
if (groupId() != group.mMeta.mGroupId) {
std::cerr << "GxsChannelGroupItem::setContent() - Wrong id, cannot set post";
std::cerr << std::endl;
return false;
}
mGroup = group;
fill();
return true;
}
void GxsChannelGroupItem::loadGroup() void GxsChannelGroupItem::loadGroup()
{ {
mLoadingGroup = true;
RsThread::async([this]() RsThread::async([this]()
{ {
// 1 - get group data // 1 - get group data
@ -131,14 +149,16 @@ void GxsChannelGroupItem::loadGroup()
if(!rsGxsChannels->getChannelsInfo(groupIds,groups)) if(!rsGxsChannels->getChannelsInfo(groupIds,groups))
{ {
RsErr() << "PostedItem::loadGroup() ERROR getting data" << std::endl; RsErr() << "PostedItem::loadGroup() ERROR getting data" << std::endl;
return; mLoadingGroup = false;
return;
} }
if (groups.size() != 1) if (groups.size() != 1)
{ {
std::cerr << "GxsGxsChannelGroupItem::loadGroup() Wrong number of Items"; std::cerr << "GxsGxsChannelGroupItem::loadGroup() Wrong number of Items";
std::cerr << std::endl; std::cerr << std::endl;
return; mLoadingGroup = false;
return;
} }
RsGxsChannelGroup group(groups[0]); RsGxsChannelGroup group(groups[0]);
@ -148,7 +168,8 @@ void GxsChannelGroupItem::loadGroup()
* thread, for example to update the data model with new information * thread, for example to update the data model with new information
* after a blocking call to RetroShare API complete */ * after a blocking call to RetroShare API complete */
setGroup(group); mGroup = group;
mLoadingGroup = false;
}, this ); }, this );
}); });

View file

@ -37,19 +37,22 @@ class GxsChannelGroupItem : public GxsGroupFeedItem
public: public:
/** Default Constructor */ /** Default Constructor */
GxsChannelGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, bool autoUpdate); GxsChannelGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, bool autoUpdate);
GxsChannelGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsChannelGroup &group, bool isHome, bool autoUpdate); //GxsChannelGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsChannelGroup &group, bool isHome, bool autoUpdate);
~GxsChannelGroupItem(); virtual ~GxsChannelGroupItem();
bool setGroup(const RsGxsChannelGroup &group);
uint64_t uniqueIdentifier() const override { return hash_64bits("GxsChannelGroupItem " + groupId().toStdString()) ; } uint64_t uniqueIdentifier() const override { return hash_64bits("GxsChannelGroupItem " + groupId().toStdString()) ; }
protected:
/* FeedItem */
virtual void doExpand(bool open);
/* GxsGroupFeedItem */ protected:
virtual QString groupName();
/* FeedItem */
virtual void doExpand(bool open) override;
virtual void paintEvent(QPaintEvent *) override;
/* GxsGroupFeedItem */
virtual QString groupName() override;
virtual void loadGroup() override; virtual void loadGroup() override;
virtual RetroShareLink::enumType getLinkType() { return RetroShareLink::TYPE_CHANNEL; } virtual RetroShareLink::enumType getLinkType() override { return RetroShareLink::TYPE_CHANNEL; }
private slots: private slots:
/* default stuff */ /* default stuff */
@ -62,6 +65,9 @@ private:
void setup(); void setup();
void addEventHandler(); void addEventHandler();
LoadingStatus mLoadingStatus;
bool mLoadingGroup;
private: private:
RsGxsChannelGroup mGroup; RsGxsChannelGroup mGroup;

View file

@ -45,37 +45,9 @@
* #define DEBUG_ITEM 1 * #define DEBUG_ITEM 1
****/ ****/
GxsChannelPostItem::GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId, const RsGroupMetaData& group_meta, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate,const std::set<RsGxsMessageId>& older_versions) :
GxsFeedItem(feedHolder, feedId, group_meta.mGroupId, messageId, isHome, rsGxsChannels, autoUpdate),
mGroupMeta(group_meta)
{
mLoadingGroup = false;
mLoadingMessage = false;
mLoadingComment = false;
mPost.mMeta.mMsgId = messageId; // useful for uniqueIdentifer() before the post is loaded
mPost.mMeta.mGroupId = mGroupMeta.mGroupId;
QVector<RsGxsMessageId> v;
//bool self = false;
for(std::set<RsGxsMessageId>::const_iterator it(older_versions.begin());it!=older_versions.end();++it)
v.push_back(*it) ;
if(older_versions.find(messageId) == older_versions.end())
v.push_back(messageId);
setMessageVersions(v) ;
setup();
// no call to loadGroup() here because we have it already.
}
GxsChannelPostItem::GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId& groupId, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate,const std::set<RsGxsMessageId>& older_versions) : GxsChannelPostItem::GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId& groupId, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate,const std::set<RsGxsMessageId>& older_versions) :
GxsFeedItem(feedHolder, feedId, groupId, messageId, isHome, rsGxsChannels, autoUpdate) // this one should be in GxsFeedItem GxsFeedItem(feedHolder, feedId, groupId, messageId, isHome, rsGxsChannels, autoUpdate) // this one should be in GxsFeedItem
{ {
mPost.mMeta.mMsgId = messageId; // useful for uniqueIdentifer() before the post is loaded
QVector<RsGxsMessageId> v; QVector<RsGxsMessageId> v;
//bool self = false; //bool self = false;
@ -85,70 +57,54 @@ GxsChannelPostItem::GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId,
if(older_versions.find(messageId) == older_versions.end()) if(older_versions.find(messageId) == older_versions.end())
v.push_back(messageId); v.push_back(messageId);
setMessageVersions(v) ; mLoadingStatus = LOADING_STATUS_NO_DATA;
mLoadingMessage = false;
mLoadingGroup = false;
setMessageVersions(v) ;
setup(); setup();
loadGroup();
} }
// GxsChannelPostItem::GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsChannelPost& post, bool isHome, bool autoUpdate,const std::set<RsGxsMessageId>& older_versions) :
// GxsFeedItem(feedHolder, feedId, post.mMeta.mGroupId, post.mMeta.mMsgId, isHome, rsGxsChannels, autoUpdate)
// {
// mPost.mMeta.mMsgId.clear(); // security
// init(post.mMeta.mMsgId,older_versions) ;
// mPost = post ;
// }
// void GxsChannelPostItem::init(const RsGxsMessageId& messageId,const std::set<RsGxsMessageId>& older_versions)
// {
// QVector<RsGxsMessageId> v;
// //bool self = false;
//
// for(std::set<RsGxsMessageId>::const_iterator it(older_versions.begin());it!=older_versions.end();++it)
// v.push_back(*it) ;
//
// if(older_versions.find(messageId) == older_versions.end())
// v.push_back(messageId);
//
// setMessageVersions(v) ;
//
// setup();
//
// mLoaded = false ;
// }
void GxsChannelPostItem::paintEvent(QPaintEvent *e) void GxsChannelPostItem::paintEvent(QPaintEvent *e)
{ {
/* This method employs a trick to trigger a deferred loading. The post and group is requested only /* This method employs a trick to trigger a deferred loading. The post and group is requested only
* when actually displayed on the screen. */ * when actually displayed on the screen. */
if(!mLoaded) if(mLoadingStatus != LOADING_STATUS_FILLED && !mGroupMeta.mGroupId.isNull() && !mPost.mMeta.mMsgId.isNull() )
{ mLoadingStatus = LOADING_STATUS_HAS_DATA;
mLoaded = true ;
std::set<RsGxsMessageId> older_versions; // not so nice. We need to use std::set everywhere if(mGroupMeta.mGroupId.isNull() && !mLoadingGroup)
for(auto& m:messageVersions()) requestGroup();
older_versions.insert(m);
fill(); if(mPost.mMeta.mMsgId.isNull() && !mLoadingMessage)
requestMessage(); requestMessage();
requestComment();
} switch(mLoadingStatus)
{
case LOADING_STATUS_FILLED:
case LOADING_STATUS_NO_DATA:
default:
break;
case LOADING_STATUS_HAS_DATA:
fill();
mLoadingStatus = LOADING_STATUS_FILLED;
break;
}
GxsFeedItem::paintEvent(e) ; GxsFeedItem::paintEvent(e) ;
} }
GxsChannelPostItem::~GxsChannelPostItem() GxsChannelPostItem::~GxsChannelPostItem()
{ {
auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(300); auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(GROUP_ITEM_LOADING_TIMEOUT_ms);
while( (mLoadingGroup || mLoadingMessage || mLoadingComment) while( (mLoadingGroup || mLoadingMessage)
&& std::chrono::steady_clock::now() < timeout) && std::chrono::steady_clock::now() < timeout)
{ {
RsDbg() << __PRETTY_FUNCTION__ << " is Waiting for " RsDbg() << __PRETTY_FUNCTION__ << " is Waiting for "
<< (mLoadingGroup ? "Group " : "") << (mLoadingGroup ? "Group " : "")
<< (mLoadingMessage ? "Message " : "") << (mLoadingMessage ? "Message " : "")
<< (mLoadingComment ? "Comment " : "")
<< "loading." << std::endl; << "loading." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
} }
@ -188,9 +144,7 @@ void GxsChannelPostItem::setup()
setAttribute(Qt::WA_DeleteOnClose, true); setAttribute(Qt::WA_DeleteOnClose, true);
mInFill = false;
mCloseOnRead = false; mCloseOnRead = false;
mLoaded = false;
/* clear ui */ /* clear ui */
ui->titleLabel->setText(tr("Loading...")); ui->titleLabel->setText(tr("Loading..."));
@ -210,7 +164,7 @@ void GxsChannelPostItem::setup()
connect(ui->downloadButton, SIGNAL(clicked()), this, SLOT(download())); connect(ui->downloadButton, SIGNAL(clicked()), this, SLOT(download()));
// HACK FOR NOW. // HACK FOR NOW.
ui->commentButton->hide();// hidden until properly enabled. ui->commentButton->hide();// hidden until properly enabled.
connect(ui->commentButton, SIGNAL(clicked()), this, SLOT(loadComments())); // connect(ui->commentButton, SIGNAL(clicked()), this, SLOT(loadComments()));
connect(ui->playButton, SIGNAL(clicked()), this, SLOT(play(void))); connect(ui->playButton, SIGNAL(clicked()), this, SLOT(play(void)));
//connect(ui->editButton, SIGNAL(clicked()), this, SLOT(edit(void))); //connect(ui->editButton, SIGNAL(clicked()), this, SLOT(edit(void)));
@ -221,8 +175,6 @@ void GxsChannelPostItem::setup()
// hide voting buttons, backend is not implemented yet // hide voting buttons, backend is not implemented yet
ui->voteUpButton->hide(); ui->voteUpButton->hide();
ui->voteDownButton->hide(); ui->voteDownButton->hide();
//connect(ui-> voteUpButton, SIGNAL(clicked()), this, SLOT(makeUpVote()));
//connect(ui->voteDownButton, SIGNAL(clicked()), this, SLOT(makeDownVote()));
ui->scoreLabel->hide(); ui->scoreLabel->hide();
@ -245,55 +197,15 @@ void GxsChannelPostItem::setup()
ui->expandFrame->hide(); ui->expandFrame->hide();
} }
bool GxsChannelPostItem::setPost(const RsGxsChannelPost &post, bool doFill)
{
if (groupId() != post.mMeta.mGroupId || messageId() != post.mMeta.mMsgId) {
std::cerr << "GxsChannelPostItem::setPost() - Wrong id, cannot set post";
std::cerr << std::endl;
return false;
}
mPost = post;
if (doFill) {
fill();
}
updateItem();
return true;
}
QString GxsChannelPostItem::getTitleLabel()
{
return QString::fromUtf8(mPost.mMeta.mMsgName.c_str());
}
QString GxsChannelPostItem::getMsgLabel()
{
//return RsHtml().formatText(NULL, QString::fromUtf8(mPost.mMsg.c_str()), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS);
// Disabled, because emoticon replacement kills performance.
return QString::fromUtf8(mPost.mMsg.c_str());
}
QString GxsChannelPostItem::groupName() QString GxsChannelPostItem::groupName()
{ {
return QString::fromUtf8(mGroupMeta.mGroupName.c_str()); return QString::fromUtf8(mGroupMeta.mGroupName.c_str());
} }
void GxsChannelPostItem::loadComments()
{
QString title = QString::fromUtf8(mPost.mMeta.mMsgName.c_str());
comments(title);
}
void GxsChannelPostItem::loadGroup() void GxsChannelPostItem::loadGroup()
{ {
#ifdef DEBUG_ITEM std::cerr << "GxsChannelGroupItem::loadGroup()" << std::endl;
std::cerr << "GxsChannelGroupItem::loadGroup()";
std::cerr << std::endl;
#endif
mLoadingGroup = true; mLoadingGroup = true;
RsThread::async([this]() RsThread::async([this]()
@ -305,15 +217,17 @@ void GxsChannelPostItem::loadGroup()
if(!rsGxsChannels->getChannelsInfo(groupIds,groups)) // would be better to call channel Summaries for a single group if(!rsGxsChannels->getChannelsInfo(groupIds,groups)) // would be better to call channel Summaries for a single group
{ {
RsErr() << "GxsGxsChannelGroupItem::loadGroup() ERROR getting data" << std::endl; RsErr() << "GxsGxsChannelGroupItem::loadGroup() ERROR getting data for group " << groupId() << std::endl;
return; mLoadingGroup = false;
return;
} }
if (groups.size() != 1) if (groups.size() != 1)
{ {
std::cerr << "GxsGxsChannelGroupItem::loadGroup() Wrong number of Items"; std::cerr << "GxsGxsChannelGroupItem::loadGroup() Wrong number of Items for group " << groupId() ;
std::cerr << std::endl; std::cerr << std::endl;
return; mLoadingGroup = false;
return;
} }
RsGxsChannelGroup group(groups[0]); RsGxsChannelGroup group(groups[0]);
@ -326,6 +240,8 @@ void GxsChannelPostItem::loadGroup()
mGroupMeta = group.mMeta; mGroupMeta = group.mMeta;
mLoadingGroup = false; mLoadingGroup = false;
update(); // this triggers a paintEvent if needed.
}, this ); }, this );
}); });
} }
@ -348,7 +264,8 @@ void GxsChannelPostItem::loadMessage()
if(! rsGxsChannels->getChannelContent( groupId(), std::set<RsGxsMessageId>( { messageId() } ),posts,comments,votes)) if(! rsGxsChannels->getChannelContent( groupId(), std::set<RsGxsMessageId>( { messageId() } ),posts,comments,votes))
{ {
RsErr() << "GxsGxsChannelGroupItem::loadGroup() ERROR getting data" << std::endl; RsErr() << "GxsGxsChannelGroupItem::loadGroup() ERROR getting data" << std::endl;
return; mLoadingMessage = false;
return;
} }
if (posts.size() == 1) if (posts.size() == 1)
@ -360,30 +277,11 @@ void GxsChannelPostItem::loadMessage()
RsQThreadUtils::postToObject( [post,this]() RsQThreadUtils::postToObject( [post,this]()
{ {
setPost(post); mPost = post;
mLoadingMessage = false; mLoadingMessage = false;
update(); // this triggers a paintEvent if needed.
}, this ); }, this );
}
else if(comments.size() == 1)
{
const RsGxsComment& cmt = comments[0];
#ifdef DEBUG_ITEM
std::cerr << (void*)this << ": Obtained comment, setting messageId to threadID = " << cmt.mMeta.mThreadId << std::endl;
#endif
RsQThreadUtils::postToObject( [cmt,this]()
{
ui->newCommentLabel->show();
ui->commLabel->show();
ui->commLabel->setText(QString::fromUtf8(cmt.mComment.c_str()));
//Change this item to be uploaded with thread element.
setMessageId(cmt.mMeta.mThreadId);
requestMessage();
mLoadingMessage = false;
}, this );
} }
else else
{ {
@ -396,70 +294,19 @@ void GxsChannelPostItem::loadMessage()
{ {
removeItem(); removeItem();
mLoadingMessage = false; mLoadingMessage = false;
update(); // this triggers a paintEvent if needed.
}, this ); }, this );
} }
}); });
} }
void GxsChannelPostItem::loadComment()
{
#ifdef DEBUG_ITEM
std::cerr << "GxsChannelPostItem::loadComment()";
std::cerr << std::endl;
#endif
mLoadingComment = true;
RsThread::async([this]()
{
// 1 - get group data
std::set<RsGxsMessageId> msgIds;
for(auto MsgId: messageVersions())
msgIds.insert(MsgId);
std::vector<RsGxsChannelPost> posts;
std::vector<RsGxsComment> comments;
if(! rsGxsChannels->getChannelComments( groupId(),msgIds,comments))
{
RsErr() << "GxsGxsChannelGroupItem::loadGroup() ERROR getting data" << std::endl;
return;
}
int comNb = comments.size();
RsQThreadUtils::postToObject( [comNb,this]()
{
QString sComButText = tr("Comment");
if (comNb == 1)
sComButText = sComButText.append("(1)");
else if(comNb > 1)
sComButText = tr("Comments ").append("(%1)").arg(comNb);
ui->commentButton->setText(sComButText);
mLoadingComment = false;
}, this );
});
}
void GxsChannelPostItem::fill() void GxsChannelPostItem::fill()
{ {
/* fill in */
// if (isLoading()) {
// /* Wait for all requests */
//return;
// }
#ifdef DEBUG_ITEM #ifdef DEBUG_ITEM
std::cerr << "GxsChannelPostItem::fill()"; std::cerr << "GxsChannelPostItem::fill()";
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
mInFill = true;
QString title; QString title;
QString msgText; QString msgText;
//float f = QFontMetricsF(font()).height()/14.0 ; //float f = QFontMetricsF(font()).height()/14.0 ;
@ -562,21 +409,6 @@ void GxsChannelPostItem::fill()
ui->commentButton->hide(); ui->commentButton->hide();
} }
// THIS CODE IS doesn't compile - disabling until fixed.
#if 0
if (post.mComments)
{
QString commentText = QString::number(post.mComments);
commentText += " ";
commentText += tr("Comments");
ui->commentButton->setText(commentText);
}
else
{
ui->commentButton->setText(tr("Comment"));
}
#endif
} }
else else
{ {
@ -642,8 +474,6 @@ void GxsChannelPostItem::fill()
QLayout *layout = ui->expandFrame->layout(); QLayout *layout = ui->expandFrame->layout();
layout->addWidget(fi); layout->addWidget(fi);
} }
mInFill = false;
} }
void GxsChannelPostItem::fillExpandFrame() void GxsChannelPostItem::fillExpandFrame()
@ -684,22 +514,6 @@ void GxsChannelPostItem::setReadStatus(bool isNew, bool isUnread)
ui->feedFrame->style()->polish( ui->feedFrame); ui->feedFrame->style()->polish( ui->feedFrame);
} }
// void GxsChannelPostItem::setFileCleanUpWarning(uint32_t time_left)
// {
// int hours = (int)time_left/3600;
// int minutes = (time_left - hours*3600)%60;
//
// ui->warning_label->setText(tr("Warning! You have less than %1 hours and %2 minute before this file is deleted Consider saving it.").arg(
// QString::number(hours)).arg(QString::number(minutes)));
//
// QFont warnFont = ui->warning_label->font();
// warnFont.setBold(true);
// ui->warning_label->setFont(warnFont);
//
// ui->warn_image_label->setVisible(true);
// ui->warning_label->setVisible(true);
// }
void GxsChannelPostItem::updateItem() void GxsChannelPostItem::updateItem()
{ {
/* fill in */ /* fill in */
@ -874,10 +688,6 @@ void GxsChannelPostItem::play()
void GxsChannelPostItem::readToggled(bool /*checked*/) void GxsChannelPostItem::readToggled(bool /*checked*/)
{ {
if (mInFill) {
return;
}
mCloseOnRead = false; mCloseOnRead = false;
RsGxsGrpMsgIdPair msgPair = std::make_pair(groupId(), messageId()); RsGxsGrpMsgIdPair msgPair = std::make_pair(groupId(), messageId());
@ -887,28 +697,3 @@ void GxsChannelPostItem::readToggled(bool /*checked*/)
//setReadStatus(false, checked); // Updated by events //setReadStatus(false, checked); // Updated by events
} }
void GxsChannelPostItem::makeDownVote()
{
RsGxsGrpMsgIdPair msgId;
msgId.first = mPost.mMeta.mGroupId;
msgId.second = mPost.mMeta.mMsgId;
ui->voteUpButton->setEnabled(false);
ui->voteDownButton->setEnabled(false);
emit vote(msgId, false);
}
void GxsChannelPostItem::makeUpVote()
{
RsGxsGrpMsgIdPair msgId;
msgId.first = mPost.mMeta.mGroupId;
msgId.second = mPost.mMeta.mMsgId;
ui->voteUpButton->setEnabled(false);
ui->voteDownButton->setEnabled(false);
emit vote(msgId, true);
}

View file

@ -44,37 +44,32 @@ public:
GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId& groupId, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate, const std::set<RsGxsMessageId>& older_versions = std::set<RsGxsMessageId>()); GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId& groupId, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate, const std::set<RsGxsMessageId>& older_versions = std::set<RsGxsMessageId>());
#ifdef UNUSED
// This one is used in channel thread widget. We don't want the group data to reload at every post, so we load it in the hosting // This one is used in channel thread widget. We don't want the group data to reload at every post, so we load it in the hosting
// GxsChannelsPostsWidget and pass it to created items. // GxsChannelsPostsWidget and pass it to created items.
GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId, const RsGroupMetaData& group, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate, const std::set<RsGxsMessageId>& older_versions = std::set<RsGxsMessageId>()); GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId, const RsGroupMetaData& group, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate, const std::set<RsGxsMessageId>& older_versions = std::set<RsGxsMessageId>());
#endif
virtual ~GxsChannelPostItem(); virtual ~GxsChannelPostItem();
uint64_t uniqueIdentifier() const override { return hash_64bits("GxsChannelPostItem " + messageId().toStdString()) ; } uint64_t uniqueIdentifier() const override { return hash_64bits("GxsChannelPostItem " + messageId().toStdString()) ; }
bool setGroup(const RsGxsChannelGroup& group, bool doFill = true); protected:
bool setPost(const RsGxsChannelPost& post, bool doFill = true);
//void setFileCleanUpWarning(uint32_t time_left); //void setFileCleanUpWarning(uint32_t time_left);
QString getTitleLabel();
QString getMsgLabel();
const std::list<SubFileItem *> &getFileItems() {return mFileItems; } const std::list<SubFileItem *> &getFileItems() {return mFileItems; }
bool isLoaded() const {return mLoaded;};
bool isUnread() const ; bool isUnread() const ;
void setReadStatus(bool isNew, bool isUnread); void setReadStatus(bool isNew, bool isUnread);
const std::set<RsGxsMessageId>& olderVersions() const { return mPost.mOlderVersions; } const std::set<RsGxsMessageId>& olderVersions() const { return mPost.mOlderVersions; }
static uint64_t computeIdentifier(const RsGxsMessageId& msgid) { return hash64("GxsChannelPostItem " + msgid.toStdString()) ; } static uint64_t computeIdentifier(const RsGxsMessageId& msgid) { return hash64("GxsChannelPostItem " + msgid.toStdString()) ; }
protected:
//void init(const RsGxsMessageId& messageId,const std::set<RsGxsMessageId>& older_versions);
/* FeedItem */ /* FeedItem */
virtual void doExpand(bool open); virtual void doExpand(bool open) override;
virtual void expandFill(bool first); virtual void expandFill(bool first) override;
// This does nothing except triggering the loading of the post data and comments. This function is mainly used to detect // This does nothing except triggering the loading of the post data and comments. This function is mainly used to detect
// when the post is actually made visible. // when the post is actually made visible.
@ -82,14 +77,14 @@ protected:
virtual void paintEvent(QPaintEvent *) override; virtual void paintEvent(QPaintEvent *) override;
/* GxsGroupFeedItem */ /* GxsGroupFeedItem */
virtual QString groupName(); virtual QString groupName() override;
virtual void loadGroup() override; virtual void loadGroup() override;
virtual RetroShareLink::enumType getLinkType() { return RetroShareLink::TYPE_CHANNEL; } virtual RetroShareLink::enumType getLinkType() override{ return RetroShareLink::TYPE_CHANNEL; }
/* GxsFeedItem */ /* GxsFeedItem */
virtual QString messageName(); virtual QString messageName() override;
virtual void loadMessage(); virtual void loadMessage() override;
virtual void loadComment(); virtual void loadComment() override {}
private slots: private slots:
/* default stuff */ /* default stuff */
@ -98,16 +93,12 @@ private slots:
void download(); void download();
void play(); void play();
void edit(); void edit();
void loadComments();
void readToggled(bool checked); void readToggled(bool checked);
void unsubscribeChannel(); void unsubscribeChannel();
void updateItem(); void updateItem();
void makeUpVote();
void makeDownVote();
signals: signals:
void vote(const RsGxsGrpMsgIdPair& msgId, bool up); void vote(const RsGxsGrpMsgIdPair& msgId, bool up);
@ -117,14 +108,12 @@ private:
void fillExpandFrame(); void fillExpandFrame();
private: private:
bool mInFill;
bool mCloseOnRead; bool mCloseOnRead;
bool mLoaded;
LoadingStatus mLoadingStatus;
bool mLoadingMessage; bool mLoadingMessage;
bool mLoadingGroup; bool mLoadingGroup;
bool mLoadingComment;
RsGroupMetaData mGroupMeta; RsGroupMetaData mGroupMeta;
RsGxsChannelPost mPost; RsGxsChannelPost mPost;

View file

@ -34,8 +34,9 @@
GxsForumGroupItem::GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, bool autoUpdate) : GxsForumGroupItem::GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, bool autoUpdate) :
GxsGroupFeedItem(feedHolder, feedId, groupId, isHome, rsGxsForums, autoUpdate) GxsGroupFeedItem(feedHolder, feedId, groupId, isHome, rsGxsForums, autoUpdate)
{ {
setup(); mLoadingGroup = false;
requestGroup(); mLoadingStatus = LOADING_STATUS_NO_DATA;
setup();
addEventHandler(); addEventHandler();
} }
@ -44,8 +45,9 @@ GxsForumGroupItem::GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, co
mAddedModerators(added_moderators), mAddedModerators(added_moderators),
mRemovedModerators(removed_moderators) mRemovedModerators(removed_moderators)
{ {
setup(); mLoadingGroup = false;
requestGroup(); mLoadingStatus = LOADING_STATUS_NO_DATA;
setup();
addEventHandler(); addEventHandler();
} }
@ -66,7 +68,8 @@ void GxsForumGroupItem::addEventHandler()
case RsForumEventCode::SUBSCRIBE_STATUS_CHANGED: case RsForumEventCode::SUBSCRIBE_STATUS_CHANGED:
case RsForumEventCode::UPDATED_FORUM: case RsForumEventCode::UPDATED_FORUM:
case RsForumEventCode::MODERATOR_LIST_CHANGED: case RsForumEventCode::MODERATOR_LIST_CHANGED:
loadGroup(); mLoadingStatus = LOADING_STATUS_NO_DATA;
mGroup = RsGxsForumGroup();
break; break;
default: default:
break; break;
@ -75,16 +78,42 @@ void GxsForumGroupItem::addEventHandler()
}, mEventHandlerId, RsEventType::GXS_FORUMS ); }, mEventHandlerId, RsEventType::GXS_FORUMS );
} }
GxsForumGroupItem::GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsForumGroup &group, bool isHome, bool autoUpdate) : void GxsForumGroupItem::paintEvent(QPaintEvent *e)
GxsGroupFeedItem(feedHolder, feedId, group.mMeta.mGroupId, isHome, rsGxsForums, autoUpdate)
{ {
setup(); /* This method employs a trick to trigger a deferred loading. The post and group is requested only
setGroup(group); * when actually displayed on the screen. */
addEventHandler();
}
if(mLoadingStatus != LOADING_STATUS_FILLED && !mGroup.mMeta.mGroupId.isNull())
mLoadingStatus = LOADING_STATUS_HAS_DATA;
if(mGroup.mMeta.mGroupId.isNull() && !mLoadingGroup)
loadGroup();
switch(mLoadingStatus)
{
case LOADING_STATUS_FILLED:
case LOADING_STATUS_NO_DATA:
default:
break;
case LOADING_STATUS_HAS_DATA:
fill();
mLoadingStatus = LOADING_STATUS_FILLED;
break;
}
GxsGroupFeedItem::paintEvent(e) ;
}
GxsForumGroupItem::~GxsForumGroupItem() GxsForumGroupItem::~GxsForumGroupItem()
{ {
auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(GROUP_ITEM_LOADING_TIMEOUT_ms);
while( mLoadingGroup && std::chrono::steady_clock::now() < timeout )
{
RsDbg() << __PRETTY_FUNCTION__ << " is Waiting for data to load " << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
rsEvents->unregisterEventsHandler(mEventHandlerId); rsEvents->unregisterEventsHandler(mEventHandlerId);
delete(ui); delete(ui);
} }
@ -113,22 +142,10 @@ void GxsForumGroupItem::setup()
ui->expandFrame->hide(); ui->expandFrame->hide();
} }
bool GxsForumGroupItem::setGroup(const RsGxsForumGroup &group)
{
if (groupId() != group.mMeta.mGroupId) {
std::cerr << "GxsForumGroupItem::setContent() - Wrong id, cannot set post";
std::cerr << std::endl;
return false;
}
mGroup = group;
fill();
return true;
}
void GxsForumGroupItem::loadGroup() void GxsForumGroupItem::loadGroup()
{ {
mLoadingGroup = true;
RsThread::async([this]() RsThread::async([this]()
{ {
// 1 - get group data // 1 - get group data
@ -143,14 +160,16 @@ void GxsForumGroupItem::loadGroup()
if(!rsGxsForums->getForumsInfo(forumIds,groups)) if(!rsGxsForums->getForumsInfo(forumIds,groups))
{ {
RsErr() << "GxsForumGroupItem::loadGroup() ERROR getting data" << std::endl; RsErr() << "GxsForumGroupItem::loadGroup() ERROR getting data" << std::endl;
return; mLoadingGroup = false;
return;
} }
if (groups.size() != 1) if (groups.size() != 1)
{ {
std::cerr << "GxsForumGroupItem::loadGroup() Wrong number of Items"; std::cerr << "GxsForumGroupItem::loadGroup() Wrong number of Items";
std::cerr << std::endl; std::cerr << std::endl;
return; mLoadingGroup = false;
return;
} }
RsGxsForumGroup group(groups[0]);// no reference to teporary accross threads! RsGxsForumGroup group(groups[0]);// no reference to teporary accross threads!
@ -160,7 +179,8 @@ void GxsForumGroupItem::loadGroup()
* thread, for example to update the data model with new information * thread, for example to update the data model with new information
* after a blocking call to RetroShare API complete */ * after a blocking call to RetroShare API complete */
setGroup(group); mGroup = group;
mLoadingGroup = false;
}, this ); }, this );
}); });

View file

@ -39,14 +39,15 @@ public:
/** Default Constructor */ /** Default Constructor */
GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, bool autoUpdate); GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, bool autoUpdate);
GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, const std::list<RsGxsId>& added_moderators,const std::list<RsGxsId>& removed_moderators,bool isHome, bool autoUpdate); GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, const std::list<RsGxsId>& added_moderators,const std::list<RsGxsId>& removed_moderators,bool isHome, bool autoUpdate);
GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsForumGroup &group, bool isHome, bool autoUpdate); //GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsForumGroup &group, bool isHome, bool autoUpdate);
virtual ~GxsForumGroupItem() override;
bool setGroup(const RsGxsForumGroup &group); virtual ~GxsForumGroupItem() override;
uint64_t uniqueIdentifier() const override { return hash_64bits("GxsForumGroupItem " + groupId().toStdString()) ; } uint64_t uniqueIdentifier() const override { return hash_64bits("GxsForumGroupItem " + groupId().toStdString()) ; }
protected: protected:
/* FeedItem */ virtual void paintEvent(QPaintEvent *) override;
/* FeedItem */
virtual void doExpand(bool open) override; virtual void doExpand(bool open) override;
/* GxsGroupFeedItem */ /* GxsGroupFeedItem */
@ -69,6 +70,9 @@ private:
/** Qt Designer generated object */ /** Qt Designer generated object */
Ui::GxsForumGroupItem *ui; Ui::GxsForumGroupItem *ui;
bool mLoadingGroup;
LoadingStatus mLoadingStatus;
std::list<RsGxsId> mAddedModerators; std::list<RsGxsId> mAddedModerators;
std::list<RsGxsId> mRemovedModerators; std::list<RsGxsId> mRemovedModerators;

View file

@ -45,59 +45,60 @@
GxsForumMsgItem::GxsForumMsgItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate) : GxsForumMsgItem::GxsForumMsgItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate) :
GxsFeedItem(feedHolder, feedId, groupId, messageId, isHome, rsGxsForums, autoUpdate) GxsFeedItem(feedHolder, feedId, groupId, messageId, isHome, rsGxsForums, autoUpdate)
{ {
mMessage.mMeta.mMsgId = messageId; // useful for uniqueIdentifier() before the post is actually loaded mLoadingStatus = LOADING_STATUS_NO_DATA;
mMessage.mMeta.mGroupId = groupId;
mLoadingGroup = false; mLoadingGroup = false;
mLoadingMessage = false; mLoadingMessage = false;
mLoadingSetAsRead = false; mLoadingSetAsRead = false;
mLoadingParentMessage = false;
setup(); setup();
requestGroup();
requestMessage();
} }
GxsForumMsgItem::GxsForumMsgItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsForumGroup &group, const RsGxsForumMsg &post, bool isHome, bool autoUpdate) : void GxsForumMsgItem::paintEvent(QPaintEvent *e)
GxsFeedItem(feedHolder, feedId, post.mMeta.mGroupId, post.mMeta.mMsgId, isHome, rsGxsForums, autoUpdate)
{ {
#ifdef DEBUG_ITEM /* This method employs a trick to trigger a deferred loading. The post and group is requested only
std::cerr << "GxsForumMsgItem::GxsForumMsgItem() Direct Load"; * when actually displayed on the screen. */
std::cerr << std::endl;
#endif
setup(); if(mLoadingStatus != LOADING_STATUS_FILLED && !mGroup.mMeta.mGroupId.isNull() && !mMessage.mMeta.mMsgId.isNull())
mLoadingStatus = LOADING_STATUS_HAS_DATA;
setGroup(group, false); if(mGroup.mMeta.mGroupId.isNull() && !mLoadingGroup)
setMessage(post); requestGroup();
}
GxsForumMsgItem::GxsForumMsgItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsForumMsg &post, bool isHome, bool autoUpdate) : if(mMessage.mMeta.mMsgId.isNull() && !mLoadingMessage)
GxsFeedItem(feedHolder, feedId, post.mMeta.mGroupId, post.mMeta.mMsgId, isHome, rsGxsForums, autoUpdate) requestMessage();
{
#ifdef DEBUG_ITEM
std::cerr << "GxsForumMsgItem::GxsForumMsgItem() Direct Load";
std::cerr << std::endl;
#endif
setup(); switch(mLoadingStatus)
{
case LOADING_STATUS_FILLED:
case LOADING_STATUS_NO_DATA:
default:
break;
requestGroup(); case LOADING_STATUS_HAS_DATA:
setMessage(post); fillGroup();
fillMessage();
if(!mParentMessage.mMeta.mMsgId.isNull())
fillParentMessage();
mLoadingStatus = LOADING_STATUS_FILLED;
break;
}
GxsFeedItem::paintEvent(e) ;
} }
GxsForumMsgItem::~GxsForumMsgItem() GxsForumMsgItem::~GxsForumMsgItem()
{ {
auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(300); auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(GROUP_ITEM_LOADING_TIMEOUT_ms);
while( (mLoadingGroup || mLoadingMessage || mLoadingSetAsRead || mLoadingParentMessage) while( (mLoadingGroup || mLoadingMessage || mLoadingSetAsRead)
&& std::chrono::steady_clock::now() < timeout) && std::chrono::steady_clock::now() < timeout)
{ {
RsDbg() << __PRETTY_FUNCTION__ << " is Waiting for " RsDbg() << __PRETTY_FUNCTION__ << " is Waiting for "
<< (mLoadingGroup ? "Group " : "") << (mLoadingGroup ? "Group " : "")
<< (mLoadingMessage ? "Message " : "") << (mLoadingMessage ? "Message " : "")
<< (mLoadingParentMessage ? "Parent message " : "")
<< (mLoadingSetAsRead ? "Set as read" : "") << (mLoadingSetAsRead ? "Set as read" : "")
<< "loading." << std::endl; << "loading." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
@ -113,7 +114,6 @@ void GxsForumMsgItem::setup()
setAttribute(Qt::WA_DeleteOnClose, true); setAttribute(Qt::WA_DeleteOnClose, true);
mInFill = false;
mCloseOnRead = false; mCloseOnRead = false;
/* clear ui */ /* clear ui */
@ -144,41 +144,6 @@ void GxsForumMsgItem::setup()
ui->parentFrame->hide(); ui->parentFrame->hide();
} }
bool GxsForumMsgItem::setGroup(const RsGxsForumGroup &group, bool doFill)
{
if (groupId() != group.mMeta.mGroupId) {
std::cerr << "GxsForumMsgItem::setGroup() - Wrong id, cannot set post";
std::cerr << std::endl;
return false;
}
mGroup = group;
if (doFill)
fillGroup();
return true;
}
bool GxsForumMsgItem::setMessage(const RsGxsForumMsg &msg, bool doFill)
{
if (groupId() != msg.mMeta.mGroupId || messageId() != msg.mMeta.mMsgId) {
std::cerr << "GxsForumMsgItem::setPost() - Wrong id, cannot set post";
std::cerr << std::endl;
return false;
}
mMessage = msg;
if(! mMessage.mMeta.mParentId.isNull())
loadParentMessage(mMessage.mMeta.mParentId);
if(doFill)
fillMessage();
return true;
}
QString GxsForumMsgItem::groupName() QString GxsForumMsgItem::groupName()
{ {
return QString::fromUtf8(mGroup.mMeta.mGroupName.c_str()); return QString::fromUtf8(mGroup.mMeta.mGroupName.c_str());
@ -192,24 +157,25 @@ void GxsForumMsgItem::loadGroup()
{ {
// 1 - get group data // 1 - get group data
#ifdef DEBUG_FORUMS #ifndef DEBUG_FORUMS
std::cerr << "Retrieving post data for post " << mThreadId << std::endl; std::cerr << "Retrieving forum group data for forum " << groupId() << std::endl;
#endif #endif
std::vector<RsGxsForumGroup> groups; std::vector<RsGxsForumGroup> groups;
const std::list<RsGxsGroupId> forumIds = { groupId() };
if(!rsGxsForums->getForumsInfo(forumIds,groups)) if(!rsGxsForums->getForumsInfo({ groupId() },groups))
{ {
RsErr() << "GxsForumGroupItem::loadGroup() ERROR getting data" << std::endl; RsErr() << "GxsForumGroupItem::loadGroup() ERROR getting data" << std::endl;
return; mLoadingGroup = false;
return;
} }
if (groups.size() != 1) if (groups.size() != 1)
{ {
std::cerr << "GxsForumGroupItem::loadGroup() Wrong number of Items"; std::cerr << "GxsForumGroupItem::loadGroup() Wrong number of Items";
std::cerr << std::endl; std::cerr << std::endl;
return; mLoadingGroup = false;
return;
} }
RsGxsForumGroup group(groups[0]); RsGxsForumGroup group(groups[0]);
@ -219,7 +185,7 @@ void GxsForumMsgItem::loadGroup()
* thread, for example to update the data model with new information * thread, for example to update the data model with new information
* after a blocking call to RetroShare API complete */ * after a blocking call to RetroShare API complete */
setGroup(group); mGroup = group;
mLoadingGroup = false; mLoadingGroup = false;
}, this ); }, this );
@ -242,89 +208,50 @@ void GxsForumMsgItem::loadMessage()
std::cerr << "Retrieving post data for post " << mThreadId << std::endl; std::cerr << "Retrieving post data for post " << mThreadId << std::endl;
#endif #endif
std::vector<RsGxsForumMsg> msgs; auto getMessageData = [](const RsGxsGroupId& gid,const RsGxsMessageId& msg_id,RsGxsForumMsg& msg) -> bool
const std::list<RsGxsGroupId> forumIds = { groupId() }; {
std::vector<RsGxsForumMsg> msgs;
if(!rsGxsForums->getForumContent(groupId(),std::set<RsGxsMessageId>( { messageId() } ),msgs)) if(!rsGxsForums->getForumContent(gid,std::set<RsGxsMessageId>( { msg_id } ),msgs))
{ return false;
std::cerr << "GxsForumMsgItem::loadMessage() ERROR getting data";
std::cerr << std::endl;
return;
}
if (msgs.size() != 1) if (msgs.size() != 1)
{ return false;
std::cerr << "GxsForumMsgItem::loadMessage() Wrong number of Items";
std::cerr << std::endl;
return;
}
RsGxsForumMsg msg(msgs[0]);
RsQThreadUtils::postToObject( [msg,this]() msg = msgs[0];
return true;
};
RsGxsForumMsg msg,parent_msg;
if(!getMessageData(groupId(),messageId(),msg))
{
std::cerr << "GxsForumMsgItem::loadMessage() ERROR getting message data";
mLoadingMessage = false;
return;
}
// now load the parent message. If not found, it's not a problem.
if(!msg.mMeta.mParentId.isNull() && !getMessageData(groupId(),msg.mMeta.mParentId,parent_msg))
std::cerr << "GxsForumMsgItem::loadMessage() ERROR getting parent message data. Maybe the parent msg is not available.";
RsQThreadUtils::postToObject( [msg,parent_msg,this]()
{ {
/* Here it goes any code you want to be executed on the Qt Gui /* Here it goes any code you want to be executed on the Qt Gui
* thread, for example to update the data model with new information * thread, for example to update the data model with new information
* after a blocking call to RetroShare API complete */ * after a blocking call to RetroShare API complete */
setMessage(msg); mMessage = msg;
mParentMessage = parent_msg;
mLoadingMessage = false; mLoadingMessage = false;
}, this ); }, this );
}); });
} }
void GxsForumMsgItem::loadParentMessage(const RsGxsMessageId& parent_msg)
{
#ifdef DEBUG_ITEM
std::cerr << "GxsForumMsgItem::loadParentMessage()";
std::cerr << std::endl;
#endif
mLoadingParentMessage = true;
RsThread::async([parent_msg,this]()
{
// 1 - get group data
#ifdef DEBUG_FORUMS
std::cerr << "Retrieving post data for post " << mThreadId << std::endl;
#endif
std::vector<RsGxsForumMsg> msgs;
const std::list<RsGxsGroupId> forumIds = { groupId() };
if(!rsGxsForums->getForumContent(groupId(),std::set<RsGxsMessageId>( { parent_msg } ),msgs))
{
std::cerr << "GxsForumMsgItem::loadMessage() ERROR getting data";
std::cerr << std::endl;
return;
}
if (msgs.size() != 1)
{
std::cerr << "GxsForumMsgItem::loadMessage() Wrong number of Items";
std::cerr << std::endl;
return;
}
RsGxsForumMsg msg(msgs[0]);
RsQThreadUtils::postToObject( [msg,this]()
{
/* Here it goes any code you want to be executed on the Qt Gui
* thread, for example to update the data model with new information
* after a blocking call to RetroShare API complete */
mParentMessage = msg;
fillParentMessage();
mLoadingParentMessage = false;
}, this );
});
}
void GxsForumMsgItem::fillParentMessage() void GxsForumMsgItem::fillParentMessage()
{ {
mInFill = true;
ui->parentFrame->hide(); ui->parentFrame->hide();
RetroShareLink linkParent = RetroShareLink::createGxsMessageLink(RetroShareLink::TYPE_FORUM, mParentMessage.mMeta.mGroupId, mParentMessage.mMeta.mMsgId, QString::fromUtf8(mParentMessage.mMeta.mMsgName.c_str())); RetroShareLink linkParent = RetroShareLink::createGxsMessageLink(RetroShareLink::TYPE_FORUM, mParentMessage.mMeta.mGroupId, mParentMessage.mMeta.mMsgId, QString::fromUtf8(mParentMessage.mMeta.mMsgName.c_str()));
@ -341,8 +268,6 @@ void GxsForumMsgItem::fillParentMessage()
pixmap = GxsIdDetails::makeDefaultIcon(mParentMessage.mMeta.mAuthorId,GxsIdDetails::SMALL); pixmap = GxsIdDetails::makeDefaultIcon(mParentMessage.mMeta.mAuthorId,GxsIdDetails::SMALL);
ui->parentAvatar->setPixmap(pixmap); ui->parentAvatar->setPixmap(pixmap);
mInFill = false;
} }
void GxsForumMsgItem::fillMessage() void GxsForumMsgItem::fillMessage()
{ {
@ -351,8 +276,6 @@ void GxsForumMsgItem::fillMessage()
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
mInFill = true;
if(!mIsHome && mCloseOnRead && !IS_MSG_NEW(mMessage.mMeta.mMsgStatus)) if(!mIsHome && mCloseOnRead && !IS_MSG_NEW(mMessage.mMeta.mMsgStatus))
removeItem(); removeItem();
@ -394,21 +317,15 @@ void GxsForumMsgItem::fillMessage()
ui->clearButton->setEnabled(false); ui->clearButton->setEnabled(false);
ui->clearButton->hide(); ui->clearButton->hide();
} }
mInFill = false;
} }
void GxsForumMsgItem::fillGroup() void GxsForumMsgItem::fillGroup()
{ {
mInFill = true;
ui->unsubscribeButton->setEnabled(IS_GROUP_SUBSCRIBED(mGroup.mMeta.mSubscribeFlags) || IS_GROUP_ADMIN(mGroup.mMeta.mSubscribeFlags)) ; ui->unsubscribeButton->setEnabled(IS_GROUP_SUBSCRIBED(mGroup.mMeta.mSubscribeFlags) || IS_GROUP_ADMIN(mGroup.mMeta.mSubscribeFlags)) ;
if (IS_GROUP_PUBLISHER(mGroup.mMeta.mSubscribeFlags)) if (IS_GROUP_PUBLISHER(mGroup.mMeta.mSubscribeFlags))
ui->iconLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/icons/png/forums.png")); ui->iconLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/icons/png/forums.png"));
else else
ui->iconLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/icons/png/forums-default.png")); ui->iconLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/icons/png/forums-default.png"));
mInFill = false;
} }
void GxsForumMsgItem::fillExpandFrame() void GxsForumMsgItem::fillExpandFrame()
@ -502,10 +419,6 @@ void GxsForumMsgItem::unsubscribeForum()
void GxsForumMsgItem::setAsRead(bool doUpdate) void GxsForumMsgItem::setAsRead(bool doUpdate)
{ {
if (mInFill) {
return;
}
mCloseOnRead = false; mCloseOnRead = false;
mLoadingSetAsRead = true; mLoadingSetAsRead = true;

View file

@ -36,27 +36,20 @@ class GxsForumMsgItem : public GxsFeedItem
public: public:
GxsForumMsgItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate); GxsForumMsgItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate);
GxsForumMsgItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsForumGroup &group, const RsGxsForumMsg &post, bool isHome, bool autoUpdate);
GxsForumMsgItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsForumMsg &post, bool isHome, bool autoUpdate);
virtual ~GxsForumMsgItem();
bool setGroup(const RsGxsForumGroup &group, bool doFill = true); virtual ~GxsForumMsgItem();
bool setMessage(const RsGxsForumMsg &msg, bool doFill = true);
uint64_t uniqueIdentifier() const override { return hash_64bits("GxsForumMsgItem " + messageId().toStdString()) ; } uint64_t uniqueIdentifier() const override { return hash_64bits("GxsForumMsgItem " + messageId().toStdString()) ; }
protected: protected:
/* FeedItem */ virtual void paintEvent(QPaintEvent *e) override;
/* FeedItem */
virtual void doExpand(bool open) override; virtual void doExpand(bool open) override;
virtual void expandFill(bool first) override; virtual void expandFill(bool first) override;
/* load message data */
virtual void loadParentMessage(const RsGxsMessageId &parent_msg);
/* GxsGroupFeedItem */ /* GxsGroupFeedItem */
virtual QString groupName() override; virtual QString groupName() override;
virtual void loadGroup() override; virtual void loadGroup() override;
virtual RetroShareLink::enumType getLinkType() override { return RetroShareLink::TYPE_FORUM; } virtual RetroShareLink::enumType getLinkType() override { return RetroShareLink::TYPE_FORUM; }
//virtual bool isLoading();
/* GxsFeedItem */ /* GxsFeedItem */
virtual QString messageName() override; virtual QString messageName() override;
@ -77,6 +70,7 @@ signals:
private: private:
void setup(); void setup();
void fillGroup(); void fillGroup();
void fillMessage(); void fillMessage();
void fillParentMessage(); void fillParentMessage();
@ -85,16 +79,19 @@ private:
void setAsRead(bool doUpdate); void setAsRead(bool doUpdate);
private: private:
bool mInFill;
bool mCloseOnRead; bool mCloseOnRead;
LoadingStatus mLoadingStatus;
bool mLoadingMessage; bool mLoadingMessage;
bool mLoadingParentMessage;
bool mLoadingGroup; bool mLoadingGroup;
bool mLoadingSetAsRead; bool mLoadingSetAsRead;
bool mHasParentMessage; // set to false when we see that the msg does not have a parent.
RsGxsForumGroup mGroup; RsGxsForumGroup mGroup;
RsGxsForumMsg mMessage; RsGxsForumMsg mMessage;
RsGxsForumMsg mParentMessage; RsGxsForumMsg mParentMessage;
/** Qt Designer generated object */ /** Qt Designer generated object */
Ui::GxsForumMsgItem *ui; Ui::GxsForumMsgItem *ui;

View file

@ -35,21 +35,50 @@
PostedGroupItem::PostedGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, bool autoUpdate) : PostedGroupItem::PostedGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, bool autoUpdate) :
GxsGroupFeedItem(feedHolder, feedId, groupId, isHome, rsPosted, autoUpdate) GxsGroupFeedItem(feedHolder, feedId, groupId, isHome, rsPosted, autoUpdate)
{ {
setup(); mLoadingGroup = false;
mLoadingStatus = LOADING_STATUS_NO_DATA;
requestGroup(); setup();
} }
PostedGroupItem::PostedGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsPostedGroup &group, bool isHome, bool autoUpdate) : void PostedGroupItem::paintEvent(QPaintEvent *e)
GxsGroupFeedItem(feedHolder, feedId, group.mMeta.mGroupId, isHome, rsPosted, autoUpdate)
{ {
setup(); /* This method employs a trick to trigger a deferred loading. The post and group is requested only
* when actually displayed on the screen. */
setGroup(group); if(mLoadingStatus != LOADING_STATUS_FILLED && !mGroup.mMeta.mGroupId.isNull())
mLoadingStatus = LOADING_STATUS_HAS_DATA;
if(mGroup.mMeta.mGroupId.isNull() && !mLoadingGroup)
loadGroup();
switch(mLoadingStatus)
{
case LOADING_STATUS_FILLED:
case LOADING_STATUS_NO_DATA:
default:
break;
case LOADING_STATUS_HAS_DATA:
fill();
mLoadingStatus = LOADING_STATUS_FILLED;
break;
}
GxsGroupFeedItem::paintEvent(e) ;
} }
PostedGroupItem::~PostedGroupItem() PostedGroupItem::~PostedGroupItem()
{ {
auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(GROUP_ITEM_LOADING_TIMEOUT_ms);
while( mLoadingGroup && std::chrono::steady_clock::now() < timeout)
{
RsDbg() << __PRETTY_FUNCTION__ << " is Waiting "
<< (mLoadingGroup ? "Group " : "")
<< "loading finished." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
delete(ui); delete(ui);
} }
@ -79,22 +108,10 @@ void PostedGroupItem::setup()
ui->expandFrame->hide(); ui->expandFrame->hide();
} }
bool PostedGroupItem::setGroup(const RsPostedGroup &group)
{
if (groupId() != group.mMeta.mGroupId) {
std::cerr << "PostedGroupItem::setContent() - Wrong id, cannot set post";
std::cerr << std::endl;
return false;
}
mGroup = group;
fill();
return true;
}
void PostedGroupItem::loadGroup() void PostedGroupItem::loadGroup()
{ {
mLoadingGroup = true;
RsThread::async([this]() RsThread::async([this]()
{ {
// 1 - get group data // 1 - get group data
@ -109,14 +126,16 @@ void PostedGroupItem::loadGroup()
if(!rsPosted->getBoardsInfo(groupIds,groups)) if(!rsPosted->getBoardsInfo(groupIds,groups))
{ {
RsErr() << "GxsPostedGroupItem::loadGroup() ERROR getting data" << std::endl; RsErr() << "GxsPostedGroupItem::loadGroup() ERROR getting data" << std::endl;
return; mLoadingGroup = false;
return;
} }
if (groups.size() != 1) if (groups.size() != 1)
{ {
std::cerr << "GxsPostedGroupItem::loadGroup() Wrong number of Items"; std::cerr << "GxsPostedGroupItem::loadGroup() Wrong number of Items";
std::cerr << std::endl; std::cerr << std::endl;
return; mLoadingGroup = false;
return;
} }
RsPostedGroup group(groups[0]); RsPostedGroup group(groups[0]);
@ -126,7 +145,8 @@ void PostedGroupItem::loadGroup()
* thread, for example to update the data model with new information * thread, for example to update the data model with new information
* after a blocking call to RetroShare API complete */ * after a blocking call to RetroShare API complete */
setGroup(group); mGroup = group;
mLoadingGroup = false;
}, this ); }, this );
}); });

View file

@ -37,21 +37,20 @@ class PostedGroupItem : public GxsGroupFeedItem
public: public:
/** Default Constructor */ /** Default Constructor */
PostedGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, bool autoUpdate); PostedGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, bool autoUpdate);
PostedGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsPostedGroup &group, bool isHome, bool autoUpdate); virtual ~PostedGroupItem() override;
~PostedGroupItem();
bool setGroup(const RsPostedGroup &group);
uint64_t uniqueIdentifier() const override { return hash_64bits("PostedGroupItem " + groupId().toStdString()) ; } uint64_t uniqueIdentifier() const override { return hash_64bits("PostedGroupItem " + groupId().toStdString()) ; }
protected: protected:
virtual void paintEvent(QPaintEvent *e) override;
/* FeedItem */ /* FeedItem */
virtual void doExpand(bool open); virtual void doExpand(bool open) override;
/* GxsGroupFeedItem */ /* GxsGroupFeedItem */
virtual QString groupName(); virtual QString groupName() override;
virtual void loadGroup() override; virtual void loadGroup() override;
virtual RetroShareLink::enumType getLinkType() { return RetroShareLink::TYPE_UNKNOWN; } virtual RetroShareLink::enumType getLinkType() override { return RetroShareLink::TYPE_UNKNOWN; }
private slots: private slots:
void toggle() override; void toggle() override;
@ -63,6 +62,8 @@ private:
private: private:
RsPostedGroup mGroup; RsPostedGroup mGroup;
bool mLoadingGroup;
LoadingStatus mLoadingStatus;
/** Qt Designer generated object */ /** Qt Designer generated object */
Ui::PostedGroupItem *ui; Ui::PostedGroupItem *ui;

View file

@ -31,6 +31,8 @@
* #define DEBUG_ITEM 1 * #define DEBUG_ITEM 1
**/ **/
const uint GxsGroupFeedItem::GROUP_ITEM_LOADING_TIMEOUT_ms = 2000;
GxsGroupFeedItem::GxsGroupFeedItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, RsGxsIfaceHelper *iface, bool /*autoUpdate*/) : GxsGroupFeedItem::GxsGroupFeedItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, RsGxsIfaceHelper *iface, bool /*autoUpdate*/) :
FeedItem(feedHolder,feedId,NULL) FeedItem(feedHolder,feedId,NULL)
{ {

View file

@ -45,6 +45,12 @@ public:
uint32_t feedId() const { return mFeedId; } uint32_t feedId() const { return mFeedId; }
protected: protected:
enum LoadingStatus {
LOADING_STATUS_NO_DATA = 0x00,
LOADING_STATUS_HAS_DATA = 0x01,
LOADING_STATUS_FILLED = 0x02
};
/* load group data */ /* load group data */
void requestGroup(); void requestGroup();
@ -60,6 +66,7 @@ protected slots:
protected: protected:
bool mIsHome; bool mIsHome;
RsGxsIfaceHelper *mGxsIface; RsGxsIfaceHelper *mGxsIface;
static const uint GROUP_ITEM_LOADING_TIMEOUT_ms ;
private slots: private slots:
/* RsGxsUpdateBroadcastBase */ /* RsGxsUpdateBroadcastBase */

@ -1 +1 @@
Subproject commit 3460cd809b6dd311b58e92733ece2fc956224fd2 Subproject commit b9c7a496ba7dd9c3495bae2ff2855899e47b245d

@ -1 +1 @@
Subproject commit f90555ba4d6f9fadb6f0fbb1e2253e13557aad34 Subproject commit 8623304b62294dafbe477573f321a464fef721dd

@ -1 +1 @@
Subproject commit 24b5e7a8b27f42fa16b96fc70aade9106cf7102f Subproject commit f54b0e47a08782a6131cc3d60f94d038fa6e0a51