Merge pull request #2681 from csoler/v0.6-BugFixing_20

Attempt at not reloading full channel data at every change (needs PR #81)
This commit is contained in:
csoler 2023-03-30 10:33:38 +02:00 committed by GitHub
commit 8475a7424d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 774 additions and 612 deletions

@ -1 +1 @@
Subproject commit 2ddc86fb575a61170f4c06a00152e3e7dc74c8f4 Subproject commit 659423769541169457c41f71c8a038e2d64ba079

@ -1 +1 @@
Subproject commit a9d4447c5660337b4f7945d20e0f4ffd68d918e9 Subproject commit 74cd958cf8a3c8b3e2d3f8a22657b5e16bdad476

View File

@ -33,11 +33,11 @@
#include "GxsChannelPostFilesModel.h" #include "GxsChannelPostFilesModel.h"
//#define DEBUG_CHANNEL_MODEL //#define DEBUG_CHANNEL_FILES_MODEL
Q_DECLARE_METATYPE(ChannelPostFileInfo) Q_DECLARE_METATYPE(ChannelPostFileInfo)
#ifdef DEBUG_CHANNEL_MODEL #ifdef DEBUG_CHANNEL_FILES_MODEL
static std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere static std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere
#endif #endif
@ -161,8 +161,8 @@ QModelIndex RsGxsChannelPostFilesModel::index(int row, int column, const QModelI
quintptr ref = getChildRef(parent.internalId(),row); quintptr ref = getChildRef(parent.internalId(),row);
#ifdef DEBUG_CHANNEL_MODEL #ifdef DEBUG_CHANNEL_FILES_MODEL
std::cerr << "index-3(" << row << "," << column << " parent=" << parent << ") : " << createIndex(row,column,ref) << std::endl; RsDbg() << "index-3(" << row << "," << column << " parent=" << parent << ") : " << createIndex(row,column,ref) ;
#endif #endif
return createIndex(row,column,ref) ; return createIndex(row,column,ref) ;
} }
@ -242,7 +242,7 @@ QVariant RsGxsChannelPostFilesModel::headerData(int section, Qt::Orientation /*o
QVariant RsGxsChannelPostFilesModel::data(const QModelIndex &index, int role) const QVariant RsGxsChannelPostFilesModel::data(const QModelIndex &index, int role) const
{ {
#ifdef DEBUG_CHANNEL_MODEL #ifdef DEBUG_CHANNEL_FILES_MODEL
std::cerr << "calling data(" << index << ") role=" << role << std::endl; std::cerr << "calling data(" << index << ") role=" << role << std::endl;
#endif #endif
@ -259,13 +259,13 @@ QVariant RsGxsChannelPostFilesModel::data(const QModelIndex &index, int role) co
quintptr ref = (index.isValid())?index.internalId():0 ; quintptr ref = (index.isValid())?index.internalId():0 ;
uint32_t entry = 0; uint32_t entry = 0;
#ifdef DEBUG_CHANNEL_MODEL #ifdef DEBUG_CHANNEL_FILES_MODEL
std::cerr << "data(" << index << ")" ; std::cerr << "data(" << index << ")" ;
#endif #endif
if(!ref) if(!ref)
{ {
#ifdef DEBUG_CHANNEL_MODEL #ifdef DEBUG_CHANNEL_FILES_MODEL
std::cerr << " [empty]" << std::endl; std::cerr << " [empty]" << std::endl;
#endif #endif
return QVariant() ; return QVariant() ;
@ -273,7 +273,7 @@ QVariant RsGxsChannelPostFilesModel::data(const QModelIndex &index, int role) co
if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFilteredFiles.size()) if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFilteredFiles.size())
{ {
#ifdef DEBUG_CHANNEL_MODEL #ifdef DEBUG_CHANNEL_FILES_MODEL
std::cerr << "Bad pointer: " << (void*)ref << std::endl; std::cerr << "Bad pointer: " << (void*)ref << std::endl;
#endif #endif
return QVariant() ; return QVariant() ;
@ -426,7 +426,6 @@ QVariant RsGxsChannelPostFilesModel::userRole(const ChannelPostFileInfo& fmpe,in
void RsGxsChannelPostFilesModel::clear() void RsGxsChannelPostFilesModel::clear()
{ {
initEmptyHierarchy(); initEmptyHierarchy();
emit channelLoaded(); emit channelLoaded();
@ -444,7 +443,7 @@ void RsGxsChannelPostFilesModel::setFiles(const std::list<ChannelPostFileInfo> &
for(uint32_t i=0;i<mFiles.size();++i) for(uint32_t i=0;i<mFiles.size();++i)
mFilteredFiles.push_back(i); mFilteredFiles.push_back(i);
#ifdef DEBUG_CHANNEL_MODEL #ifdef DEBUG_CHANNEL_FILES_MODEL
// debug_dump(); // debug_dump();
#endif #endif
@ -463,3 +462,61 @@ void RsGxsChannelPostFilesModel::setFiles(const std::list<ChannelPostFileInfo> &
postMods(); postMods();
} }
void RsGxsChannelPostFilesModel::update_files(std::set<ChannelPostFileInfo>& added_files,std::set<ChannelPostFileInfo>& removed_files)
{
// 1 - remove common files from both lists
#ifdef DEBUG_CHANNEL_FILES_MODEL
RsDbg() << "RsGxsChannelPostsFilesModel:: updating files." ;
#endif
for(auto afit=added_files.begin();afit!=added_files.end();)
{
auto rfit = removed_files.find(*afit);
if(rfit != removed_files.end())
{
#ifdef DEBUG_CHANNEL_FILES_MODEL
RsDbg() << " Eliminating common file " << rfit->mName ;
#endif
removed_files.erase(rfit);
auto tmp = afit;
++tmp;
added_files.erase(afit);
afit = tmp;
}
else
++afit;
}
RsDbg() << " Remains: " << added_files.size() << " added files and " << removed_files.size() << " removed files" ;
// 2 - add whatever file remains,
for(const auto& f:removed_files)
{
#ifdef DEBUG_CHANNEL_FILES_MODEL
RsDbg() << " Removing deleted file " << f.mName ;
#endif
for(uint32_t i=0;i<mFiles.size();++i)
if(mFiles[i].mHash == f.mHash)
{
mFiles[i] = mFiles.back();
mFiles.pop_back();
break;
}
}
// 3 - add other files. We do not check that they are duplicates, because the list of files includes duplicates.
for(const auto& f:added_files )
{
#ifdef DEBUG_CHANNEL_FILES_MODEL
RsDbg() << " Adding new file " << f.mName ;
#endif
mFilteredFiles.push_back(mFiles.size());
mFiles.push_back(f);
}
}

View File

@ -46,7 +46,7 @@ struct ChannelPostFileInfo: public RsGxsFile
ChannelPostFileInfo() : mPublishTime(0) {} ChannelPostFileInfo() : mPublishTime(0) {}
rstime_t mPublishTime; rstime_t mPublishTime; // related post publish time
}; };
// This class is the item model used by Qt to display the information // This class is the item model used by Qt to display the information
@ -83,6 +83,9 @@ public:
void setFiles(const std::list<ChannelPostFileInfo>& files); void setFiles(const std::list<ChannelPostFileInfo>& files);
void setFilter(const QStringList &strings, uint32_t &count) ; void setFilter(const QStringList &strings, uint32_t &count) ;
// This method adds/removes the given lists of files. Useful when a single post is updated
void update_files(std::set<ChannelPostFileInfo> &added_files, std::set<ChannelPostFileInfo> &removed_files);
#ifdef TODO #ifdef TODO
QModelIndex getIndexOfFile(const RsFileHash& hash) const; QModelIndex getIndexOfFile(const RsFileHash& hash) const;
void setSortMode(SortMode mode) ; void setSortMode(SortMode mode) ;

View File

@ -35,10 +35,10 @@
#include "GxsChannelPostsModel.h" #include "GxsChannelPostsModel.h"
#include "GxsChannelPostFilesModel.h" #include "GxsChannelPostFilesModel.h"
//#define DEBUG_CHANNEL_MODEL_DATA
//#define DEBUG_CHANNEL_MODEL //#define DEBUG_CHANNEL_MODEL
Q_DECLARE_METATYPE(RsMsgMetaData) Q_DECLARE_METATYPE(RsMsgMetaData)
Q_DECLARE_METATYPE(RsGxsChannelPost) Q_DECLARE_METATYPE(RsGxsChannelPost)
std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere
@ -47,14 +47,6 @@ RsGxsChannelPostsModel::RsGxsChannelPostsModel(QObject *parent)
: QAbstractItemModel(parent), mTreeMode(RsGxsChannelPostsModel::TREE_MODE_GRID), mColumns(6) : QAbstractItemModel(parent), mTreeMode(RsGxsChannelPostsModel::TREE_MODE_GRID), mColumns(6)
{ {
initEmptyHierarchy(); initEmptyHierarchy();
mEventHandlerId = 0;
// Needs to be asynced because this function is called by another thread!
rsEvents->registerEventsHandler( [this](std::shared_ptr<const RsEvent> event)
{
RsQThreadUtils::postToObject([=](){ handleEvent_main_thread(event); }, this );
}, mEventHandlerId, RsEventType::GXS_CHANNELS );
} }
RsGxsChannelPostsModel::~RsGxsChannelPostsModel() RsGxsChannelPostsModel::~RsGxsChannelPostsModel()
@ -72,7 +64,7 @@ void RsGxsChannelPostsModel::setMode(TreeMode mode)
triggerViewUpdate(); triggerViewUpdate();
} }
void updateCommentCounts( std::vector<RsGxsChannelPost>& posts, std::vector<RsGxsComment>& comments) void RsGxsChannelPostsModel::computeCommentCounts( std::vector<RsGxsChannelPost>& posts, std::vector<RsGxsComment>& comments)
{ {
// Store posts IDs in a std::map to avoid a quadratic cost // Store posts IDs in a std::map to avoid a quadratic cost
@ -108,99 +100,6 @@ void updateCommentCounts( std::vector<RsGxsChannelPost>& posts, std::vector<RsGx
} }
void RsGxsChannelPostsModel::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)
{
const RsGxsChannelEvent *e = dynamic_cast<const RsGxsChannelEvent*>(event.get());
if(!e)
return;
switch(e->mChannelEventCode)
{
case RsChannelEventCode::UPDATED_MESSAGE:
case RsChannelEventCode::READ_STATUS_CHANGED:
{
// Normally we should just emit dataChanged() on the index of the data that has changed:
// We need to update the data!
// make a copy of e, so as to avoid destruction of the shared pointer during async thread execution, since [e] doesn't actually tell
// the original shared_ptr that it is copied! So no counter is updated in event, which will be destroyed (as e will be) during or even before
// the execution of the lambda.
RsGxsChannelEvent E(*e);
if(E.mChannelGroupId == mChannelGroup.mMeta.mGroupId)
RsThread::async([this, E]()
{
// 1 - get message data from p3GxsChannels. No need for pointers here, because we send only a single post to postToObject()
// At this point we dont know what kind of msg id we have. It can be a vote, a comment or an actual message.
std::vector<RsGxsChannelPost> posts;
std::vector<RsGxsComment> comments;
std::vector<RsGxsVote> votes;
std::set<RsGxsMessageId> msg_ids{ E.mChannelMsgId };
if(!rsGxsChannels->getChannelContent(E.mChannelGroupId,msg_ids, posts,comments,votes))
{
std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve channel message data for channel/msg " << E.mChannelGroupId << "/" << E.mChannelMsgId << std::endl;
return;
}
// Check if what we have actually is a comment or a vote. If so we need to update the actual message they refer to
if(posts.empty()) // means we have a comment or a vote
{
msg_ids.clear();
for(auto c:comments) msg_ids.insert(c.mMeta.mThreadId);
for(auto v:votes ) msg_ids.insert(v.mMeta.mThreadId);
comments.clear();
votes.clear();
if(!rsGxsChannels->getChannelContent(E.mChannelGroupId,msg_ids,posts,comments,votes))
{
std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve channel message data for channel/msg " << E.mChannelGroupId << "/" << E.mChannelMsgId << std::endl;
return;
}
}
// Need to call this in order to get the actuall comment count. The previous call only retrieves the message, since we supplied the message ID.
// another way to go would be to save the comment ids of the existing message and re-insert them before calling getChannelContent.
if(!rsGxsChannels->getChannelComments(E.mChannelGroupId,msg_ids,comments))
{
std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve message comment data for channel/msg " << E.mChannelGroupId << "/" << E.mChannelMsgId << std::endl;
return;
}
updateCommentCounts(posts,comments);
// 2 - update the model in the UI thread.
RsQThreadUtils::postToObject( [posts,this]()
{
for(uint32_t i=0;i<posts.size();++i)
{
// linear search. Not good at all, but normally this is for a single post.
for(uint32_t j=0;j<mPosts.size();++j)
if(mPosts[j].mMeta.mMsgId == posts[i].mMeta.mMsgId)
{
mPosts[j] = posts[i];
triggerViewUpdate();
}
}
},this);
});
}
default:
break;
}
}
void RsGxsChannelPostsModel::initEmptyHierarchy() void RsGxsChannelPostsModel::initEmptyHierarchy()
{ {
beginResetModel(); beginResetModel();
@ -241,7 +140,31 @@ void RsGxsChannelPostsModel::getFilesList(std::list<ChannelPostFileInfo>& files)
files.push_back(it.second); files.push_back(it.second);
} }
bool RsGxsChannelPostsModel::postPassesFilter(const RsGxsChannelPost& post,const QStringList& strings,bool only_unread) const
{
bool passes_strings = true;
for(auto& s:strings)
passes_strings = passes_strings && QString::fromStdString(post.mMeta.mMsgName).contains(s,Qt::CaseInsensitive);
if(strings.empty())
passes_strings = true;
if(passes_strings && (!only_unread || (IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus))))
return true;
return false;
}
void RsGxsChannelPostsModel::setFilter(const QStringList& strings,bool only_unread, uint32_t& count) void RsGxsChannelPostsModel::setFilter(const QStringList& strings,bool only_unread, uint32_t& count)
{
mFilteredStrings = strings;
mFilterUnread = only_unread;
updateFilter(count);
}
void RsGxsChannelPostsModel::updateFilter(uint32_t& count)
{ {
preMods(); preMods();
@ -252,18 +175,8 @@ void RsGxsChannelPostsModel::setFilter(const QStringList& strings,bool only_unre
endResetModel(); endResetModel();
for(size_t i=0;i<mPosts.size();++i) for(size_t i=0;i<mPosts.size();++i)
{ if(postPassesFilter(mPosts[i],mFilteredStrings,mFilterUnread))
bool passes_strings = true;
for(auto& s:strings)
passes_strings = passes_strings && QString::fromStdString(mPosts[i].mMeta.mMsgName).contains(s,Qt::CaseInsensitive);
if(strings.empty())
passes_strings = true;
if(passes_strings && (!only_unread || (IS_MSG_UNREAD(mPosts[i].mMeta.mMsgStatus) || IS_MSG_NEW(mPosts[i].mMeta.mMsgStatus))))
mFilteredPosts.push_back(i); mFilteredPosts.push_back(i);
}
count = mFilteredPosts.size(); count = mFilteredPosts.size();
@ -292,7 +205,7 @@ int RsGxsChannelPostsModel::rowCount(const QModelIndex& parent) const
return mFilteredPosts.size(); return mFilteredPosts.size();
} }
RsErr() << __PRETTY_FUNCTION__ << " rowCount cannot figure out the porper number of rows." << std::endl; RsErr() << __PRETTY_FUNCTION__ << " rowCount cannot figure out the proper number of rows." ;
return 0; return 0;
} }
@ -370,7 +283,7 @@ QModelIndex RsGxsChannelPostsModel::index(int row, int column, const QModelIndex
quintptr ref = getChildRef(parent.internalId(),(mTreeMode == TREE_MODE_GRID)?(column + row*mColumns):row); quintptr ref = getChildRef(parent.internalId(),(mTreeMode == TREE_MODE_GRID)?(column + row*mColumns):row);
#ifdef DEBUG_CHANNEL_MODEL #ifdef DEBUG_CHANNEL_MODEL_DATA
std::cerr << "index-3(" << row << "," << column << " parent=" << parent << ") : " << createIndex(row,column,ref) << std::endl; std::cerr << "index-3(" << row << "," << column << " parent=" << parent << ") : " << createIndex(row,column,ref) << std::endl;
#endif #endif
return createIndex(row,column,ref) ; return createIndex(row,column,ref) ;
@ -460,7 +373,7 @@ int RsGxsChannelPostsModel::getChildrenCount(quintptr ref) const
QVariant RsGxsChannelPostsModel::data(const QModelIndex &index, int role) const QVariant RsGxsChannelPostsModel::data(const QModelIndex &index, int role) const
{ {
#ifdef DEBUG_CHANNEL_MODEL #ifdef DEBUG_CHANNEL_MODEL_DATA
std::cerr << "calling data(" << index << ") role=" << role << std::endl; std::cerr << "calling data(" << index << ") role=" << role << std::endl;
#endif #endif
@ -477,13 +390,13 @@ QVariant RsGxsChannelPostsModel::data(const QModelIndex &index, int role) const
quintptr ref = (index.isValid())?index.internalId():0 ; quintptr ref = (index.isValid())?index.internalId():0 ;
uint32_t entry = 0; uint32_t entry = 0;
#ifdef DEBUG_CHANNEL_MODEL #ifdef DEBUG_CHANNEL_MODEL_DATA
std::cerr << "data(" << index << ")" ; std::cerr << "data(" << index << ")" ;
#endif #endif
if(!ref) if(!ref)
{ {
#ifdef DEBUG_CHANNEL_MODEL #ifdef DEBUG_CHANNEL_MODEL_DATA
std::cerr << " [empty]" << std::endl; std::cerr << " [empty]" << std::endl;
#endif #endif
return QVariant() ; return QVariant() ;
@ -491,7 +404,7 @@ QVariant RsGxsChannelPostsModel::data(const QModelIndex &index, int role) const
if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFilteredPosts.size()) if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFilteredPosts.size())
{ {
#ifdef DEBUG_CHANNEL_MODEL #ifdef DEBUG_CHANNEL_MODEL_DATA
std::cerr << "Bad pointer: " << (void*)ref << std::endl; std::cerr << "Bad pointer: " << (void*)ref << std::endl;
#endif #endif
return QVariant() ; return QVariant() ;
@ -564,6 +477,79 @@ bool operator<(const RsGxsChannelPost& p1,const RsGxsChannelPost& p2)
return p1.mMeta.mPublishTs > p2.mMeta.mPublishTs; return p1.mMeta.mPublishTs > p2.mMeta.mPublishTs;
} }
void RsGxsChannelPostsModel::updateSinglePost(const RsGxsChannelPost& post,std::set<RsGxsFile>& added_files,std::set<RsGxsFile>& removed_files)
{
#ifdef DEBUG_CHANNEL_MODEL
RsDbg() << "updating single post for group id=" << currentGroupId() << " and msg id=" << post.mMeta.mMsgId ;
#endif
added_files.clear();
removed_files.clear();
emit layoutAboutToBeChanged();
// linear search. Not good at all, but normally this is just for a single post.
bool found = false;
const auto& new_post_meta(post.mMeta);
for(uint32_t j=0;j<mPosts.size();++j)
if(new_post_meta.mMsgId == mPosts[j].mMeta.mMsgId) // same post updated
{
added_files.insert(post.mFiles.begin(),post.mFiles.end());
removed_files.insert(mPosts[j].mFiles.begin(),mPosts[j].mFiles.end());
auto save_ucc = mPosts[j].mUnreadCommentCount;
auto save_cc = mPosts[j].mCommentCount;
mPosts[j] = post;
mPosts[j].mUnreadCommentCount = save_ucc;
mPosts[j].mCommentCount = save_cc;
#ifdef DEBUG_CHANNEL_MODEL
RsDbg() << " post is an updated existing post." ;
#endif
found=true;
break;
}
else if( (new_post_meta.mOrigMsgId == mPosts[j].mMeta.mOrigMsgId || new_post_meta.mOrigMsgId == mPosts[j].mMeta.mMsgId)
&& mPosts[j].mMeta.mPublishTs < new_post_meta.mPublishTs) // new post version
{
added_files.insert(post.mFiles.begin(),post.mFiles.end());
removed_files.insert(mPosts[j].mFiles.begin(),mPosts[j].mFiles.end());
auto old_post_id = mPosts[j].mMeta.mMsgId;
auto save_ucc = mPosts[j].mUnreadCommentCount;
auto save_cc = mPosts[j].mCommentCount;
mPosts[j] = post;
mPosts[j].mCommentCount += save_cc;
mPosts[j].mUnreadCommentCount += save_ucc;
mPosts[j].mOlderVersions.insert(old_post_id);
#ifdef DEBUG_CHANNEL_MODEL
RsDbg() << " post is an new version of an existing post." ;
#endif
found=true;
break;
}
if(!found)
{
#ifdef DEBUG_CHANNEL_MODEL
RsDbg() << " post is an new post.";
#endif
added_files.insert(post.mFiles.begin(),post.mFiles.end());
mPosts.push_back(post);
}
std::sort(mPosts.begin(),mPosts.end());
uint32_t count;
updateFilter(count);
triggerViewUpdate();
}
void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vector<RsGxsChannelPost>& posts) void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vector<RsGxsChannelPost>& posts)
{ {
preMods(); preMods();
@ -593,6 +579,8 @@ void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vecto
emit channelPostsLoaded(); emit channelPostsLoaded();
} }
void RsGxsChannelPostsModel::update_posts(const RsGxsGroupId& group_id) void RsGxsChannelPostsModel::update_posts(const RsGxsGroupId& group_id)
{ {
if(group_id.isNull()) if(group_id.isNull())
@ -635,7 +623,7 @@ void RsGxsChannelPostsModel::update_posts(const RsGxsGroupId& group_id)
// This shouldn't be needed normally. We need it until a background process computes the number of comments per // This shouldn't be needed normally. We need it until a background process computes the number of comments per
// post and stores it in the service string. Since we request all data, this process isn't costing much anyway. // post and stores it in the service string. Since we request all data, this process isn't costing much anyway.
updateCommentCounts(*posts,*comments); computeCommentCounts(*posts,*comments);
// 2 - update the model in the UI thread. // 2 - update the model in the UI thread.
@ -801,8 +789,28 @@ void RsGxsChannelPostsModel::setAllMsgReadStatus(bool read_status)
if(!rsGxsChannels->setMessageReadStatus(p,read_status)) if(!rsGxsChannels->setMessageReadStatus(p,read_status))
RsErr() << "setAllMsgReadStatus: failed to change status of msg " << p.first << " in group " << p.second << " to status " << read_status << std::endl; RsErr() << "setAllMsgReadStatus: failed to change status of msg " << p.first << " in group " << p.second << " to status " << read_status << std::endl;
}); });
// 3 - update the local model data, since we don't catch the READ_STATUS_CHANGED event later, to avoid re-loading the msg.
for(uint32_t i=0;i<mPosts.size();++i)
if(read_status)
mPosts[i].mMeta.mMsgStatus &= ~(GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD | GXS_SERV::GXS_MSG_STATUS_GUI_NEW);
else
mPosts[i].mMeta.mMsgStatus |= GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD ;
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(rowCount()-1,mColumns-1,(void*)NULL));
} }
void RsGxsChannelPostsModel::updatePostWithNewComment(const RsGxsMessageId& msg_id)
{
for(uint32_t i=0;i<mPosts.size();++i)
if(mPosts[i].mMeta.mMsgId == msg_id)
{
++mPosts[i].mUnreadCommentCount;
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(rowCount()-1,mColumns-1,(void*)NULL)); // update everything because we don't know the index.
break;
}
}
void RsGxsChannelPostsModel::setMsgReadStatus(const QModelIndex& i,bool read_status) void RsGxsChannelPostsModel::setMsgReadStatus(const QModelIndex& i,bool read_status)
{ {
if(!i.isValid()) if(!i.isValid())
@ -817,6 +825,18 @@ void RsGxsChannelPostsModel::setMsgReadStatus(const QModelIndex& i,bool read_sta
return ; return ;
rsGxsChannels->setMessageReadStatus(RsGxsGrpMsgIdPair(mPosts[mFilteredPosts[entry]].mMeta.mGroupId,mPosts[mFilteredPosts[entry]].mMeta.mMsgId),read_status); rsGxsChannels->setMessageReadStatus(RsGxsGrpMsgIdPair(mPosts[mFilteredPosts[entry]].mMeta.mGroupId,mPosts[mFilteredPosts[entry]].mMeta.mMsgId),read_status);
// Quick update to the msg itself. Normally setMsgReadStatus will launch an event,
// that we can catch to update the msg, but all the information is already here.
if(read_status)
mPosts[mFilteredPosts[entry]].mMeta.mMsgStatus &= ~(GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD | GXS_SERV::GXS_MSG_STATUS_GUI_NEW);
else
mPosts[mFilteredPosts[entry]].mMeta.mMsgStatus |= GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD;
mPosts[mFilteredPosts[entry]].mUnreadCommentCount = 0;
emit dataChanged(i,i);
} }
QModelIndex RsGxsChannelPostsModel::getIndexOfMessage(const RsGxsMessageId& mid) const QModelIndex RsGxsChannelPostsModel::getIndexOfMessage(const RsGxsMessageId& mid) const

View File

@ -101,6 +101,7 @@ public:
SORT_MODE_CHILDREN_PUBLISH_TS = 0x01, SORT_MODE_CHILDREN_PUBLISH_TS = 0x01,
}; };
#endif #endif
static void computeCommentCounts( std::vector<RsGxsChannelPost>& posts, std::vector<RsGxsComment>& comments);
QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;}
QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const; QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const;
@ -138,8 +139,11 @@ public:
void setMsgReadStatus(const QModelIndex &i, bool read_status); void setMsgReadStatus(const QModelIndex &i, bool read_status);
void setAllMsgReadStatus(bool read_status); void setAllMsgReadStatus(bool read_status);
void updatePostWithNewComment(const RsGxsMessageId& msg_id);
void setFilter(const QStringList &strings, bool only_unread,uint32_t &count) ; void setFilter(const QStringList &strings, bool only_unread,uint32_t &count) ;
bool postPassesFilter(const RsGxsChannelPost &post, const QStringList &strings, bool only_unread) const;
void updateFilter(uint32_t& count);
#ifdef TODO #ifdef TODO
void setAuthorOpinion(const QModelIndex& indx,RsOpinion op); void setAuthorOpinion(const QModelIndex& indx,RsOpinion op);
@ -215,6 +219,8 @@ private:
void update_posts(const RsGxsGroupId& group_id); void update_posts(const RsGxsGroupId& group_id);
private:
#ifdef TODO #ifdef TODO
void setForumMessageSummary(const std::vector<RsGxsForumMsg>& messages); void setForumMessageSummary(const std::vector<RsGxsForumMsg>& messages);
#endif #endif
@ -231,8 +237,13 @@ private:
//void computeMessagesHierarchy(const RsGxsChannelGroup& forum_group, const std::vector<RsMsgMetaData> &msgs_array, std::vector<ChannelPostsModelPostEntry> &posts, std::map<RsGxsMessageId, std::vector<std::pair<time_t, RsGxsMessageId> > > &mPostVersions); //void computeMessagesHierarchy(const RsGxsChannelGroup& forum_group, const std::vector<RsMsgMetaData> &msgs_array, std::vector<ChannelPostsModelPostEntry> &posts, std::map<RsGxsMessageId, std::vector<std::pair<time_t, RsGxsMessageId> > > &mPostVersions);
void createPostsArray(std::vector<RsGxsChannelPost> &posts); void createPostsArray(std::vector<RsGxsChannelPost> &posts);
void setPosts(const RsGxsChannelGroup& group, std::vector<RsGxsChannelPost> &posts); void setPosts(const RsGxsChannelGroup& group, std::vector<RsGxsChannelPost> &posts);
public:
void updateSinglePost(const RsGxsChannelPost& post, std::set<RsGxsFile>& added_files, std::set<RsGxsFile>& removed_files);
private:
void initEmptyHierarchy(); void initEmptyHierarchy();
void handleEvent_main_thread(std::shared_ptr<const RsEvent> event);
QStringList mFilteredStrings;
bool mFilterUnread;
std::vector<int> mFilteredPosts; // stores the list of displayes indices due to filtering. std::vector<int> mFilteredPosts; // stores the list of displayes indices due to filtering.
std::vector<RsGxsChannelPost> mPosts ; // store the list of posts updated from rsForums. std::vector<RsGxsChannelPost> mPosts ; // store the list of posts updated from rsForums.

View File

@ -75,6 +75,7 @@ QColor SelectedColor = QRgb(0xff308dc7);
#define STAR_OVERLAY_IMAGE ":icons/star_overlay_128.png" #define STAR_OVERLAY_IMAGE ":icons/star_overlay_128.png"
#define COMMENT_OVERLAY_IMAGE ":images/white-bubble-64.png" #define COMMENT_OVERLAY_IMAGE ":images/white-bubble-64.png"
#define UNREAD_COMMENT_OVERLAY_IMAGE ":images/orange-bubble-64.png"
#define IMAGE_COPYLINK ":icons/png/copy.png" #define IMAGE_COPYLINK ":icons/png/copy.png"
#define IMAGE_GRID_VIEW ":icons/png/menu.png" #define IMAGE_GRID_VIEW ":icons/png/menu.png"
#define IMAGE_DOWNLOAD ":icons/png/download.png" #define IMAGE_DOWNLOAD ":icons/png/download.png"
@ -121,11 +122,7 @@ void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem &
RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ; RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ;
// if(index.row() & 0x01)
// painter->fillRect( option.rect, option.palette.alternateBase().color());
// else
painter->fillRect( option.rect, option.palette.base().color()); painter->fillRect( option.rect, option.palette.base().color());
painter->restore(); painter->restore();
if(mUseGrid || index.column()==0) if(mUseGrid || index.column()==0)
@ -144,14 +141,7 @@ void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem &
if((option.state & QStyle::State_Selected) && post.mMeta.mPublishTs > 0) // check if post is selected and is not empty (end of last row) if((option.state & QStyle::State_Selected) && post.mMeta.mPublishTs > 0) // check if post is selected and is not empty (end of last row)
pixmap.fill(SelectedColor); // I dont know how to grab the backgroud color for selected objects automatically. pixmap.fill(SelectedColor); // I dont know how to grab the backgroud color for selected objects automatically.
else else
{
// we need to do the alternate color manually
//if(index.row() & 0x01)
// pixmap.fill(option.palette.alternateBase().color());
//else
pixmap.fill(option.palette.base().color()); pixmap.fill(option.palette.base().color());
}
w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background
@ -168,8 +158,6 @@ void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem &
// file.close(); // file.close();
// } // }
if(mUseGrid || index.column()==0)
{
if(mZoom != 1.0) if(mZoom != 1.0)
pixmap = pixmap.scaled(mZoom*pixmap.size(),Qt::KeepAspectRatio,Qt::SmoothTransformation); pixmap = pixmap.scaled(mZoom*pixmap.size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
@ -181,7 +169,16 @@ void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem &
p.drawPixmap(mZoom*QPoint(0.1*fm.height(),-3.4*fm.height()),FilesDefs::getPixmapFromQtResourcePath(STAR_OVERLAY_IMAGE).scaled(mZoom*6*fm.height(),mZoom*6*fm.height(),Qt::KeepAspectRatio,Qt::SmoothTransformation)); p.drawPixmap(mZoom*QPoint(0.1*fm.height(),-3.4*fm.height()),FilesDefs::getPixmapFromQtResourcePath(STAR_OVERLAY_IMAGE).scaled(mZoom*6*fm.height(),mZoom*6*fm.height(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
} }
if(post.mUnreadCommentCount) if(post.mUnreadCommentCount > 0)
{
QPainter p(&pixmap);
QFontMetricsF fm(option.font);
p.drawPixmap(QPoint(pixmap.width(),0.0)+mZoom*QPoint(-2.9*fm.height(),0.4*fm.height()),
FilesDefs::getPixmapFromQtResourcePath(UNREAD_COMMENT_OVERLAY_IMAGE).scaled(mZoom*3*fm.height(),mZoom*3*fm.height(),
Qt::KeepAspectRatio,Qt::SmoothTransformation));
}
else if(post.mCommentCount > 0)
{ {
QPainter p(&pixmap); QPainter p(&pixmap);
QFontMetricsF fm(option.font); QFontMetricsF fm(option.font);
@ -191,10 +188,9 @@ void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem &
Qt::KeepAspectRatio,Qt::SmoothTransformation)); Qt::KeepAspectRatio,Qt::SmoothTransformation));
} }
}
painter->drawPixmap(option.rect.topLeft(), painter->drawPixmap(option.rect.topLeft(),
pixmap.scaled(option.rect.width(),option.rect.width()*pixmap.height()/(float)pixmap.width(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation)); pixmap.scaled(option.rect.width(),option.rect.width()*pixmap.height()/(float)pixmap.width(),
Qt::IgnoreAspectRatio,Qt::SmoothTransformation));
} }
else else
{ {
@ -262,6 +258,9 @@ QSize ChannelPostDelegate::sizeHint(const QStyleOptionViewItem& option, const QM
float cell_width = mZoom*COLUMN_SIZE_FONT_FACTOR_W*fm.height(); float cell_width = mZoom*COLUMN_SIZE_FONT_FACTOR_W*fm.height();
float cell_height = mZoom*COLUMN_SIZE_FONT_FACTOR_W*fm.height()*aspect_ratio; float cell_height = mZoom*COLUMN_SIZE_FONT_FACTOR_W*fm.height()*aspect_ratio;
#ifdef DEBUG_CHANNEL_POSTS_WIDGET
RsDbg() << "SizeHint: mUseGrid=" << mUseGrid << " cell_width=" << cell_width << " cell_height=" << cell_height << " mZoom=" << mZoom ;
#endif
if(mUseGrid || index.column()==0) if(mUseGrid || index.column()==0)
return QSize(cell_width,cell_height); return QSize(cell_width,cell_height);
@ -743,7 +742,7 @@ void GxsChannelPostsWidgetWithModel::handlePostsTreeSizeChange(QSize s,bool forc
return; return;
int n_columns = std::max(1,(int)floor(s.width() / (mChannelPostsDelegate->cellSize(0,font(),ui->postsTree->width())))); int n_columns = std::max(1,(int)floor(s.width() / (mChannelPostsDelegate->cellSize(0,font(),ui->postsTree->width()))));
std::cerr << "nb columns: " << n_columns << " current count=" << mChannelPostsModel->columnCount() << std::endl; RsDbg() << "nb columns: " << n_columns << " current count=" << mChannelPostsModel->columnCount() ;
// save current post. The setNumColumns() indeed loses selection // save current post. The setNumColumns() indeed loses selection
@ -771,20 +770,90 @@ void GxsChannelPostsWidgetWithModel::handleEvent_main_thread(std::shared_ptr<con
{ {
case RsChannelEventCode::NEW_CHANNEL: // [[fallthrough]]; case RsChannelEventCode::NEW_CHANNEL: // [[fallthrough]];
case RsChannelEventCode::DELETED_CHANNEL: // [[fallthrough]]; case RsChannelEventCode::DELETED_CHANNEL: // [[fallthrough]];
case RsChannelEventCode::NEW_COMMENT: // [[fallthrough]];
case RsChannelEventCode::NEW_VOTE: // [[fallthrough]];
case RsChannelEventCode::UPDATED_CHANNEL: // [[fallthrough]]; case RsChannelEventCode::UPDATED_CHANNEL: // [[fallthrough]];
case RsChannelEventCode::NEW_MESSAGE: // [[fallthrough]];
case RsChannelEventCode::UPDATED_MESSAGE:
case RsChannelEventCode::RECEIVED_PUBLISH_KEY: case RsChannelEventCode::RECEIVED_PUBLISH_KEY:
case RsChannelEventCode::SYNC_PARAMETERS_UPDATED: case RsChannelEventCode::SYNC_PARAMETERS_UPDATED:
{ {
if(e->mChannelGroupId == groupId()) if(e->mChannelGroupId == groupId())
updateDisplay(true); updateDisplay(true,false);
} }
break;
case RsChannelEventCode::READ_STATUS_CHANGED: // This is already handled by setMsgReadStatus() that has been called and issued this event.
break;
case RsChannelEventCode::NEW_MESSAGE:
{
if(e->mChannelGroupId == groupId())
{
RsDbg() << "Received new message in current channel, msgId=" << e->mChannelMsgId ;
RsThread::async([this,E=*e]() // dereferencing to make a copy that will survive while e is deleted by the parent thread.
{
// 1 - get message data from p3GxsChannels. No need for pointers here, because we send only a single post to postToObject()
// At this point we dont know what kind of msg id we have. It can be a vote, a comment or an actual message.
std::vector<RsGxsChannelPost> posts;
std::vector<RsGxsComment> comments;
std::vector<RsGxsVote> votes;
const auto& msg_id(E.mChannelMsgId);
const auto& grp_id(E.mChannelGroupId);
if(!rsGxsChannels->getChannelContent(grp_id, { msg_id }, posts,comments,votes) || posts.size() != 1)
{
RsErr() << " failed to retrieve channel message data for channel/msg " << grp_id << "/" << msg_id;
return;
}
// Need to call this in order to get the actual comment count. The previous call only retrieves the message, since we supplied the message ID.
// another way to go would be to save the comment ids of the existing message and re-insert them before calling getChannelContent.
if(!rsGxsChannels->getChannelComments(grp_id,{ msg_id },comments))
{
RsErr() << " failed to retrieve message comment data for channel/msg " << grp_id << "/" << msg_id ;
return;
}
// Normally, there's a single post in the "post" array. The function below takes a full array of posts however.
RsGxsChannelPostsModel::computeCommentCounts(posts,comments);
// 2 - update the model in the UI thread.
RsQThreadUtils::postToObject( [post=posts[0],this]()
{
std::set<RsGxsFile> added_files,removed_files;
mChannelPostsModel->updateSinglePost(post,added_files,removed_files);
std::set<ChannelPostFileInfo> added_filesi,removed_filesi;
for(auto f:added_files) added_filesi.insert(ChannelPostFileInfo(f,post.mMeta.mPublishTs));
for(auto f:removed_files) removed_filesi.insert(ChannelPostFileInfo(f,post.mMeta.mPublishTs));
mChannelFilesModel->update_files(added_filesi,removed_filesi);
},this);
});
}
}
break;
case RsChannelEventCode::NEW_COMMENT:
if(e->mChannelGroupId == groupId() && e->mChannelThreadId != ui->commentsDialog->messageId())
mChannelPostsModel->updatePostWithNewComment(e->mChannelThreadId); [[fallthrough]];
case RsChannelEventCode::NEW_VOTE:
if(e->mChannelGroupId == groupId() && e->mChannelThreadId == ui->commentsDialog->messageId())
ui->commentsDialog->refresh();
break;
default: default:
break; break;
} }
} }
@ -793,7 +862,7 @@ void GxsChannelPostsWidgetWithModel::showPostDetails()
QModelIndex index = ui->postsTree->selectionModel()->currentIndex(); QModelIndex index = ui->postsTree->selectionModel()->currentIndex();
RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ; RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ;
#ifdef DEBUG_CHANNEL_POSTS_WIDGET #ifdef DEBUG_CHANNEL_POSTS_WIDGET
std::cerr << "showPostDetails: current index is " << index.row() << "," << index.column() << std::endl; RsDbg() << "showPostDetails: current index is " << index.row() << "," << index.column() ;
#endif #endif
//QTextDocument doc; //QTextDocument doc;
@ -818,7 +887,7 @@ void GxsChannelPostsWidgetWithModel::showPostDetails()
ui->postTime_LB->show(); ui->postTime_LB->show();
#ifdef DEBUG_CHANNEL_POSTS_WIDGET #ifdef DEBUG_CHANNEL_POSTS_WIDGET
std::cerr << "showPostDetails: setting mLastSelectedPosts[groupId()] to current post Id " << post.mMeta.mMsgId << ". Previous value: " << mLastSelectedPosts[groupId()] << std::endl; RsDbg() << "showPostDetails: setting mLastSelectedPosts[groupId()] to current post Id " << post.mMeta.mMsgId << ". Previous value: " << mLastSelectedPosts[groupId()] ;
#endif #endif
mLastSelectedPosts[groupId()] = post.mMeta.mMsgId; mLastSelectedPosts[groupId()] = post.mMeta.mMsgId;
@ -834,7 +903,7 @@ void GxsChannelPostsWidgetWithModel::showPostDetails()
ui->commentsDialog->commentLoad(post.mMeta.mGroupId, all_msgs_versions, post.mMeta.mMsgId,true); ui->commentsDialog->commentLoad(post.mMeta.mGroupId, all_msgs_versions, post.mMeta.mMsgId,true);
#ifdef DEBUG_CHANNEL_POSTS_WIDGET #ifdef DEBUG_CHANNEL_POSTS_WIDGET
std::cerr << "Showing details about selected index : "<< index.row() << "," << index.column() << std::endl; RsDbg() << "Showing details about selected index : "<< index.row() << "," << index.column() ;
#endif #endif
ui->postDetails_TE->setText(RsHtml().formatText(NULL, QString::fromUtf8(post.mMsg.c_str()), /* RSHTML_FORMATTEXT_EMBED_SMILEYS |*/ RSHTML_FORMATTEXT_EMBED_LINKS)); ui->postDetails_TE->setText(RsHtml().formatText(NULL, QString::fromUtf8(post.mMsg.c_str()), /* RSHTML_FORMATTEXT_EMBED_SMILEYS |*/ RSHTML_FORMATTEXT_EMBED_LINKS));
@ -864,13 +933,18 @@ void GxsChannelPostsWidgetWithModel::showPostDetails()
// Now also set the post as read // Now also set the post as read
if(IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus)) if(IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus) || post.mUnreadCommentCount > 0)
{ {
RsGxsGrpMsgIdPair postId; mChannelPostsModel->setMsgReadStatus(index,true);
postId.second = post.mMeta.mMsgId;
postId.first = post.mMeta.mGroupId;
RsThread::async([postId]() { rsGxsChannels->setMessageReadStatus(postId, true) ; } ); //RsGxsGrpMsgIdPair postId;
//postId.second = post.mMeta.mMsgId;
//postId.first = post.mMeta.mGroupId;
//RsThread::async([postId]()
//{
//rsGxsChannels->setMessageReadStatus(postId, true) ;
//} );
} }
updateDAll_PB(); updateDAll_PB();
@ -883,7 +957,7 @@ void GxsChannelPostsWidgetWithModel::updateCommentsCount(int n)
else else
ui->details_TW->setTabText(2,tr("Comments")); ui->details_TW->setTabText(2,tr("Comments"));
} }
void GxsChannelPostsWidgetWithModel::updateGroupData() void GxsChannelPostsWidgetWithModel::updateData(bool update_group_data, bool update_posts)
{ {
if(groupId().isNull()) if(groupId().isNull())
{ {
@ -893,10 +967,10 @@ void GxsChannelPostsWidgetWithModel::updateGroupData()
return; return;
} }
RsThread::async([this]() RsThread::async([this,update_group_data,update_posts]()
{ {
RsGxsChannelGroup group;
std::vector<RsGxsChannelGroup> groups; std::vector<RsGxsChannelGroup> groups;
RsGxsChannelGroup group;
if(rsGxsChannels->getChannelsInfo(std::list<RsGxsGroupId>{ groupId() }, groups) && groups.size()==1) if(rsGxsChannels->getChannelsInfo(std::list<RsGxsGroupId>{ groupId() }, groups) && groups.size()==1)
group = groups[0]; group = groups[0];
@ -906,7 +980,7 @@ void GxsChannelPostsWidgetWithModel::updateGroupData()
return; return;
} }
RsQThreadUtils::postToObject( [this,group]() RsQThreadUtils::postToObject( [this,update_group_data,update_posts,group]()
{ {
if(mGroup.mMeta.mGroupId != group.mMeta.mGroupId) // this prevents any attempt to display the wrong index. Navigate() if needed will use mNavigatePendingMsgId if(mGroup.mMeta.mGroupId != group.mMeta.mGroupId) // this prevents any attempt to display the wrong index. Navigate() if needed will use mNavigatePendingMsgId
{ {
@ -918,15 +992,21 @@ void GxsChannelPostsWidgetWithModel::updateGroupData()
updateCommentsCount(0); updateCommentsCount(0);
} }
if(update_group_data)
{
mGroup = group; mGroup = group;
insertChannelDetails(mGroup);
}
if(update_posts)
{
ui->postsTree->setPlaceholderText(tr("Loading...")); ui->postsTree->setPlaceholderText(tr("Loading..."));
mChannelPostsModel->updateChannel(groupId()); mChannelPostsModel->updateChannel(groupId());
whileBlocking(ui->filterLineEdit)->clear(); whileBlocking(ui->filterLineEdit)->clear();
whileBlocking(ui->showUnread_TB)->setChecked(false); whileBlocking(ui->showUnread_TB)->setChecked(false);
}
insertChannelDetails(mGroup);
emit groupDataLoaded(); emit groupDataLoaded();
emit groupChanged(this); // signals the parent widget to e.g. update the group tab name emit groupChanged(this); // signals the parent widget to e.g. update the group tab name
@ -991,10 +1071,10 @@ void GxsChannelPostsWidgetWithModel::postChannelPostLoad()
handlePostsTreeSizeChange(ui->postsTree->size(),true); // force the update handlePostsTreeSizeChange(ui->postsTree->size(),true); // force the update
} }
void GxsChannelPostsWidgetWithModel::updateDisplay(bool complete) void GxsChannelPostsWidgetWithModel::updateDisplay(bool update_group_data,bool update_posts)
{ {
// First, clear all widget // First, clear all widget
blank();
#ifdef DEBUG_CHANNEL #ifdef DEBUG_CHANNEL
std::cerr << "udateDisplay: groupId()=" << groupId()<< std::endl; std::cerr << "udateDisplay: groupId()=" << groupId()<< std::endl;
#endif #endif
@ -1006,25 +1086,16 @@ void GxsChannelPostsWidgetWithModel::updateDisplay(bool complete)
return; return;
} }
if(mGroup.mMeta.mGroupId.isNull() && !groupId().isNull()) if(mGroup.mMeta.mGroupId != groupId())
{ {
#ifdef DEBUG_FORUMS #ifdef DEBUG_FORUMS
std::cerr << " inconsistent group data. Reloading!"<< std::endl; std::cerr << " inconsistent group data. Reloading!"<< std::endl;
#endif #endif
complete = true; update_group_data = true;
update_posts = true;
} }
if(complete) // need to update the group data, reload the messages etc.
{
#warning csoler 2020-06-02 : todo
//saveExpandedItems(mSavedExpandedMessages);
//if(mGroupId != mChannelPostsModel->currentGroupId()) updateData(update_group_data,update_posts);
// mThreadId.clear();
updateGroupData();
return;
}
} }
GxsChannelPostsWidgetWithModel::~GxsChannelPostsWidgetWithModel() GxsChannelPostsWidgetWithModel::~GxsChannelPostsWidgetWithModel()
{ {

View File

@ -104,11 +104,11 @@ public:
/* GxsMessageFrameWidget */ /* GxsMessageFrameWidget */
virtual QIcon groupIcon() override; virtual QIcon groupIcon() override;
virtual void groupIdChanged() override { updateDisplay(true); } virtual void groupIdChanged() override { updateDisplay(true,true); }
virtual QString groupName(bool) override; virtual QString groupName(bool) override;
virtual bool navigate(const RsGxsMessageId&) override; virtual bool navigate(const RsGxsMessageId&) override;
void updateDisplay(bool complete); void updateDisplay(bool update_group_data, bool update_posts);
#ifdef TODO #ifdef TODO
/* FeedHolder */ /* FeedHolder */
@ -141,7 +141,7 @@ protected:
private slots: private slots:
void showPostDetails(); void showPostDetails();
void updateGroupData(); void updateData(bool update_group_data,bool update_posts);
void download(); void download();
void updateDAll_PB(); void updateDAll_PB();
void createMsg(); void createMsg();

@ -1 +1 @@
Subproject commit a593b9c808f90cce7d47a5de86c207ef8675945f Subproject commit 5cc37b3e5ad6b64b247e9d2066a9b6c8acae67ce