From 9d575ddca14cae07ab9658e542119725df317109 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 2 Mar 2023 09:46:16 +0100 Subject: [PATCH 1/7] implemented new algorithm for sorting channel posts --- .../gui/gxschannels/GxsChannelPostsModel.cpp | 97 ++++++++++++++++++- .../gui/gxschannels/GxsChannelPostsModel.h | 5 +- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 06b671532..750db7519 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -571,7 +571,7 @@ void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vecto initEmptyHierarchy(); mChannelGroup = group; - createPostsArray(posts); + createPostsArray(posts); std::sort(mPosts.begin(),mPosts.end()); @@ -658,7 +658,7 @@ void RsGxsChannelPostsModel::update_posts(const RsGxsGroupId& group_id) }); } -void RsGxsChannelPostsModel::createPostsArray(std::vector& posts) +void RsGxsChannelPostsModel::old_createPostsArray(std::vector& posts) { // collect new versions of posts if any @@ -776,6 +776,99 @@ void RsGxsChannelPostsModel::createPostsArray(std::vector& pos } } +void RsGxsChannelPostsModel::createPostsArray(std::vector& posts) +{ + // The hierarchy of posts may contain edited posts. In the new model (03/2023), mOrigMsgId points to the original + // top-level post in the hierarchy of edited posts. However, in the old model, mOrigMsgId points to the edited post. + // Therefore the algorithm below is made to cope with both models at once. + // + // In the future, using the new model, it will be possible to delete old versions from the db, and detect new versions + // because they all share the same mOrigMsgId. + // + // We proceed as follows: + // + // 1 - create a search map to convert post IDs into their index in the posts tab + // 2 - recursively climb up the post mOrigMsgId until no parent is found. At top level, create the original post, and add all previous elements as newer versions. + // 3 - go through the list of original posts, select among them the most recent version, and set all others as older versions. + // + // The algorithm handles the case where some parent has been deleted. + +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "Inserting channel posts" << std::endl; +#endif + + // 1 - create a search map to convert post IDs into their index in the posts tab + + std::map search_map ; + + for (uint32_t i=0;i original_versions ; + + for (uint32_t i=0;i newest_time) + { + newest_index = current_index; + newest_time = m.mPublishTs; + } + + RsGxsMessageId top_level_id; + std::map::const_iterator it; + + if(m.mOrigMsgId.isNull() || m.mOrigMsgId==m.mMsgId) // we have a top-level post. + top_level_id = m.mMsgId; + else if( (it = search_map.find(m.mOrigMsgId)) == search_map.end()) // we don't have the post. Never mind, we store the + top_level_id = m.mOrigMsgId; + else + { + current_index = it->second; + continue; + } + + auto vit = original_versions.find(top_level_id); + + if(vit != original_versions.end()) + { + if(posts[vit->second].mMeta.mPublishTs < newest_time) + vit->second = newest_index; + } + else + original_versions[top_level_id] = newest_index; + + break; + } + } + +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "Now adding " << posts.size() << " posts into array structure..." << std::endl; +#endif + + mPosts.clear(); + + // make sure the posts are delivered in the same order they appears in the posts[] tab. + + std::vector ids; + + for(auto id:original_versions) + ids.push_back(id.second); + + std::sort(ids.begin(),ids.end()); + + for(uint32_t i=0;i &msgs_array, std::vector &posts, std::map > > &mPostVersions); - void createPostsArray(std::vector &posts); - void setPosts(const RsGxsChannelGroup& group, std::vector &posts); + void old_createPostsArray(std::vector &posts); + void createPostsArray(std::vector& posts); + void setPosts(const RsGxsChannelGroup& group, std::vector &posts); void initEmptyHierarchy(); void handleEvent_main_thread(std::shared_ptr event); From 97265dddab46f94746bc8680a56101997933e0e3 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 2 Mar 2023 22:55:58 +0100 Subject: [PATCH 2/7] updated algorithm for sorting channel posts with debug info and collection of all post versions --- .../gui/gxschannels/GxsChannelPostsModel.cpp | 99 ++++++++++++++----- 1 file changed, 75 insertions(+), 24 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 750db7519..25fdd6d0f 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -35,7 +35,7 @@ #include "GxsChannelPostsModel.h" #include "GxsChannelPostFilesModel.h" -//#define DEBUG_CHANNEL_MODEL +#define DEBUG_CHANNEL_MODEL Q_DECLARE_METATYPE(RsMsgMetaData) @@ -704,9 +704,6 @@ void RsGxsChannelPostsModel::old_createPostsArray(std::vector& uint32_t current_index = new_versions[i] ; uint32_t source_index = new_versions[i] ; -#ifdef DEBUG_CHANNEL_MODEL - RsGxsMessageId source_msg_id = posts[source_index].mMeta.mMsgId ; -#endif // What we do is everytime we find a replacement post, we climb up the replacement graph until we find the original post // (or the most recent version of it). When we reach this post, we replace it with the data of the source post. @@ -799,30 +796,51 @@ void RsGxsChannelPostsModel::createPostsArray(std::vector& pos // 1 - create a search map to convert post IDs into their index in the posts tab +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << " Given list: " << std::endl; +#endif std::map search_map ; for (uint32_t i=0;i > > original_versions ; for (uint32_t i=0;i& versions,rstime_t newest_time,uint32_t newest_index,int depth)> recurs_find_top_level + = [&posts,&search_map,&recurs_find_top_level,&original_versions](uint32_t index, + std::set& collected_versions, + rstime_t newest_time, + uint32_t newest_index, + int depth) + -> RsGxsMessageId { - const auto& m(posts[current_index].mMeta); + const auto& m(posts[index].mMeta); if(m.mPublishTs > newest_time) { - newest_index = current_index; + newest_index = index; newest_time = m.mPublishTs; } + collected_versions.insert(m.mMsgId); RsGxsMessageId top_level_id; std::map::const_iterator it; @@ -830,44 +848,77 @@ void RsGxsChannelPostsModel::createPostsArray(std::vector& pos if(m.mOrigMsgId.isNull() || m.mOrigMsgId==m.mMsgId) // we have a top-level post. top_level_id = m.mMsgId; else if( (it = search_map.find(m.mOrigMsgId)) == search_map.end()) // we don't have the post. Never mind, we store the + { top_level_id = m.mOrigMsgId; + collected_versions.insert(m.mOrigMsgId); // this one will never be added to the set by the previous call + } else { - current_index = it->second; - continue; + top_level_id = recurs_find_top_level(it->second,collected_versions,newest_time,newest_index,depth+1); + posts[index].mMeta.mOrigMsgId = top_level_id; // this fastens calculation because it will skip already seen posts. + + return top_level_id; } +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << std::string(2*depth,' ') << " top level = " << top_level_id ; +#endif auto vit = original_versions.find(top_level_id); if(vit != original_versions.end()) { - if(posts[vit->second].mMeta.mPublishTs < newest_time) - vit->second = newest_index; - } - else - original_versions[top_level_id] = newest_index; - - break; - } - } + if(posts[vit->second.first].mMeta.mPublishTs < newest_time) + vit->second.first = newest_index; #ifdef DEBUG_CHANNEL_MODEL - std::cerr << "Now adding " << posts.size() << " posts into array structure..." << std::endl; + std::cerr << " already existing. " << std::endl; #endif + } + else + { + original_versions[top_level_id].first = newest_index; +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << " new. " << std::endl; +#endif + } + original_versions[top_level_id].second.insert(collected_versions.begin(),collected_versions.end()); + + return top_level_id; + }; + + auto versions_set = std::set(); + recurs_find_top_level(i,versions_set,posts[i].mMeta.mPublishTs,i,0); + } mPosts.clear(); +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << " Total top_level posts: " << original_versions.size() << std::endl; + + for(auto it:original_versions) + { + std::cerr << " Post " << it.first << ". Total versions = " << it.second.second.size() << " latest: " << posts[it.second.first].mMeta.mMsgId << std::endl; + + for(auto m:it.second.second) + if(m != it.first) + std::cerr << " other (newer version): " << m << std::endl; + } +#endif // make sure the posts are delivered in the same order they appears in the posts[] tab. std::vector ids; for(auto id:original_versions) - ids.push_back(id.second); + ids.push_back(id.second.first); std::sort(ids.begin(),ids.end()); for(uint32_t i=0;i Date: Fri, 3 Mar 2023 00:08:33 +0100 Subject: [PATCH 3/7] switch from createPost() to createPostV2() in channels --- .../gui/gxschannels/CreateGxsChannelMsg.cpp | 45 +++---------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp index c834ae3da..05ce9bda6 100644 --- a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp +++ b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp @@ -794,56 +794,25 @@ void CreateGxsChannelMsg::sendMessage(const std::string &subject, const std::str /* rsGxsChannels */ if (rsGxsChannels) { - RsGxsChannelPost post; - - post.mMeta.mGroupId = mChannelId; - post.mMeta.mParentId.clear() ; - post.mMeta.mThreadId.clear() ; - post.mMeta.mMsgId.clear() ; - - post.mMeta.mOrigMsgId = mOrigPostId; - post.mMeta.mMsgName = subject; - post.mMsg = msg; - post.mFiles = files; - QByteArray ba; QBuffer buffer(&ba); + RsGxsImage image; + if(!picture.isNull()) { // send chan image buffer.open(QIODevice::WriteOnly); preview_W->getCroppedScaledPicture().save(&buffer, "JPG"); // writes image into ba in PNG format - post.mThumbnail.copy((uint8_t *) ba.data(), ba.size()); + image.copy((uint8_t *) ba.data(), ba.size()); } + std::string error_string; + RsGxsMessageId post_id; -#ifdef ENABLE_GENERATE - int generateCount = 0; - if (generateCheckBox->isChecked()) { - generateCount = generateSpinBox->value(); - if (QMessageBox::question(this, tr("Generate mass data"), tr("Do you really want to generate %1 messages ?").arg(generateCount), QMessageBox::Yes|QMessageBox::No, QMessageBox::No) == QMessageBox::No) { - return; - } - } -#endif - - uint32_t token; -#ifdef ENABLE_GENERATE - if (generateCount) { - for (int count = 0; count < generateCount; ++count) { - RsGxsChannelPost generatePost = post; - generatePost.mMeta.mMsgName = QString("%1 %2").arg(QString::fromUtf8(post.mMeta.mMsgName.c_str())).arg(count + 1, 3, 10, QChar('0')).toUtf8().constData(); - - rsGxsChannels->createPost(token, generatePost); - } - } else { -#endif - rsGxsChannels->createPost(token, post); -#ifdef ENABLE_GENERATE - } -#endif + if(!rsGxsChannels->createPostV2(mChannelId,subject,msg,files,image,mOrigPostId,post_id,error_string)) + QMessageBox::critical(nullptr,tr("Cannot publish post"),QString::fromStdString(error_string)); } accept(); From 3b9886a747a29a7cb56f5583e4de9b61ab261538 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 12 Mar 2023 17:43:09 +0100 Subject: [PATCH 4/7] fixed channel mode debug output --- retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 25fdd6d0f..045a7a8d9 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -35,7 +35,7 @@ #include "GxsChannelPostsModel.h" #include "GxsChannelPostFilesModel.h" -#define DEBUG_CHANNEL_MODEL +//#define DEBUG_CHANNEL_MODEL Q_DECLARE_METATYPE(RsMsgMetaData) From 548ef009608acc746b7aa4e514defed8d177520a Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 21 Mar 2023 21:08:30 +0100 Subject: [PATCH 5/7] enabled channel post model debug --- retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 045a7a8d9..25fdd6d0f 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -35,7 +35,7 @@ #include "GxsChannelPostsModel.h" #include "GxsChannelPostFilesModel.h" -//#define DEBUG_CHANNEL_MODEL +#define DEBUG_CHANNEL_MODEL Q_DECLARE_METATYPE(RsMsgMetaData) From 7299ace57ab15e1e0ceb839c67bba9479dd9e800 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 8 Apr 2023 18:04:22 +0200 Subject: [PATCH 6/7] re-enabled channel debug output --- retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 11a29903a..3136004a2 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -36,7 +36,7 @@ #include "GxsChannelPostFilesModel.h" //#define DEBUG_CHANNEL_MODEL_DATA -//#define DEBUG_CHANNEL_MODEL +#define DEBUG_CHANNEL_MODEL Q_DECLARE_METATYPE(RsMsgMetaData) Q_DECLARE_METATYPE(RsGxsChannelPost) From a7b2091bb80154c58278bdba9b5ca9384c597acd Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 13 Apr 2023 21:51:37 +0200 Subject: [PATCH 7/7] added a waiting cursor when loading a channel --- .../src/gui/gxschannels/GxsChannelPostsModel.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 3136004a2..197013c8b 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -27,6 +27,8 @@ #include "retroshare/rsgxschannels.h" #include "retroshare/rsexpr.h" +#include "gui/MainWindow.h" +#include "gui/mainpagestack.h" #include "gui/common/FilesDefs.h" #include "util/qtthreadsutils.h" #include "util/HandleRichText.h" @@ -453,7 +455,6 @@ const RsGxsGroupId& RsGxsChannelPostsModel::currentGroupId() const { return mChannelGroup.mMeta.mGroupId; } - void RsGxsChannelPostsModel::updateChannel(const RsGxsGroupId& channel_group_id) { if(channel_group_id.isNull()) @@ -586,7 +587,9 @@ void RsGxsChannelPostsModel::update_posts(const RsGxsGroupId& group_id) if(group_id.isNull()) return; - RsThread::async([this, group_id]() + MainWindow::getPage(MainWindow::Channels)->setCursor(Qt::WaitCursor) ; // Maybe we should pass that widget when calling update_posts + + RsThread::async([this, group_id]() { // 1 - get message data from p3GxsChannels @@ -641,7 +644,9 @@ void RsGxsChannelPostsModel::update_posts(const RsGxsGroupId& group_id) delete comments; delete votes; - }, this ); + MainWindow::getPage(MainWindow::Channels)->setCursor(Qt::ArrowCursor) ; + + }, this ); }); }