From 9d49ca0e4c83463a0bc27bcda9f76a73c6643f2a Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 17 Nov 2018 22:36:07 +0100 Subject: [PATCH 01/79] initial attempt at creating an ItemModel for forums --- .../src/gui/gxsforums/GxsForumModel.cpp | 409 ++++++++++++++++++ .../src/gui/gxsforums/GxsForumModel.h | 53 +++ retroshare-gui/src/retroshare-gui.pro | 2 + 3 files changed, 464 insertions(+) create mode 100644 retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp create mode 100644 retroshare-gui/src/gui/gxsforums/GxsForumModel.h diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp new file mode 100644 index 000000000..b2e6241b9 --- /dev/null +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -0,0 +1,409 @@ +#include +#include +#include + +#include "GxsForumModel.h" + +#define DEBUG_FORUMMODEL + +#define COLUMN_TITLE 0 +#define COLUMN_READ_STATUS 1 +#define COLUMN_DATE 2 +#define COLUMN_AUTHOR 3 +#define COLUMN_COUNT 4 + +Q_DECLARE_METATYPE(RsMsgMetaData); + +std::ostream& operator<<(std::ostream& o, const QModelIndex& i) +{ + return o << i.row() << "," << i.column() << "," << i.internalPointer() ; +} + +RsGxsForumModel::RsGxsForumModel(QObject *parent) + : QAbstractItemModel(parent) +{ + mPosts.resize(1); // adds a sentinel item +} + +int RsGxsForumModel::rowCount(const QModelIndex& parent) const +{ + void *ref = (parent.isValid())?parent.internalPointer():NULL ; + + if(mPosts.empty()) // security. Should never happen. + return 0; + + uint32_t entry = 0 ; + int source_id ; + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + { +#ifdef DEBUG_FORUMMODEL + std::cerr << "rowCount-2(" << parent << ") : " << 0 << std::endl; +#endif + return 0 ; + } + +#ifdef DEBUG_FORUMMODEL + std::cerr << "rowCount-3(" << parent << ") : " << mPosts[entry].children.size() << std::endl; +#endif + return mPosts[entry].children.size(); +} + +int RsGxsForumModel::columnCount(const QModelIndex &parent) const +{ + return COLUMN_COUNT ; +} + +bool RsGxsForumModel::hasChildren(const QModelIndex &parent) const +{ + void *ref = (parent.isValid())?parent.internalPointer():NULL ; + uint32_t entry = 0; + + if(!ref) + { +#ifdef DEBUG_FORUMMODEL + std::cerr << "hasChildren-1(" << parent << ") : " << true << std::endl; +#endif + return true ; + } + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + { +#ifdef DEBUG_FORUMMODEL + std::cerr << "hasChildren-2(" << parent << ") : " << false << std::endl; +#endif + return false ; + } + +#ifdef DEBUG_DOWNLOADLIST + std::cerr << "hasChildren-3(" << parent << ") : " << !mDownloads[entry].peers.empty() << std::endl; +#endif + return !mPosts[entry].children.empty(); +} + +bool RsGxsForumModel::convertTabEntryToRefPointer(uint32_t entry,void *& ref) +{ + // the pointer is formed the following way: + // + // [ 32 bits ] + // + // This means that the whole software has the following build-in limitation: + // * 4 B simultaenous posts. Should be enough ! + + ref = reinterpret_cast( (intptr_t)entry ); + + return true; +} + +bool RsGxsForumModel::convertRefPointerToTabEntry(void *ref,uint32_t& entry) +{ + intptr_t val = (intptr_t)ref; + + if(val > (intptr_t)(~(uint32_t(0)))) // make sure the pointer is an int that fits in 32bits + { + std::cerr << "(EE) trying to make a ForumModelIndex out of a number that is larger than 2^32 !" << std::endl; + return false ; + } + entry = uint32_t(val); + + return true; +} + +QModelIndex RsGxsForumModel::index(int row, int column, const QModelIndex & parent) const +{ + if(row < 0 || column < 0 || column >= COLUMN_COUNT) + return QModelIndex(); + + void *parent_ref = (parent.isValid())?parent.internalPointer():NULL ; + uint32_t entry = 0; + int source_id=0 ; + + if(!parent_ref) // top level. The entry is that of a transfer + { + void *ref = NULL ; + + if(row >= (int)mPosts.size() || !convertTabEntryToRefPointer(row,ref)) + { +#ifdef DEBUG_FORUMMODEL + std::cerr << "index-1(" << row << "," << column << " parent=" << parent << ") : " << "NULL" << std::endl; +#endif + return QModelIndex() ; + } + +#ifdef DEBUG_FORUMMODEL + std::cerr << "index-2(" << row << "," << column << " parent=" << parent << ") : " << createIndex(row,column,ref) << std::endl; +#endif + return createIndex(row,column,ref) ; + } + + if(!convertRefPointerToTabEntry(parent_ref,entry) || entry >= mPosts.size()) + { +#ifdef DEBUG_FORUMMODEL + std::cerr << "index-5(" << row << "," << column << " parent=" << parent << ") : " << "NULL"<< std::endl ; +#endif + return QModelIndex() ; + } + + void *ref = NULL ; + + if(row >= mPosts[entry].children.size() || !convertTabEntryToRefPointer(mPosts[entry].children[row],ref)) + { +#ifdef DEBUG_FORUMMODEL + std::cerr << "index-4(" << row << "," << column << " parent=" << parent << ") : " << "NULL" << std::endl; +#endif + return QModelIndex() ; + } + +#ifdef DEBUG_FORUMMODEL + std::cerr << "index-3(" << row << "," << column << " parent=" << parent << ") : " << createIndex(row,column,ref) << std::endl; +#endif + return createIndex(row,column,ref) ; +} + +QModelIndex RsGxsForumModel::parent(const QModelIndex& child) const +{ + void *child_ref = (child.isValid())?child.internalPointer():NULL ; + uint32_t entry = 0; + int source_id=0 ; + + if(!child_ref) + return QModelIndex() ; + + if(!convertRefPointerToTabEntry(child_ref,entry) || entry >= mPosts.size()) + return QModelIndex() ; + + void *parent_ref =NULL; + + if(!convertTabEntryToRefPointer(mPosts[entry].parent,parent_ref)) + return QModelIndex() ; + + return createIndex(entry,child.column(),parent_ref) ; // I'm not sure about the .column() here ! +} + +QVariant RsGxsForumModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if(role != Qt::DisplayRole) + return QVariant(); + + switch(section) + { + default: + case COLUMN_TITLE: return tr("Title"); + case COLUMN_READ_STATUS: return tr("Read Status"); + case COLUMN_DATE: return tr("Date"); + case COLUMN_AUTHOR: return tr("Author"); + } +} + +QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const +{ + if(!index.isValid()) + return QVariant(); + + int coln = index.column() ; + + switch(role) + { + case Qt::SizeHintRole: return sizeHintRole(index.column()) ; + case Qt::TextAlignmentRole: + case Qt::TextColorRole: + case Qt::WhatsThisRole: + case Qt::EditRole: + case Qt::ToolTipRole: + case Qt::StatusTipRole: + return QVariant(); + } + + void *ref = (index.isValid())?index.internalPointer():NULL ; + uint32_t entry = 0; + +#ifdef DEBUG_FORUMMODEL + std::cerr << "data(" << index << ")" ; +#endif + + if(!ref) + { +#ifdef DEBUG_FORUMMODEL + std::cerr << " [empty]" << std::endl; +#endif + return QVariant() ; + } + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + { +#ifdef DEBUG_FORUMMODEL + std::cerr << "Bad pointer: " << (void*)ref << std::endl; +#endif + return QVariant() ; + } + + const RsMsgMetaData& meta(mPosts[entry].meta_versions[0]) ; + +#ifdef DEBUG_DOWNLOADLIST + std::cerr << " [ok]" << std::endl; +#endif + + switch(role) + { + case Qt::DisplayRole: return displayRole (meta,index.column()) ; + case Qt::DecorationRole: return decorationRole(meta,index.column()) ; + case Qt::UserRole: return userRole (meta,index.column()) ; + default: + return QVariant(); + } +} + +QVariant RsGxsForumModel::sizeHintRole(int col) const +{ + float factor = QFontMetricsF(QApplication::font()).height()/14.0f ; + + switch(col) + { + default: + case COLUMN_TITLE: return QVariant( factor * 170 ); + case COLUMN_READ_STATUS: return QVariant( factor * 10 ); + case COLUMN_DATE: return QVariant( factor * 75 ); + case COLUMN_AUTHOR: return QVariant( factor * 75 ); + } +} + +QVariant RsGxsForumModel::displayRole(const RsMsgMetaData& meta,int col) const +{ + switch(col) + { + case COLUMN_TITLE: return QVariant(QString::fromUtf8(meta.mMsgName.c_str())); + case COLUMN_READ_STATUS: return QVariant(meta.mMsgStatus); + case COLUMN_DATE: return QVariant(qulonglong(meta.mPublishTs)); + case COLUMN_AUTHOR: return QVariant(QString::fromStdString(meta.mAuthorId.toStdString())); + + default: + return QVariant("[ TODO ]"); + } + + + return QVariant("[ERROR]"); +} + +QVariant RsGxsForumModel::userRole(const RsMsgMetaData &meta, int col) const +{ +#ifdef TODO + switch(col) + { + case COLUMN_PROGRESS: + { + FileChunksInfo fcinfo; + if (!rsFiles->FileDownloadChunksDetails(fileInfo.hash, fcinfo)) + return QVariant(); + + FileProgressInfo pinfo; + pinfo.cmap = fcinfo.chunks; + pinfo.type = FileProgressInfo::DOWNLOAD_LINE; + pinfo.progress = (fileInfo.size == 0) ? 0 : (fileInfo.transfered * 100.0 / fileInfo.size); + pinfo.nb_chunks = pinfo.cmap._map.empty() ? 0 : fcinfo.chunks.size(); + + for (uint32_t i = 0; i < fcinfo.chunks.size(); ++i) + switch(fcinfo.chunks[i]) + { + case FileChunksInfo::CHUNK_CHECKING: pinfo.chunks_in_checking.push_back(i); + break ; + case FileChunksInfo::CHUNK_ACTIVE: pinfo.chunks_in_progress.push_back(i); + break ; + case FileChunksInfo::CHUNK_DONE: + case FileChunksInfo::CHUNK_OUTSTANDING: + break ; + } + + return QVariant::fromValue(pinfo); + } + + case COLUMN_ID: return QVariant(QString::fromStdString(fileInfo.hash.toStdString())); + + + default: + return QVariant(); + } + } +#endif + return QVariant(); + +} + +QVariant RsGxsForumModel::decorationRole(const RsMsgMetaData& meta,int col) const +{ + return QVariant(); +} + +void RsGxsForumModel::update_posts() +{ +#ifdef TODO + std::list downHashes; + rsFiles->FileDownloads(downHashes); + + size_t old_size = mDownloads.size(); + + mDownloads.resize(downHashes.size()) ; + + if(old_size < mDownloads.size()) + { + beginInsertRows(QModelIndex(), old_size, mDownloads.size()-1); + insertRows(old_size, mDownloads.size() - old_size); + endInsertRows(); + } + else if(mDownloads.size() < old_size) + { + beginRemoveRows(QModelIndex(), mDownloads.size(), old_size-1); + removeRows(mDownloads.size(), old_size - mDownloads.size()); + endRemoveRows(); + } + + uint32_t i=0; + + for(auto it(downHashes.begin());it!=downHashes.end();++it,++i) + { + FileInfo fileInfo(mDownloads[i]); // we dont update the data itself but only a copy of it.... + int old_size = fileInfo.peers.size() ; + + rsFiles->FileDetails(*it, RS_FILE_HINTS_DOWNLOAD, fileInfo); + + int new_size = fileInfo.peers.size() ; + + if(old_size < new_size) + { + beginInsertRows(index(i,0), old_size, new_size-1); + insertRows(old_size, new_size - old_size,index(i,0)); +#ifdef DEBUG_DOWNLOADLIST + std::cerr << "called insert rows ( " << old_size << ", " << new_size - old_size << ",index(" << index(i,0)<< "))" << std::endl; +#endif + endInsertRows(); + } + else if(new_size < old_size) + { + beginRemoveRows(index(i,0), new_size, old_size-1); + removeRows(new_size, old_size - new_size,index(i,0)); +#ifdef DEBUG_DOWNLOADLIST + std::cerr << "called remove rows ( " << old_size << ", " << old_size - new_size << ",index(" << index(i,0)<< "))" << std::endl; +#endif + endRemoveRows(); + } + + uint32_t old_status = mDownloads[i].downloadStatus ; + + mDownloads[i] = fileInfo ; // ... because insertRows() calls rowCount() which needs to be consistent with the *old* number of rows. + + if(fileInfo.downloadStatus == FT_STATE_DOWNLOADING || old_status != fileInfo.downloadStatus) + { + QModelIndex topLeft = createIndex(i,0), bottomRight = createIndex(i, COLUMN_COUNT-1); + emit dataChanged(topLeft, bottomRight); + } + + // This is apparently not needed. + // + // if(!mDownloads.empty()) + // { + // QModelIndex topLeft = createIndex(0,0), bottomRight = createIndex(mDownloads.size()-1, COLUMN_COUNT-1); + // emit dataChanged(topLeft, bottomRight); + // mDownloads[i] = fileInfo ; + // } + } +#endif +} diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h new file mode 100644 index 000000000..7b8845f80 --- /dev/null +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -0,0 +1,53 @@ +#include "retroshare/rsgxsifacetypes.h" + +// This class holds the actual hierarchy of posts, represented by identifiers +// It is responsible for auto-updating when necessary and holds a mutex to allow the Model to +// safely access the data. + +// The model contains a post in place 0 that is the parent of all posts. + +typedef uint32_t ForumModelIndex; + +struct ForumPostEntry +{ + std::vector meta_versions; // maybe we don't need all this. Could be too large. + + std::vector children; + ForumModelIndex parent; +}; + +// This class is the item model used by Qt to display the information + +class RsGxsForumModel : public QAbstractItemModel +{ + // Q_OBJECT + +public: + explicit RsGxsForumModel(QObject *parent = NULL); + ~RsGxsForumModel(){} + + enum Roles{ SortRole = Qt::UserRole+1 }; + + int rowCount(const QModelIndex& parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + bool hasChildren(const QModelIndex &parent = QModelIndex()) const; + + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex& child) const; + + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + + QVariant sizeHintRole(int col) const; + QVariant displayRole(const RsMsgMetaData& meta, int col) const; + QVariant userRole(const RsMsgMetaData& meta, int col) const; + QVariant decorationRole(const RsMsgMetaData &meta, int col) const; + + void update_posts(); + +private: + static bool convertTabEntryToRefPointer(uint32_t entry,void *& ref); + static bool convertRefPointerToTabEntry(void *ref,uint32_t& entry); + + std::vector mPosts ; // store the list of posts updated from rsForums. +}; diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 61baf713e..8a9ae04ce 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -1231,6 +1231,7 @@ gxsforums { gui/gxsforums/CreateGxsForumMsg.h \ gui/gxsforums/GxsForumThreadWidget.h \ gui/gxsforums/GxsForumsFillThread.h \ + gui/gxsforums/GxsForumModel.h \ gui/gxsforums/GxsForumUserNotify.h \ gui/feeds/GxsForumGroupItem.h \ gui/feeds/GxsForumMsgItem.h @@ -1244,6 +1245,7 @@ gxsforums { gui/gxsforums/GxsForumGroupDialog.cpp \ gui/gxsforums/CreateGxsForumMsg.cpp \ gui/gxsforums/GxsForumThreadWidget.cpp \ + gui/gxsforums/GxsForumModel.cpp \ gui/gxsforums/GxsForumsFillThread.cpp \ gui/gxsforums/GxsForumUserNotify.cpp \ gui/feeds/GxsForumGroupItem.cpp \ From a532b68b8e0de81d76967ab3276c3eeeb01458c8 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 18 Nov 2018 21:36:13 +0100 Subject: [PATCH 02/79] improvements of the Forum Model --- .../src/gui/gxsforums/GxsForumModel.cpp | 84 ++++++++++--------- .../src/gui/gxsforums/GxsForumModel.h | 1 + .../gui/gxsforums/GxsForumThreadWidget.cpp | 55 +++++++++++- .../src/gui/gxsforums/GxsForumThreadWidget.ui | 43 +--------- 4 files changed, 98 insertions(+), 85 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index b2e6241b9..33dcc2efb 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -14,15 +14,34 @@ Q_DECLARE_METATYPE(RsMsgMetaData); -std::ostream& operator<<(std::ostream& o, const QModelIndex& i) -{ - return o << i.row() << "," << i.column() << "," << i.internalPointer() ; -} +std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere RsGxsForumModel::RsGxsForumModel(QObject *parent) : QAbstractItemModel(parent) { mPosts.resize(1); // adds a sentinel item + + // adds some fake posts to debug + + int N=5 ; + mPosts.resize(N+1); + + for(int i=1;i<=N;++i) + { + mPosts[0].children.push_back(ForumModelIndex(i)); + mPosts[i].parent = ForumModelIndex(0); + mPosts[i].prow = i-1; + + RsMsgMetaData meta; + meta.mMsgName = "message " + (QString::number(i).toStdString()) ; + mPosts[i].meta_versions.push_back(meta); + } + + // add one child to last post + mPosts.resize(N+2); + mPosts[N].children.push_back(ForumModelIndex(N+1)); + mPosts[N+1].parent = ForumModelIndex(N); + mPosts[N+1].prow = 0; } int RsGxsForumModel::rowCount(const QModelIndex& parent) const @@ -59,14 +78,6 @@ bool RsGxsForumModel::hasChildren(const QModelIndex &parent) const void *ref = (parent.isValid())?parent.internalPointer():NULL ; uint32_t entry = 0; - if(!ref) - { -#ifdef DEBUG_FORUMMODEL - std::cerr << "hasChildren-1(" << parent << ") : " << true << std::endl; -#endif - return true ; - } - if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) { #ifdef DEBUG_FORUMMODEL @@ -115,28 +126,12 @@ QModelIndex RsGxsForumModel::index(int row, int column, const QModelIndex & pare return QModelIndex(); void *parent_ref = (parent.isValid())?parent.internalPointer():NULL ; - uint32_t entry = 0; + uint32_t parent_entry = 0; int source_id=0 ; - if(!parent_ref) // top level. The entry is that of a transfer - { - void *ref = NULL ; + // We dont need to handle parent==NULL because the conversion will return entry=0 which is what we need. - if(row >= (int)mPosts.size() || !convertTabEntryToRefPointer(row,ref)) - { -#ifdef DEBUG_FORUMMODEL - std::cerr << "index-1(" << row << "," << column << " parent=" << parent << ") : " << "NULL" << std::endl; -#endif - return QModelIndex() ; - } - -#ifdef DEBUG_FORUMMODEL - std::cerr << "index-2(" << row << "," << column << " parent=" << parent << ") : " << createIndex(row,column,ref) << std::endl; -#endif - return createIndex(row,column,ref) ; - } - - if(!convertRefPointerToTabEntry(parent_ref,entry) || entry >= mPosts.size()) + if(!convertRefPointerToTabEntry(parent_ref,parent_entry) || parent_entry >= mPosts.size()) { #ifdef DEBUG_FORUMMODEL std::cerr << "index-5(" << row << "," << column << " parent=" << parent << ") : " << "NULL"<< std::endl ; @@ -146,7 +141,7 @@ QModelIndex RsGxsForumModel::index(int row, int column, const QModelIndex & pare void *ref = NULL ; - if(row >= mPosts[entry].children.size() || !convertTabEntryToRefPointer(mPosts[entry].children[row],ref)) + if(row >= mPosts[parent_entry].children.size() || !convertTabEntryToRefPointer(mPosts[parent_entry].children[row],ref)) { #ifdef DEBUG_FORUMMODEL std::cerr << "index-4(" << row << "," << column << " parent=" << parent << ") : " << "NULL" << std::endl; @@ -163,21 +158,32 @@ QModelIndex RsGxsForumModel::index(int row, int column, const QModelIndex & pare QModelIndex RsGxsForumModel::parent(const QModelIndex& child) const { void *child_ref = (child.isValid())?child.internalPointer():NULL ; - uint32_t entry = 0; - int source_id=0 ; if(!child_ref) return QModelIndex() ; - if(!convertRefPointerToTabEntry(child_ref,entry) || entry >= mPosts.size()) + ForumModelIndex child_entry ; + + if(!convertRefPointerToTabEntry(child_ref,child_entry) || child_entry >= mPosts.size()) return QModelIndex() ; void *parent_ref =NULL; + ForumModelIndex parent_entry = mPosts[child_entry].parent; + QModelIndex indx; - if(!convertTabEntryToRefPointer(mPosts[entry].parent,parent_ref)) - return QModelIndex() ; + if(parent_entry == 0) // top level index + indx = QModelIndex() ; + else + { + if(!convertTabEntryToRefPointer(parent_entry,parent_ref)) + return QModelIndex() ; - return createIndex(entry,child.column(),parent_ref) ; // I'm not sure about the .column() here ! + indx = createIndex(mPosts[parent_entry].prow,child.column(),parent_ref) ; + } +#ifdef DEBUG_FORUMMODEL + std::cerr << "parent-1(" << child << ") : " << indx << std::endl; +#endif + return indx; } QVariant RsGxsForumModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -239,7 +245,7 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const const RsMsgMetaData& meta(mPosts[entry].meta_versions[0]) ; -#ifdef DEBUG_DOWNLOADLIST +#ifdef DEBUG_FORUMMODEL std::cerr << " [ok]" << std::endl; #endif diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index 7b8845f80..e5fdbf976 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -14,6 +14,7 @@ struct ForumPostEntry std::vector children; ForumModelIndex parent; + int prow ; // parent row }; // This class is the item model used by Qt to display the information diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index d04d982c3..d33aab4eb 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -27,6 +27,7 @@ #include "GxsForumThreadWidget.h" #include "ui_GxsForumThreadWidget.h" #include "GxsForumsFillThread.h" +#include "GxsForumModel.h" #include "GxsForumsDialog.h" #include "gui/RetroShareLink.h" #include "gui/common/RSTreeWidgetItem.h" @@ -179,8 +180,9 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mStateHelper->addWidget(mTokenTypeInsertThreads, ui->nextUnreadButton); mStateHelper->addWidget(mTokenTypeInsertThreads, ui->previousButton); mStateHelper->addWidget(mTokenTypeInsertThreads, ui->nextButton); - +#ifdef SUSPENDED_CODE mStateHelper->addClear(mTokenTypeInsertThreads, ui->threadTreeWidget); +#endif mStateHelper->addWidget(mTokenTypeMessageData, ui->newmessageButton); // mStateHelper->addWidget(mTokenTypeMessageData, ui->postText); @@ -200,6 +202,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mThreadCompareRole = new RSTreeWidgetItemCompareRole; mThreadCompareRole->setRole(COLUMN_THREAD_DATE, ROLE_THREAD_SORT); + ui->threadTreeWidget->setModel(new RsGxsForumModel(this)); ui->threadTreeWidget->setItemDelegateForColumn(COLUMN_THREAD_DISTRIBUTION,new DistributionItemDelegate()) ; connect(ui->versions_CB, SIGNAL(currentIndexChanged(int)), this, SLOT(changedVersion())); @@ -247,12 +250,14 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ttheader->resizeSection (COLUMN_THREAD_DISTRIBUTION, 24*f); ttheader->resizeSection (COLUMN_THREAD_AUTHOR, 150*f); +#ifdef SUSPENDED_CODE /* Set text of column "Read" to empty - without this the column has a number as header text */ QTreeWidgetItem *headerItem = ui->threadTreeWidget->headerItem(); headerItem->setText(COLUMN_THREAD_READ, "") ; headerItem->setText(COLUMN_THREAD_DISTRIBUTION, ""); headerItem->setData(COLUMN_THREAD_READ,Qt::UserRole, tr("Read status")) ; // this is used to display drop menus. headerItem->setData(COLUMN_THREAD_DISTRIBUTION,Qt::UserRole, tr("Distribution")); +#endif /* add filter actions */ ui->filterLineEdit->addFilter(QIcon(), tr("Title"), COLUMN_THREAD_TITLE, tr("Search Title")); @@ -294,9 +299,11 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->subscribeToolButton->setToolTip(tr( "

Subscribing to the forum will gather \ available posts from your subscribed friends, and make the \ forum visible to all other friends.

Afterwards you can unsubscribe from the context menu of the forum list at left.

")); - ui->threadTreeWidget->enableColumnCustomize(true); +#ifdef SUSPENDED_CODE + ui->threadTreeWidget->enableColumnCustomize(true); ui->threadTreeWidget->sortItems(COLUMN_THREAD_DATE, Qt::DescendingOrder); +#endif } void GxsForumThreadWidget::blank() @@ -312,7 +319,9 @@ void GxsForumThreadWidget::blank() ui->by_label->hide(); ui->postText->setImageBlockWidget(ui->imageBlockWidget) ; ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages()); +#ifdef SUSPENDED_CODE ui->threadTreeWidget->clear(); +#endif ui->forumName->setText(""); mStateHelper->setWidgetEnabled(ui->newthreadButton, false); @@ -509,7 +518,7 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) if (mFillThread) { return; } - +#ifdef TODO QMenu contextMnu(this); QList selectedItems = ui->threadTreeWidget->selectedItems(); @@ -690,6 +699,7 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) } contextMnu.exec(QCursor::pos()); +#endif } void GxsForumThreadWidget::contextMenuTextBrowser(QPoint point) @@ -713,6 +723,7 @@ void GxsForumThreadWidget::contextMenuTextBrowser(QPoint point) bool GxsForumThreadWidget::eventFilter(QObject *obj, QEvent *event) { +#ifdef TODO if (obj == ui->threadTreeWidget) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(event); @@ -726,6 +737,8 @@ bool GxsForumThreadWidget::eventFilter(QObject *obj, QEvent *event) } // pass the event on to the parent class return RsGxsUpdateBroadcastWidget::eventFilter(obj, event); +#endif + return true; } void GxsForumThreadWidget::togglethreadview() @@ -762,6 +775,7 @@ void GxsForumThreadWidget::changedVersion() void GxsForumThreadWidget::changedThread() { +#ifdef TODO /* just grab the ids of the current item */ QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); @@ -779,6 +793,7 @@ void GxsForumThreadWidget::changedThread() ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages()) ; insertMessage(); +#endif } void GxsForumThreadWidget::clickedThread(QTreeWidgetItem *item, int column) @@ -883,6 +898,7 @@ void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item, bool &h void GxsForumThreadWidget::calculateUnreadCount() { +#ifdef TODO unsigned int unreadCount = 0; unsigned int newCount = 0; @@ -913,10 +929,12 @@ void GxsForumThreadWidget::calculateUnreadCount() if (changed) { emit groupChanged(this); } +#endif } void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item /*= NULL*/) { +#ifdef TODO bool dummy1 = false; bool dummy2 = false; @@ -933,6 +951,7 @@ void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item /*= NULL dummy2 = false; calculateIconsAndFonts(ui->threadTreeWidget->topLevelItem(index), dummy1, dummy2); } +#endif } static void cleanupItems (QList &items) @@ -1086,6 +1105,7 @@ static QString getDurationString(uint32_t days) void GxsForumThreadWidget::fillThreadFinished() { +#ifdef TODO #ifdef DEBUG_FORUMS std::cerr << "GxsForumThreadWidget::fillThreadFinished" << std::endl; #endif @@ -1204,6 +1224,7 @@ void GxsForumThreadWidget::fillThreadFinished() #ifdef DEBUG_FORUMS std::cerr << "GxsForumThreadWidget::fillThreadFinished done" << std::endl; #endif +#endif } void GxsForumThreadWidget::fillThreadProgress(int current, int count) @@ -1526,6 +1547,7 @@ static void copyItem(QTreeWidgetItem *item, const QTreeWidgetItem *newItem) void GxsForumThreadWidget::fillThreads(QList &threadList, bool expandNewMessages, QList &itemToExpand) { +#ifdef TODO #ifdef DEBUG_FORUMS std::cerr << "GxsForumThreadWidget::fillThreads()" << std::endl; #endif @@ -1597,6 +1619,7 @@ void GxsForumThreadWidget::fillThreads(QList &threadList, boo #ifdef DEBUG_FORUMS std::cerr << "GxsForumThreadWidget::fillThreads() done" << std::endl; #endif +#endif } void GxsForumThreadWidget::fillChildren(QTreeWidgetItem *parentItem, QTreeWidgetItem *newParentItem, bool expandNewMessages, QList &itemToExpand) @@ -1665,6 +1688,7 @@ void GxsForumThreadWidget::fillChildren(QTreeWidgetItem *parentItem, QTreeWidget void GxsForumThreadWidget::insertMessage() { +#ifdef TODO if (groupId().isNull()) { mStateHelper->setActive(mTokenTypeMessageData, false); @@ -1764,10 +1788,12 @@ void GxsForumThreadWidget::insertMessage() /* request Post */ RsGxsGrpMsgIdPair msgId = std::make_pair(groupId(), mThreadId); requestMessageData(msgId); +#endif } void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) { +#ifdef TODO /* As some time has elapsed since request - check that this is still the current msg. * otherwise, another request will fill the data */ @@ -1842,10 +1868,12 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) ui->postText->setHtml(extraTxt); } // ui->threadTitle->setText(QString::fromUtf8(msg.mMeta.mMsgName.c_str())); +#endif } void GxsForumThreadWidget::previousMessage() { +#ifdef TODO QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); if (item == NULL) { return; @@ -1859,10 +1887,12 @@ void GxsForumThreadWidget::previousMessage() ui->threadTreeWidget->setCurrentItem(previousItem); } } +#endif } void GxsForumThreadWidget::nextMessage() { +#ifdef TODO QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); if (item == NULL) { return; @@ -1877,6 +1907,7 @@ void GxsForumThreadWidget::nextMessage() ui->threadTreeWidget->setCurrentItem(nextItem); } } +#endif } void GxsForumThreadWidget::downloadAllFiles() @@ -1895,6 +1926,7 @@ void GxsForumThreadWidget::downloadAllFiles() void GxsForumThreadWidget::nextUnreadMessage() { +#ifdef TODO QTreeWidgetItem *currentItem = ui->threadTreeWidget->currentItem(); while (true) { @@ -1923,12 +1955,14 @@ void GxsForumThreadWidget::nextUnreadMessage() /* start from top */ currentItem = NULL; } +#endif } /* get selected messages the messages tree is single selected, but who knows ... */ int GxsForumThreadWidget::getSelectedMsgCount(QList *rows, QList *rowsRead, QList *rowsUnread) { +#ifdef TODO if (rowsRead) rowsRead->clear(); if (rowsUnread) rowsUnread->clear(); @@ -1946,6 +1980,8 @@ int GxsForumThreadWidget::getSelectedMsgCount(QList *rows, QLi } return selectedItems.size(); +#endif + return 0; } void GxsForumThreadWidget::setMsgReadStatus(QList &rows, bool read) @@ -2035,6 +2071,7 @@ void GxsForumThreadWidget::showInPeopleTab() void GxsForumThreadWidget::markMsgAsReadUnread (bool read, bool children, bool forum) { +#ifdef TODO if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { return; } @@ -2081,6 +2118,7 @@ void GxsForumThreadWidget::markMsgAsReadUnread (bool read, bool children, bool f } setMsgReadStatus(rows, read); +#endif } void GxsForumThreadWidget::markMsgAsRead() @@ -2110,6 +2148,7 @@ void GxsForumThreadWidget::setAllMessagesReadDo(bool read, uint32_t &/*token*/) bool GxsForumThreadWidget::navigate(const RsGxsMessageId &msgId) { +#ifdef TODO if (mStateHelper->isLoading(mTokenTypeInsertThreads)) { mNavigatePendingMsgId = msgId; @@ -2131,6 +2170,7 @@ bool GxsForumThreadWidget::navigate(const RsGxsMessageId &msgId) return true; } } +#endif return false; } @@ -2149,7 +2189,7 @@ void GxsForumThreadWidget::copyMessageLink() if (groupId().isNull() || mThreadId.isNull()) { return; } - +#ifdef TODO QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); QString thread_title = (item != NULL)?item->text(COLUMN_THREAD_TITLE):QString() ; @@ -2161,6 +2201,7 @@ void GxsForumThreadWidget::copyMessageLink() urls.push_back(link); RSLinkClipboard::copyLinks(urls); } +#endif } void GxsForumThreadWidget::subscribeGroup(bool subscribe) @@ -2188,6 +2229,7 @@ void GxsForumThreadWidget::createmessage() void GxsForumThreadWidget::togglePinUpPost() { +#ifdef TODO if (groupId().isNull() || mThreadId.isNull()) return; @@ -2215,6 +2257,7 @@ void GxsForumThreadWidget::togglePinUpPost() ui->threadTreeWidget->takeTopLevelItem(ui->threadTreeWidget->indexOfTopLevelItem(item)); // forces the re-creation of all posts widgets. A bit extreme. We should rather only delete item above updateDisplay(true) ; +#endif } void GxsForumThreadWidget::createthread() @@ -2434,6 +2477,7 @@ void GxsForumThreadWidget::saveImage() void GxsForumThreadWidget::changedViewBox() { +#ifdef TODO if (mInProcessSettings) { return; } @@ -2444,6 +2488,7 @@ void GxsForumThreadWidget::changedViewBox() ui->threadTreeWidget->clear(); insertThreads(); +#endif } void GxsForumThreadWidget::filterColumnChanged(int column) @@ -2465,12 +2510,14 @@ void GxsForumThreadWidget::filterColumnChanged(int column) void GxsForumThreadWidget::filterItems(const QString& text) { +#ifdef TODO int filterColumn = ui->filterLineEdit->currentFilter(); int count = ui->threadTreeWidget->topLevelItemCount(); for (int index = 0; index < count; ++index) { filterItem(ui->threadTreeWidget->topLevelItem(index), text, filterColumn); } +#endif } bool GxsForumThreadWidget::filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui index 56d08267f..fa372b940 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui @@ -215,7 +215,7 @@ - + Qt::CustomContextMenu @@ -225,42 +225,6 @@ true - - - Title - - - - - - - - - :/images/message-state-header.png:/images/message-state-header.png - - - - - Date - - - - - - - - Distribution - - - - :/icons/flag-green.png:/icons/flag-green.png - - - - - Author - - @@ -558,11 +522,6 @@ QTextBrowser
gui/common/RSTextBrowser.h
- - RSTreeWidget - QTreeWidget -
gui/common/RSTreeWidget.h
-
ElidedLabel QLabel From dbeb97c0e907956dd2b358a731feea654a837f80 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 19 Nov 2018 21:45:42 +0100 Subject: [PATCH 03/79] fixed bug in sizeHintRole() --- .../src/gui/gxsforums/GxsForumModel.cpp | 189 +++++++++++------- .../src/gui/gxsforums/GxsForumModel.h | 40 +++- 2 files changed, 148 insertions(+), 81 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 33dcc2efb..210d4f27f 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -42,32 +42,25 @@ RsGxsForumModel::RsGxsForumModel(QObject *parent) mPosts[N].children.push_back(ForumModelIndex(N+1)); mPosts[N+1].parent = ForumModelIndex(N); mPosts[N+1].prow = 0; + + RsMsgMetaData meta; + meta.mMsgName = "message " + (QString::number(N+1).toStdString()) ; + mPosts[N+1].meta_versions.push_back(meta); } int RsGxsForumModel::rowCount(const QModelIndex& parent) const { - void *ref = (parent.isValid())?parent.internalPointer():NULL ; + if(parent.column() > 0) + return 0; if(mPosts.empty()) // security. Should never happen. return 0; - uint32_t entry = 0 ; - int source_id ; - - if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) - { -#ifdef DEBUG_FORUMMODEL - std::cerr << "rowCount-2(" << parent << ") : " << 0 << std::endl; -#endif - return 0 ; - } - -#ifdef DEBUG_FORUMMODEL - std::cerr << "rowCount-3(" << parent << ") : " << mPosts[entry].children.size() << std::endl; -#endif - return mPosts[entry].children.size(); + if(!parent.isValid()) + return getChildrenCount(NULL); + else + return getChildrenCount(parent.internalPointer()); } - int RsGxsForumModel::columnCount(const QModelIndex &parent) const { return COLUMN_COUNT ; @@ -75,7 +68,10 @@ int RsGxsForumModel::columnCount(const QModelIndex &parent) const bool RsGxsForumModel::hasChildren(const QModelIndex &parent) const { - void *ref = (parent.isValid())?parent.internalPointer():NULL ; + if(!parent.isValid()) + return true; + + void *ref = parent.internalPointer(); uint32_t entry = 0; if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) @@ -86,8 +82,8 @@ bool RsGxsForumModel::hasChildren(const QModelIndex &parent) const return false ; } -#ifdef DEBUG_DOWNLOADLIST - std::cerr << "hasChildren-3(" << parent << ") : " << !mDownloads[entry].peers.empty() << std::endl; +#ifdef DEBUG_FORUMMODEL + std::cerr << "hasChildren-3(" << parent << ") : " << !mPosts[entry].children.empty() << std::endl; #endif return !mPosts[entry].children.empty(); } @@ -112,7 +108,7 @@ bool RsGxsForumModel::convertRefPointerToTabEntry(void *ref,uint32_t& entry) if(val > (intptr_t)(~(uint32_t(0)))) // make sure the pointer is an int that fits in 32bits { - std::cerr << "(EE) trying to make a ForumModelIndex out of a number that is larger than 2^32 !" << std::endl; + std::cerr << "(EE) trying to make a ForumModelIndex out of a number that is larger than 2^32-1 !" << std::endl; return false ; } entry = uint32_t(val); @@ -122,70 +118,117 @@ bool RsGxsForumModel::convertRefPointerToTabEntry(void *ref,uint32_t& entry) QModelIndex RsGxsForumModel::index(int row, int column, const QModelIndex & parent) const { - if(row < 0 || column < 0 || column >= COLUMN_COUNT) +// if(!hasIndex(row,column,parent)) + if(row < 0 || column < 0 || column >= COLUMN_COUNT) return QModelIndex(); - void *parent_ref = (parent.isValid())?parent.internalPointer():NULL ; - uint32_t parent_entry = 0; - int source_id=0 ; - - // We dont need to handle parent==NULL because the conversion will return entry=0 which is what we need. - - if(!convertRefPointerToTabEntry(parent_ref,parent_entry) || parent_entry >= mPosts.size()) - { -#ifdef DEBUG_FORUMMODEL - std::cerr << "index-5(" << row << "," << column << " parent=" << parent << ") : " << "NULL"<< std::endl ; -#endif - return QModelIndex() ; - } - - void *ref = NULL ; - - if(row >= mPosts[parent_entry].children.size() || !convertTabEntryToRefPointer(mPosts[parent_entry].children[row],ref)) - { -#ifdef DEBUG_FORUMMODEL - std::cerr << "index-4(" << row << "," << column << " parent=" << parent << ") : " << "NULL" << std::endl; -#endif - return QModelIndex() ; - } - + void *ref = getChildRef(parent.internalPointer(),row); #ifdef DEBUG_FORUMMODEL std::cerr << "index-3(" << row << "," << column << " parent=" << parent << ") : " << createIndex(row,column,ref) << std::endl; #endif return createIndex(row,column,ref) ; } -QModelIndex RsGxsForumModel::parent(const QModelIndex& child) const +QModelIndex RsGxsForumModel::parent(const QModelIndex& index) const { - void *child_ref = (child.isValid())?child.internalPointer():NULL ; + if(!index.isValid()) + return QModelIndex(); - if(!child_ref) - return QModelIndex() ; + void *child_ref = index.internalPointer(); + int row=0; - ForumModelIndex child_entry ; + void *parent_ref = getParentRef(child_ref,row) ; - if(!convertRefPointerToTabEntry(child_ref,child_entry) || child_entry >= mPosts.size()) - return QModelIndex() ; + if(parent_ref == NULL) // root + return QModelIndex() ; - void *parent_ref =NULL; - ForumModelIndex parent_entry = mPosts[child_entry].parent; - QModelIndex indx; + return createIndex(row,0,parent_ref); +} + +Qt::ItemFlags RsGxsForumModel::flags(const QModelIndex& index) const +{ + if (!index.isValid()) + return 0; + + return QAbstractItemModel::flags(index); +} + +void *RsGxsForumModel::getChildRef(void *ref,int row) const +{ + ForumModelIndex entry ; + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + return NULL ; + + void *new_ref; + if(row >= mPosts[entry].children.size()) + return NULL; + + convertTabEntryToRefPointer(mPosts[entry].children[row],new_ref); + + return new_ref; +} + +void *RsGxsForumModel::getParentRef(void *ref,int& row) const +{ + ForumModelIndex ref_entry; + + if(!convertRefPointerToTabEntry(ref,ref_entry) || ref_entry >= mPosts.size()) + return NULL ; + + ForumModelIndex parent_entry = mPosts[ref_entry].parent; if(parent_entry == 0) // top level index - indx = QModelIndex() ; + { + row = 0; + return NULL ; + } else { - if(!convertTabEntryToRefPointer(parent_entry,parent_ref)) - return QModelIndex() ; + void *parent_ref; + convertTabEntryToRefPointer(parent_entry,parent_ref); + row = mPosts[parent_entry].prow; - indx = createIndex(mPosts[parent_entry].prow,child.column(),parent_ref) ; + return parent_ref; } -#ifdef DEBUG_FORUMMODEL - std::cerr << "parent-1(" << child << ") : " << indx << std::endl; -#endif - return indx; } +int RsGxsForumModel::getChildrenCount(void *ref) const +{ + uint32_t entry = 0 ; + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + return 0 ; + + return mPosts[entry].children.size(); +} + + + +//bool RsGxsForumModel::hasIndex(int row,int column,const QModelIndex& parent) const +//{ +// if(row < 0 || column < 0 || column >= COLUMN_COUNT) +// return false; +// +// if(!parent.isValid()) +// return false; +// +// ForumModelIndex entry; +// +// convertRefPointerToTabEntry(parent.internalPointer(),entry); +// +// if(entry >= mPosts.size()) +// return false; +// +// if(row >= mPosts[entry].children.size()) +// return false; +// +// if(mPosts[entry].children[row] >= mPosts.size()) +// return false; +// +// return true; +//} + QVariant RsGxsForumModel::headerData(int section, Qt::Orientation orientation, int role) const { if(role != Qt::DisplayRole) @@ -203,11 +246,13 @@ QVariant RsGxsForumModel::headerData(int section, Qt::Orientation orientation, i QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const { +#ifdef DEBUG_FORUMMODEL + std::cerr << "calling data(" << index << ") role=" << role << std::endl; +#endif + if(!index.isValid()) return QVariant(); - int coln = index.column() ; - switch(role) { case Qt::SizeHintRole: return sizeHintRole(index.column()) ; @@ -216,8 +261,8 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const case Qt::WhatsThisRole: case Qt::EditRole: case Qt::ToolTipRole: - case Qt::StatusTipRole: - return QVariant(); + case Qt::StatusTipRole: return QVariant(); + default: break; } void *ref = (index.isValid())?index.internalPointer():NULL ; @@ -266,10 +311,10 @@ QVariant RsGxsForumModel::sizeHintRole(int col) const switch(col) { default: - case COLUMN_TITLE: return QVariant( factor * 170 ); - case COLUMN_READ_STATUS: return QVariant( factor * 10 ); - case COLUMN_DATE: return QVariant( factor * 75 ); - case COLUMN_AUTHOR: return QVariant( factor * 75 ); + case COLUMN_TITLE: return QVariant( QSize(factor * 170, factor*14 )); + case COLUMN_READ_STATUS: return QVariant( QSize(factor * 10 , factor*14 )); + case COLUMN_DATE: return QVariant( QSize(factor * 75 , factor*14 )); + case COLUMN_AUTHOR: return QVariant( QSize(factor * 75 , factor*14 )); } } diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index e5fdbf976..a951116a8 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -1,4 +1,20 @@ +#ifdef SUSPENDED_CODE #include "retroshare/rsgxsifacetypes.h" +#else +#include +#include + +struct RsMsgMetaData +{ + std::string mMsgName ; + time_t mPublishTs; + uint32_t mMsgStatus; + QString mAuthorId; +}; + +#endif + +#include // This class holds the actual hierarchy of posts, represented by identifiers // It is responsible for auto-updating when necessary and holds a mutex to allow the Model to @@ -29,17 +45,18 @@ public: enum Roles{ SortRole = Qt::UserRole+1 }; - int rowCount(const QModelIndex& parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; - bool hasChildren(const QModelIndex &parent = QModelIndex()) const; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; - QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const; - QModelIndex parent(const QModelIndex& child) const; + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& child) const override; + Qt::ItemFlags flags(const QModelIndex& index) const override; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - QVariant sizeHintRole(int col) const; + QVariant sizeHintRole(int col) const; QVariant displayRole(const RsMsgMetaData& meta, int col) const; QVariant userRole(const RsMsgMetaData& meta, int col) const; QVariant decorationRole(const RsMsgMetaData &meta, int col) const; @@ -47,7 +64,12 @@ public: void update_posts(); private: - static bool convertTabEntryToRefPointer(uint32_t entry,void *& ref); + void *getParentRef(void *ref,int& row) const; + void *getChildRef(void *ref,int row) const; + //bool hasIndex(int row,int column,const QModelIndex& parent)const; + int getChildrenCount(void *ref) const; + + static bool convertTabEntryToRefPointer(uint32_t entry,void *& ref); static bool convertRefPointerToTabEntry(void *ref,uint32_t& entry); std::vector mPosts ; // store the list of posts updated from rsForums. From d8f9559b0e207e333c7b2b1bd761344c17d35c75 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 19 Nov 2018 23:33:19 +0100 Subject: [PATCH 04/79] fixed memory corruption bug in GxsForumModel --- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 4 ++-- retroshare-gui/src/gui/gxsforums/GxsForumModel.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 210d4f27f..a3a228374 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -33,7 +33,7 @@ RsGxsForumModel::RsGxsForumModel(QObject *parent) mPosts[i].prow = i-1; RsMsgMetaData meta; - meta.mMsgName = "message " + (QString::number(i).toStdString()) ; + meta.mMsgName = std::string("message ") + QString::number(i).toStdString() ; mPosts[i].meta_versions.push_back(meta); } @@ -44,7 +44,7 @@ RsGxsForumModel::RsGxsForumModel(QObject *parent) mPosts[N+1].prow = 0; RsMsgMetaData meta; - meta.mMsgName = "message " + (QString::number(N+1).toStdString()) ; + meta.mMsgName = std::string("message ") + QString::number(N+1).toStdString() ; mPosts[N+1].meta_versions.push_back(meta); } diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index a951116a8..556aff4f9 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -1,4 +1,4 @@ -#ifdef SUSPENDED_CODE +#ifndef SUSPENDED_CODE #include "retroshare/rsgxsifacetypes.h" #else #include From 2066248b3b44747460c244fb9e3dcc344e10e100 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 20 Nov 2018 23:28:07 +0100 Subject: [PATCH 05/79] started updating ForumFillThread to new model --- .../src/gui/gxsforums/GxsForumModel.cpp | 101 ++++++++++++++++-- .../src/gui/gxsforums/GxsForumModel.h | 27 ++++- .../gui/gxsforums/GxsForumThreadWidget.cpp | 1 + .../src/gui/gxsforums/GxsForumsFillThread.cpp | 74 ++++++++++++- 4 files changed, 191 insertions(+), 12 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index a3a228374..91836723f 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -260,7 +260,6 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const case Qt::TextColorRole: case Qt::WhatsThisRole: case Qt::EditRole: - case Qt::ToolTipRole: case Qt::StatusTipRole: return QVariant(); default: break; } @@ -299,11 +298,63 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: return displayRole (meta,index.column()) ; case Qt::DecorationRole: return decorationRole(meta,index.column()) ; case Qt::UserRole: return userRole (meta,index.column()) ; + case Qt::ToolTipRole: return toolTipRole (meta,index.column()) + + case ThreadPinnedRole: return pinnedRole(index.column()) ; + case MissingRole: return missingRole(index.column()) ; + case StatusRole: return statusRole(index.column()) ; default: return QVariant(); } } +QVariant RsGxsForumModel::statusRole(int column,const ForumModelPostEntry& fmpe) +{ + if(column != COLUMN_THREAD_DATA) + return QVariant(); + + return QVariant(fmpe.mMsgStatus); +} + +QVariant RsGxsForumModel::missingRole(int column,const ForumModelPostEntry& fmpe) +{ + if(column != COLUMN_THREAD_DATA) + return QVariant(); + + if(fmpe.mPostFlags & FLAG_POST_IS_MISSING) + return QVariant(true); + else + return QVariant(false); +} + +QVariant RsGxsForumModel::toolTipRole(int column,const ForumModelPostEntry& fmpe) +{ + if(column != COLUMN_THREAD_DISTRIBUTION) + return QVariant(); + + switch(fmpe.mReputationWaningLevel) + { + case 3: return QVariant(tr("Information for this identity is currently missing.")) ; + case 2: return QVariant(tr("You have banned this ID. The message will not be\ndisplayed nor forwarded to your friends.")) ; + case 1: return QVariant(tr("You have not set an opinion for this person,\n and your friends do not vote positively: Spam regulation \nprevents the message to be forwarded to your friends.")) ; + case 0: return QVariant(tr("Message will be forwarded to your friends.") ; + default: + return QVariant("[ERROR: missing reputation level information - contact the developers]"); + } +} + +QVariant RsGxsForumModel::pinnedRole(int column,const ForumModelPostEntry& fmpe) +{ + if(column != COLUMN_THREAD_DATE) + return QVariant(); + + if(fmpe.mFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) + return QVariant(true); + else + return QVariant(false); +} + + QVariant RsGxsForumModel::sizeHintRole(int col) const { float factor = QFontMetricsF(QApplication::font()).height()/14.0f ; @@ -318,15 +369,50 @@ QVariant RsGxsForumModel::sizeHintRole(int col) const } } +QVariant RsGxsForumModel::authorRole(int column,const ForumModelPostEntry& fmpe) +{ + if(column == COLUMN_THREAD_DATA) + return QVariant(QString::fromStdString(msg.mMeta.mAuthorId.toStdString())); + + return QVariant(); +} + +QVariant RsGxsForumModel::sortRole(int column,const ForumModelPostEntry& fmpe) +{ + if(column == COLUMN_THREAD_DATA) + return QVariant(QString::number(fmpe.mPublishTs)); // we should probably have leading zeroes here + +} + QVariant RsGxsForumModel::displayRole(const RsMsgMetaData& meta,int col) const { switch(col) { - case COLUMN_TITLE: return QVariant(QString::fromUtf8(meta.mMsgName.c_str())); - case COLUMN_READ_STATUS: return QVariant(meta.mMsgStatus); - case COLUMN_DATE: return QVariant(qulonglong(meta.mPublishTs)); - case COLUMN_AUTHOR: return QVariant(QString::fromStdString(meta.mAuthorId.toStdString())); + case COLUMN_TITLE: if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_REDACTED) + return QVariant(tr("[ ... Redacted message ... ]")); + else if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) + return QVariant(tr("[PINNED] ") + QString::fromUtf8(msg.mMeta.mMsgName.c_str())); + else + return QVariant(QString::fromUtf8(msg.mMeta.mMsgName.c_str())); + case COLUMN_READ_STATUS:return QVariant(meta.mMsgStatus); + case COLUMN_DATE: { + QDateTime qtime; + qtime.setTime_t(msg.mMeta.mPublishTs); + + return QVariant(DateTime::formatDateTime(qtime)); + } + + case COLUMN_AUTHOR: return QVariant(QString::fromStdString(meta.mAuthorId.toStdString())); + case COLUMN_THREAD_MSGID: return QVariant(QString::fromStdString(meta.mMsgId.toStdString())); +#ifdef TODO + if (filterColumn == COLUMN_THREAD_CONTENT) { + // need content for filter + QTextDocument doc; + doc.setHtml(QString::fromUtf8(msg.mMsg.c_str())); + item->setText(COLUMN_THREAD_CONTENT, doc.toPlainText().replace(QString("\n"), QString(" "))); + } +#endif default: return QVariant("[ TODO ]"); } @@ -381,7 +467,10 @@ QVariant RsGxsForumModel::userRole(const RsMsgMetaData &meta, int col) const QVariant RsGxsForumModel::decorationRole(const RsMsgMetaData& meta,int col) const { - return QVariant(); + if(col == COLUMN_THREAD_DISTRIBUTION) + return QVariant(fmpe.mReputationWarningLevel); + else + return QVariant(); } void RsGxsForumModel::update_posts() diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index 556aff4f9..384367097 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -24,12 +24,25 @@ struct RsMsgMetaData typedef uint32_t ForumModelIndex; -struct ForumPostEntry +struct ForumModelPostEntry { + typedef enum { // flags for display of posts + FLAG_POST_IS_PINNED = 0x0001, + FLAG_POST_IS_MISSING = 0x0002, + FLAG_POST_IS_REDACTED = 0x0004, + }; + + std::string mTitle ; + RsGxsId mAuthorId ; + RsGxsMessageId mMsgId; + uint32_t mPublishTs; + uint32_t mPostFlags; + int mReputationWarningLevel; + std::vector meta_versions; // maybe we don't need all this. Could be too large. - std::vector children; - ForumModelIndex parent; + std::vector mChildren; + ForumModelIndex mParent; int prow ; // parent row }; @@ -43,7 +56,11 @@ public: explicit RsGxsForumModel(QObject *parent = NULL); ~RsGxsForumModel(){} - enum Roles{ SortRole = Qt::UserRole+1 }; + enum Roles{ SortRole = Qt::UserRole+1, + ThreadPinnedRole = Qt::UserRole+2, + MissingRole = Qt::UserRole+3, + StatusRole = Qt::UserRole+4, + }; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; @@ -72,5 +89,5 @@ private: static bool convertTabEntryToRefPointer(uint32_t entry,void *& ref); static bool convertRefPointerToTabEntry(void *ref,uint32_t& entry); - std::vector mPosts ; // store the list of posts updated from rsForums. + std::vector mPosts ; // store the list of posts updated from rsForums. }; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index d33aab4eb..48609a9c0 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -1427,6 +1427,7 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum return item; } + QTreeWidgetItem *GxsForumThreadWidget::generateMissingItem(const RsGxsMessageId &msgId) { GxsIdRSTreeWidgetItem *item = new GxsIdRSTreeWidgetItem(mThreadCompareRole,GxsIdDetails::ICON_TYPE_AVATAR); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp index 7545e4f07..f0c61d877 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp @@ -23,9 +23,10 @@ #include "GxsForumsFillThread.h" #include "GxsForumThreadWidget.h" +#include "GxsForumModel.h" #include "retroshare/rsgxsflags.h" -#include +#include "retroshare/rsgxsforums.h" #include #include @@ -553,4 +554,75 @@ void GxsForumsFillThread::run() deleteLater(); } +QTreeWidgetItem *GxsForumsFillThread::convertMsgToThreadWidget(const RsGxsForumMsg& msg, bool useChildTS, uint32_t filterColumn, ForumModelIndex parent) +{ + ForumModelPostEntry fentry; + fentry.mMsgId = msg.mMeta.mMsgId; + fentry.mPublishTs = msg.mMeta.mPublishTs; + fentry.mParent = parent; + + if(mForumGroup.mPinnedPosts.ids.find(msg.mMeta.mMsgId) != mForumGroup.mPinnedPosts.ids.end()) + fentry.mFlags |= ForumModelPostEntry::FLAG_POST_IS_PINNED; + + // Early check for a message that should be hidden because its author + // is flagged with a bad reputation + + uint32_t idflags =0; + RsReputations::ReputationLevel reputation_level = rsReputations->overallReputationLevel(msg.mMeta.mAuthorId,&idflags) ; + bool redacted = false; + + if(reputation_level == RsReputations::REPUTATION_LOCALLY_NEGATIVE) + fentry.mPostFlags |= ForumModelPostEntry::FLAG_POST_IS_REDACTED; + + // We use a specific item model for forums in order to handle the post pinning. + + if(reputation_level == RsReputations::REPUTATION_UNKNOWN) + fentry.mReputationWarningLevel = 3 ; + else if(reputation_level == RsReputations::REPUTATION_LOCALLY_NEGATIVE) + fentry.mReputationWarningLevel = 2 ; + else if(reputation_level < rsGxsForums->minReputationForForwardingMessages(mForumGroup.mMeta.mSignFlags,idflags)) + fentry.mReputationWarningLevel = 1 ; + else + fentry.mReputationWarningLevel = 0 ; + +#ifdef TODO + // This is an attempt to put pinned posts on the top. We should rather use a QSortFilterProxyModel here. + QString itemSort = QString::number(msg.mMeta.mPublishTs);//Don't need to format it as for sort. + + if (useChildTS) + { + for(QTreeWidgetItem *grandParent = parent; grandParent!=NULL; grandParent = grandParent->parent()) + { + //Update Parent Child TimeStamp + QString oldTSSort = grandParent->data(COLUMN_THREAD_DATE, ROLE_THREAD_SORT).toString(); + + QString oldCTSSort = oldTSSort.split("|").at(0); + QString oldPTSSort = oldTSSort.contains("|") ? oldTSSort.split(" | ").at(1) : oldCTSSort; +#ifdef SHOW_COMBINED_DATES + QString oldTSText = grandParent->text(COLUMN_THREAD_DATE); + QString oldCTSText = oldTSText.split("|").at(0); + QString oldPTSText = oldTSText.contains("|") ? oldTSText.split(" | ").at(1) : oldCTSText;//If first time parent get only its mPublishTs + #endif + if (oldCTSSort.toDouble() < itemSort.toDouble()) + { +#ifdef SHOW_COMBINED_DATES + grandParent->setText(COLUMN_THREAD_DATE, DateTime::formatDateTime(qtime) + " | " + oldPTSText); +#endif + grandParent->setData(COLUMN_THREAD_DATE, ROLE_THREAD_SORT, itemSort + " | " + oldPTSSort); + } + } + } +#endif +//#TODO +#if 0 + if (IS_GROUP_SUBSCRIBED(subscribeFlags) && !(msginfo.mMsgFlags & RS_DISTRIB_MISSING_MSG)) { + rsGxsForums->getMessageStatus(msginfo.forumId, msginfo.msgId, status); + } else { + // show message as read + status = RSGXS_MSG_STATUS_READ; + } +#endif + if (parent) parent->addChild(item); + return item; +} From d3565c2ee4436526fb2c7a8ec73dcfd0de8b6f19 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 21 Nov 2018 23:18:08 +0100 Subject: [PATCH 06/79] implemented update of posts for new model. Unfinished yet. --- .../src/gui/gxsforums/GxsForumModel.cpp | 703 +++++++++++++----- .../src/gui/gxsforums/GxsForumModel.h | 35 +- .../gui/gxsforums/GxsForumThreadWidget.cpp | 13 - .../src/gui/gxsforums/GxsForumsFillThread.cpp | 71 -- 4 files changed, 545 insertions(+), 277 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 91836723f..08eb676d8 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -2,15 +2,24 @@ #include #include +#include "util/qtthreadsutils.h" #include "GxsForumModel.h" +#include "retroshare/rsgxsforums.h" #define DEBUG_FORUMMODEL -#define COLUMN_TITLE 0 -#define COLUMN_READ_STATUS 1 -#define COLUMN_DATE 2 -#define COLUMN_AUTHOR 3 -#define COLUMN_COUNT 4 +#define COLUMN_THREAD_TITLE 0 +#define COLUMN_THREAD_READ 1 +#define COLUMN_THREAD_DATE 2 +#define COLUMN_THREAD_DISTRIBUTION 3 +#define COLUMN_THREAD_AUTHOR 4 +#define COLUMN_THREAD_SIGNED 5 +#define COLUMN_THREAD_CONTENT 6 +#define COLUMN_THREAD_COUNT 7 +#define COLUMN_THREAD_MSGID 8 +#define COLUMN_THREAD_NB_COLUMNS 9 + +#define COLUMN_THREAD_DATA 0 // column for storing the userdata like parentid Q_DECLARE_METATYPE(RsMsgMetaData); @@ -21,31 +30,29 @@ RsGxsForumModel::RsGxsForumModel(QObject *parent) { mPosts.resize(1); // adds a sentinel item - // adds some fake posts to debug - - int N=5 ; - mPosts.resize(N+1); - - for(int i=1;i<=N;++i) - { - mPosts[0].children.push_back(ForumModelIndex(i)); - mPosts[i].parent = ForumModelIndex(0); - mPosts[i].prow = i-1; - - RsMsgMetaData meta; - meta.mMsgName = std::string("message ") + QString::number(i).toStdString() ; - mPosts[i].meta_versions.push_back(meta); - } - - // add one child to last post - mPosts.resize(N+2); - mPosts[N].children.push_back(ForumModelIndex(N+1)); - mPosts[N+1].parent = ForumModelIndex(N); - mPosts[N+1].prow = 0; - - RsMsgMetaData meta; - meta.mMsgName = std::string("message ") + QString::number(N+1).toStdString() ; - mPosts[N+1].meta_versions.push_back(meta); +// // adds some fake posts to debug +// +// int N=5 ; +// mPosts.resize(N+1); +// +// for(int i=1;i<=N;++i) +// { +// mPosts[0].mChildren.push_back(ForumModelIndex(i)); +// mPosts[i].mParent = ForumModelIndex(0); +// mPosts[i].prow = i-1; +// +// RsMsgMetaData meta; +// meta.mMsgName = std::string("message ") + QString::number(i).toStdString() ; +// } +// +// // add one child to last post +// mPosts.resize(N+2); +// mPosts[N].mChildren.push_back(ForumModelIndex(N+1)); +// mPosts[N+1].mParent = ForumModelIndex(N); +// mPosts[N+1].prow = 0; +// +// RsMsgMetaData meta; +// meta.mMsgName = std::string("message ") + QString::number(N+1).toStdString() ; } int RsGxsForumModel::rowCount(const QModelIndex& parent) const @@ -63,7 +70,7 @@ int RsGxsForumModel::rowCount(const QModelIndex& parent) const } int RsGxsForumModel::columnCount(const QModelIndex &parent) const { - return COLUMN_COUNT ; + return COLUMN_THREAD_COUNT ; } bool RsGxsForumModel::hasChildren(const QModelIndex &parent) const @@ -83,9 +90,9 @@ bool RsGxsForumModel::hasChildren(const QModelIndex &parent) const } #ifdef DEBUG_FORUMMODEL - std::cerr << "hasChildren-3(" << parent << ") : " << !mPosts[entry].children.empty() << std::endl; + std::cerr << "hasChildren-3(" << parent << ") : " << !mPosts[entry].mChildren.empty() << std::endl; #endif - return !mPosts[entry].children.empty(); + return !mPosts[entry].mChildren.empty(); } bool RsGxsForumModel::convertTabEntryToRefPointer(uint32_t entry,void *& ref) @@ -119,7 +126,7 @@ bool RsGxsForumModel::convertRefPointerToTabEntry(void *ref,uint32_t& entry) QModelIndex RsGxsForumModel::index(int row, int column, const QModelIndex & parent) const { // if(!hasIndex(row,column,parent)) - if(row < 0 || column < 0 || column >= COLUMN_COUNT) + if(row < 0 || column < 0 || column >= COLUMN_THREAD_COUNT) return QModelIndex(); void *ref = getChildRef(parent.internalPointer(),row); @@ -161,10 +168,10 @@ void *RsGxsForumModel::getChildRef(void *ref,int row) const return NULL ; void *new_ref; - if(row >= mPosts[entry].children.size()) + if(row >= mPosts[entry].mChildren.size()) return NULL; - convertTabEntryToRefPointer(mPosts[entry].children[row],new_ref); + convertTabEntryToRefPointer(mPosts[entry].mChildren[row],new_ref); return new_ref; } @@ -176,7 +183,7 @@ void *RsGxsForumModel::getParentRef(void *ref,int& row) const if(!convertRefPointerToTabEntry(ref,ref_entry) || ref_entry >= mPosts.size()) return NULL ; - ForumModelIndex parent_entry = mPosts[ref_entry].parent; + ForumModelIndex parent_entry = mPosts[ref_entry].mParent; if(parent_entry == 0) // top level index { @@ -200,7 +207,7 @@ int RsGxsForumModel::getChildrenCount(void *ref) const if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) return 0 ; - return mPosts[entry].children.size(); + return mPosts[entry].mChildren.size(); } @@ -237,10 +244,9 @@ QVariant RsGxsForumModel::headerData(int section, Qt::Orientation orientation, i switch(section) { default: - case COLUMN_TITLE: return tr("Title"); - case COLUMN_READ_STATUS: return tr("Read Status"); - case COLUMN_DATE: return tr("Date"); - case COLUMN_AUTHOR: return tr("Author"); + case COLUMN_THREAD_TITLE: return tr("Title"); + case COLUMN_THREAD_DATE: return tr("Date"); + case COLUMN_THREAD_AUTHOR: return tr("Author"); } } @@ -287,7 +293,7 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const return QVariant() ; } - const RsMsgMetaData& meta(mPosts[entry].meta_versions[0]) ; + const ForumModelPostEntry& fmpe(mPosts[entry]); #ifdef DEBUG_FORUMMODEL std::cerr << " [ok]" << std::endl; @@ -295,60 +301,60 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const switch(role) { - case Qt::DisplayRole: return displayRole (meta,index.column()) ; - case Qt::DecorationRole: return decorationRole(meta,index.column()) ; - case Qt::UserRole: return userRole (meta,index.column()) ; - case Qt::ToolTipRole: return toolTipRole (meta,index.column()) + case Qt::DisplayRole: return displayRole (fmpe,index.column()) ; + case Qt::DecorationRole: return decorationRole(fmpe,index.column()) ; + case Qt::UserRole: return userRole (fmpe,index.column()) ; + case Qt::ToolTipRole: return toolTipRole (fmpe,index.column()) ; - case ThreadPinnedRole: return pinnedRole(index.column()) ; - case MissingRole: return missingRole(index.column()) ; - case StatusRole: return statusRole(index.column()) ; + case ThreadPinnedRole: return pinnedRole (fmpe,index.column()) ; + case MissingRole: return missingRole (fmpe,index.column()) ; + case StatusRole: return statusRole (fmpe,index.column()) ; default: return QVariant(); } } -QVariant RsGxsForumModel::statusRole(int column,const ForumModelPostEntry& fmpe) +QVariant RsGxsForumModel::statusRole(const ForumModelPostEntry& fmpe,int column) const { if(column != COLUMN_THREAD_DATA) return QVariant(); - return QVariant(fmpe.mMsgStatus); + return QVariant(fmpe.mStatus); } -QVariant RsGxsForumModel::missingRole(int column,const ForumModelPostEntry& fmpe) +QVariant RsGxsForumModel::missingRole(const ForumModelPostEntry& fmpe,int column) const { if(column != COLUMN_THREAD_DATA) return QVariant(); - if(fmpe.mPostFlags & FLAG_POST_IS_MISSING) + if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) return QVariant(true); else return QVariant(false); } -QVariant RsGxsForumModel::toolTipRole(int column,const ForumModelPostEntry& fmpe) +QVariant RsGxsForumModel::toolTipRole(const ForumModelPostEntry& fmpe,int column) const { if(column != COLUMN_THREAD_DISTRIBUTION) return QVariant(); - switch(fmpe.mReputationWaningLevel) + switch(fmpe.mReputationWarningLevel) { case 3: return QVariant(tr("Information for this identity is currently missing.")) ; case 2: return QVariant(tr("You have banned this ID. The message will not be\ndisplayed nor forwarded to your friends.")) ; case 1: return QVariant(tr("You have not set an opinion for this person,\n and your friends do not vote positively: Spam regulation \nprevents the message to be forwarded to your friends.")) ; - case 0: return QVariant(tr("Message will be forwarded to your friends.") ; + case 0: return QVariant(tr("Message will be forwarded to your friends.")) ; default: return QVariant("[ERROR: missing reputation level information - contact the developers]"); } } -QVariant RsGxsForumModel::pinnedRole(int column,const ForumModelPostEntry& fmpe) +QVariant RsGxsForumModel::pinnedRole(const ForumModelPostEntry& fmpe,int column) const { if(column != COLUMN_THREAD_DATE) return QVariant(); - if(fmpe.mFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) + if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) return QVariant(true); else return QVariant(false); @@ -362,14 +368,13 @@ QVariant RsGxsForumModel::sizeHintRole(int col) const switch(col) { default: - case COLUMN_TITLE: return QVariant( QSize(factor * 170, factor*14 )); - case COLUMN_READ_STATUS: return QVariant( QSize(factor * 10 , factor*14 )); - case COLUMN_DATE: return QVariant( QSize(factor * 75 , factor*14 )); - case COLUMN_AUTHOR: return QVariant( QSize(factor * 75 , factor*14 )); + case COLUMN_THREAD_TITLE: return QVariant( QSize(factor * 170, factor*14 )); + case COLUMN_THREAD_DATE: return QVariant( QSize(factor * 75 , factor*14 )); + case COLUMN_THREAD_AUTHOR: return QVariant( QSize(factor * 75 , factor*14 )); } } -QVariant RsGxsForumModel::authorRole(int column,const ForumModelPostEntry& fmpe) +QVariant RsGxsForumModel::authorRole(const ForumModelPostEntry& fmpe,int column) const { if(column == COLUMN_THREAD_DATA) return QVariant(QString::fromStdString(msg.mMeta.mAuthorId.toStdString())); @@ -377,34 +382,34 @@ QVariant RsGxsForumModel::authorRole(int column,const ForumModelPostEntry& fmpe) return QVariant(); } -QVariant RsGxsForumModel::sortRole(int column,const ForumModelPostEntry& fmpe) +QVariant RsGxsForumModel::sortRole(const ForumModelPostEntry& fmpe,int column) const { if(column == COLUMN_THREAD_DATA) return QVariant(QString::number(fmpe.mPublishTs)); // we should probably have leading zeroes here } -QVariant RsGxsForumModel::displayRole(const RsMsgMetaData& meta,int col) const +QVariant RsGxsForumModel::displayRole(const ForumModelPostEntry& fmpe,int col) const { switch(col) { - case COLUMN_TITLE: if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_REDACTED) + case COLUMN_THREAD_TITLE: if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_REDACTED) return QVariant(tr("[ ... Redacted message ... ]")); else if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) - return QVariant(tr("[PINNED] ") + QString::fromUtf8(msg.mMeta.mMsgName.c_str())); + return QVariant(tr("[PINNED] ") + QString::fromUtf8(fmpe.mTitle.c_str())); else - return QVariant(QString::fromUtf8(msg.mMeta.mMsgName.c_str())); + return QVariant(QString::fromUtf8(fmpe.mTitle.c_str())); - case COLUMN_READ_STATUS:return QVariant(meta.mMsgStatus); - case COLUMN_DATE: { + //case COLUMN_THREAD_READ_STATUS:return QVariant(fmpe.mMsgStatus); + case COLUMN_THREAD_DATE: { QDateTime qtime; - qtime.setTime_t(msg.mMeta.mPublishTs); + qtime.setTime_t(fmpe.mPublishTs); - return QVariant(DateTime::formatDateTime(qtime)); + return QVariant(QDateTime::formatDateTime(qtime)); } - case COLUMN_AUTHOR: return QVariant(QString::fromStdString(meta.mAuthorId.toStdString())); - case COLUMN_THREAD_MSGID: return QVariant(QString::fromStdString(meta.mMsgId.toStdString())); + case COLUMN_THREAD_AUTHOR: return QVariant(QString::fromStdString(fmpe.mAuthorId.toStdString())); + case COLUMN_THREAD_MSGID: return QVariant(QString::fromStdString(fmpe.mMsgId.toStdString())); #ifdef TODO if (filterColumn == COLUMN_THREAD_CONTENT) { // need content for filter @@ -421,51 +426,7 @@ QVariant RsGxsForumModel::displayRole(const RsMsgMetaData& meta,int col) const return QVariant("[ERROR]"); } -QVariant RsGxsForumModel::userRole(const RsMsgMetaData &meta, int col) const -{ -#ifdef TODO - switch(col) - { - case COLUMN_PROGRESS: - { - FileChunksInfo fcinfo; - if (!rsFiles->FileDownloadChunksDetails(fileInfo.hash, fcinfo)) - return QVariant(); - - FileProgressInfo pinfo; - pinfo.cmap = fcinfo.chunks; - pinfo.type = FileProgressInfo::DOWNLOAD_LINE; - pinfo.progress = (fileInfo.size == 0) ? 0 : (fileInfo.transfered * 100.0 / fileInfo.size); - pinfo.nb_chunks = pinfo.cmap._map.empty() ? 0 : fcinfo.chunks.size(); - - for (uint32_t i = 0; i < fcinfo.chunks.size(); ++i) - switch(fcinfo.chunks[i]) - { - case FileChunksInfo::CHUNK_CHECKING: pinfo.chunks_in_checking.push_back(i); - break ; - case FileChunksInfo::CHUNK_ACTIVE: pinfo.chunks_in_progress.push_back(i); - break ; - case FileChunksInfo::CHUNK_DONE: - case FileChunksInfo::CHUNK_OUTSTANDING: - break ; - } - - return QVariant::fromValue(pinfo); - } - - case COLUMN_ID: return QVariant(QString::fromStdString(fileInfo.hash.toStdString())); - - - default: - return QVariant(); - } - } -#endif - return QVariant(); - -} - -QVariant RsGxsForumModel::decorationRole(const RsMsgMetaData& meta,int col) const +QVariant RsGxsForumModel::decorationRole(const ForumModelPostEntry& fmpe,int col) const { if(col == COLUMN_THREAD_DISTRIBUTION) return QVariant(fmpe.mReputationWarningLevel); @@ -473,77 +434,451 @@ QVariant RsGxsForumModel::decorationRole(const RsMsgMetaData& meta,int col) cons return QVariant(); } -void RsGxsForumModel::update_posts() +void RsGxsForumModel::setForum(const RsGxsGroupId& forumGroup) { + if(mForumGroupId == forumGroup) + return ; + + mPosts.clear(); + mForumGroupId = forumGroup; + + update_posts(); +} + +void RsGxsForumModel::update_posts(const RsGxsGroupId& group_id) +{ + RsThread::async([this, group_id]() + { + // 1 - get message data from p3GxsForums + + std::list forumIds; + std::vector messages; + std::vector groups; + + forumIds.push_back(group_id); + + if(!rsGxsForums->getForumsInfo(forumIds,groups)) + { + std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve forum group info for forum " << group_id << std::endl; + return; + } + + if(!rsGxsForums->getForumsContent(forumIds,messages)) + { + std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve forum message info for forum " << group_id << std::endl; + return; + } + + // 2 - sort the messages into a proper hierarchy + + std::vector *vect = new std::vector(); + + computeMessagesHierarchy(groups[0],messages,*vect); + + // 3 - update the model in the UI thread. + + RsQThreadUtils::postToObject( [vect,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, note that + * Qt::QueuedConnection is important! + */ + + setPosts(*vect) ; + delete vect; + + + }, this ); + + }); +} + +ForumModelIndex RsGxsForumModel::addEntry(std::vector& posts,const ForumModelPostEntry& entry,ForumModelIndex parent) +{ + uint32_t N = posts.size(); + posts.push_back(entry); + + posts[N].mParent = parent; + posts[parent].mChildren.push_back(N); + + return ForumModelIndex(N); +} + +void RsGxsForumModel::generateMissingItem(const RsGxsMessageId &msgId,ForumModelPostEntry& entry) +{ + entry.mPostFlags = ForumModelPostEntry::FLAG_POST_IS_MISSING ; + entry.mTitle = std::string(tr("[ ... Missing Message ... ]").toUtf8()); + entry.mMsgId = msgId; + entry.mAuthorId.clear(); + entry.mPublishTs=0; + entry.mReputationWarningLevel = 3; +} + +void RsGxsForumModel::convertMsgToPostEntry(const RsGxsForumGroup& mForumGroup,const RsGxsForumMsg& msg, bool useChildTS, uint32_t filterColumn,ForumModelPostEntry& fentry) +{ + fentry.mMsgId = msg.mMeta.mMsgId; + fentry.mPublishTs = msg.mMeta.mPublishTs; + fentry.mStatus = msg.mMeta.mMsgStatus; + + if(mForumGroup.mPinnedPosts.ids.find(msg.mMeta.mMsgId) != mForumGroup.mPinnedPosts.ids.end()) + fentry.mPostFlags |= ForumModelPostEntry::FLAG_POST_IS_PINNED; + + // Early check for a message that should be hidden because its author + // is flagged with a bad reputation + + uint32_t idflags =0; + RsReputations::ReputationLevel reputation_level = rsReputations->overallReputationLevel(msg.mMeta.mAuthorId,&idflags) ; + bool redacted = false; + + if(reputation_level == RsReputations::REPUTATION_LOCALLY_NEGATIVE) + fentry.mPostFlags |= ForumModelPostEntry::FLAG_POST_IS_REDACTED; + + // We use a specific item model for forums in order to handle the post pinning. + + if(reputation_level == RsReputations::REPUTATION_UNKNOWN) + fentry.mReputationWarningLevel = 3 ; + else if(reputation_level == RsReputations::REPUTATION_LOCALLY_NEGATIVE) + fentry.mReputationWarningLevel = 2 ; + else if(reputation_level < rsGxsForums->minReputationForForwardingMessages(mForumGroup.mMeta.mSignFlags,idflags)) + fentry.mReputationWarningLevel = 1 ; + else + fentry.mReputationWarningLevel = 0 ; + #ifdef TODO - std::list downHashes; - rsFiles->FileDownloads(downHashes); + // This is an attempt to put pinned posts on the top. We should rather use a QSortFilterProxyModel here. + QString itemSort = QString::number(msg.mMeta.mPublishTs);//Don't need to format it as for sort. - size_t old_size = mDownloads.size(); - - mDownloads.resize(downHashes.size()) ; - - if(old_size < mDownloads.size()) + if (useChildTS) { - beginInsertRows(QModelIndex(), old_size, mDownloads.size()-1); - insertRows(old_size, mDownloads.size() - old_size); - endInsertRows(); - } - else if(mDownloads.size() < old_size) - { - beginRemoveRows(QModelIndex(), mDownloads.size(), old_size-1); - removeRows(mDownloads.size(), old_size - mDownloads.size()); - endRemoveRows(); - } - - uint32_t i=0; - - for(auto it(downHashes.begin());it!=downHashes.end();++it,++i) - { - FileInfo fileInfo(mDownloads[i]); // we dont update the data itself but only a copy of it.... - int old_size = fileInfo.peers.size() ; - - rsFiles->FileDetails(*it, RS_FILE_HINTS_DOWNLOAD, fileInfo); - - int new_size = fileInfo.peers.size() ; - - if(old_size < new_size) + for(QTreeWidgetItem *grandParent = parent; grandParent!=NULL; grandParent = grandParent->parent()) { - beginInsertRows(index(i,0), old_size, new_size-1); - insertRows(old_size, new_size - old_size,index(i,0)); -#ifdef DEBUG_DOWNLOADLIST - std::cerr << "called insert rows ( " << old_size << ", " << new_size - old_size << ",index(" << index(i,0)<< "))" << std::endl; + //Update Parent Child TimeStamp + QString oldTSSort = grandParent->data(COLUMN_THREAD_DATE, ROLE_THREAD_SORT).toString(); + + QString oldCTSSort = oldTSSort.split("|").at(0); + QString oldPTSSort = oldTSSort.contains("|") ? oldTSSort.split(" | ").at(1) : oldCTSSort; +#ifdef SHOW_COMBINED_DATES + QString oldTSText = grandParent->text(COLUMN_THREAD_DATE); + QString oldCTSText = oldTSText.split("|").at(0); + QString oldPTSText = oldTSText.contains("|") ? oldTSText.split(" | ").at(1) : oldCTSText;//If first time parent get only its mPublishTs + #endif + if (oldCTSSort.toDouble() < itemSort.toDouble()) + { +#ifdef SHOW_COMBINED_DATES + grandParent->setText(COLUMN_THREAD_DATE, DateTime::formatDateTime(qtime) + " | " + oldPTSText); #endif - endInsertRows(); + grandParent->setData(COLUMN_THREAD_DATE, ROLE_THREAD_SORT, itemSort + " | " + oldPTSSort); + } } - else if(new_size < old_size) - { - beginRemoveRows(index(i,0), new_size, old_size-1); - removeRows(new_size, old_size - new_size,index(i,0)); -#ifdef DEBUG_DOWNLOADLIST - std::cerr << "called remove rows ( " << old_size << ", " << old_size - new_size << ",index(" << index(i,0)<< "))" << std::endl; -#endif - endRemoveRows(); - } - - uint32_t old_status = mDownloads[i].downloadStatus ; - - mDownloads[i] = fileInfo ; // ... because insertRows() calls rowCount() which needs to be consistent with the *old* number of rows. - - if(fileInfo.downloadStatus == FT_STATE_DOWNLOADING || old_status != fileInfo.downloadStatus) - { - QModelIndex topLeft = createIndex(i,0), bottomRight = createIndex(i, COLUMN_COUNT-1); - emit dataChanged(topLeft, bottomRight); - } - - // This is apparently not needed. - // - // if(!mDownloads.empty()) - // { - // QModelIndex topLeft = createIndex(0,0), bottomRight = createIndex(mDownloads.size()-1, COLUMN_COUNT-1); - // emit dataChanged(topLeft, bottomRight); - // mDownloads[i] = fileInfo ; - // } } #endif } + +static bool decreasing_time_comp(const QPair& e1,const QPair& e2) { return e2.first < e1.first ; } + +void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_group,const std::vector& msgs_array,std::vector& posts) +{ + std::cerr << "updating messages data with " << msgs_array.size() << " messages" << std::endl; + +//#ifdef DEBUG_FORUMS + std::cerr << "Retrieved group data: " << std::endl; + std::cerr << " Group ID: " << forum_group.mMeta.mGroupId << std::endl; + std::cerr << " Admin lst: " << forum_group.mAdminList.ids.size() << " elements." << std::endl; + for(auto it(forum_group.mAdminList.ids.begin());it!=forum_group.mAdminList.ids.end();++it) + std::cerr << " " << *it << std::endl; + std::cerr << " Pinned Post: " << forum_group.mPinnedPosts.ids.size() << " messages." << std::endl; + for(auto it(forum_group.mPinnedPosts.ids.begin());it!=forum_group.mPinnedPosts.ids.end();++it) + std::cerr << " " << *it << std::endl; +//#endif + + /* get messages */ + std::map msgs; + + for(uint32_t i=0;i > > mPostVersions ; + + // ThreadList contains the list of parent threads. The algorithm below iterates through all messages + // and tries to establish parenthood relationships between them, given that we only know the + // immediate parent of a message and now its children. Some messages have a missing parent and for them + // a fake top level parent is generated. + + // In order to be efficient, we first create a structure that lists the children of every mesage ID in the list. + // Then the hierarchy of message is build by attaching the kids to every message until all of them have been processed. + // The messages with missing parents will be the last ones remaining in the list. + + std::list > threadStack; + std::map > kids_array ; + std::set missing_parents; + + // First of all, remove all older versions of posts. This is done by first adding all posts into a hierarchy structure + // and then removing all posts which have a new versions available. The older versions are kept appart. + +#ifdef DEBUG_FORUMS + std::cerr << "GxsForumsFillThread::run() Collecting post versions" << std::endl; +#endif + mPostVersions.clear(); + std::list msg_stack ; + + for ( std::map::iterator msgIt = msgs.begin(); msgIt != msgs.end();++msgIt) + { + if(!msgIt->second.mMeta.mOrigMsgId.isNull() && msgIt->second.mMeta.mOrigMsgId != msgIt->second.mMeta.mMsgId) + { +#ifdef DEBUG_FORUMS + std::cerr << " Post " << msgIt->second.mMeta.mMsgId << " is a new version of " << msgIt->second.mMeta.mOrigMsgId << std::endl; +#endif + std::map::iterator msgIt2 = msgs.find(msgIt->second.mMeta.mOrigMsgId); + + // Ensuring that the post exists allows to only collect the existing data. + + if(msgIt2 == msgs.end()) + continue ; + + // Make sure that the author is the same than the original message, or is a moderator. This should always happen when messages are constructed using + // the UI but nothing can prevent a nasty user to craft a new version of a message with his own signature. + + if(msgIt2->second.mMeta.mAuthorId != msgIt->second.mMeta.mAuthorId) + { + if( !IS_FORUM_MSG_MODERATION(msgIt->second.mMeta.mMsgFlags) ) // if authors are different the moderation flag needs to be set on the editing msg + continue ; + + if( forum_group.mAdminList.ids.find(msgIt->second.mMeta.mAuthorId)==forum_group.mAdminList.ids.end()) // if author is not a moderator, continue + continue ; + } + + // always add the post a self version + + if(mPostVersions[msgIt->second.mMeta.mOrigMsgId].empty()) + mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(QPair(msgIt2->second.mMeta.mPublishTs,msgIt2->second.mMeta.mMsgId)) ; + + mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(QPair(msgIt->second.mMeta.mPublishTs,msgIt->second.mMeta.mMsgId)) ; + } + } + + // The following code assembles all new versions of a given post into the same array, indexed by the oldest version of the post. + + for(QMap > >::iterator it(mPostVersions.begin());it!=mPostVersions.end();++it) + { + QVector >& v(*it) ; + + for(int32_t i=0;i > >::iterator it2 = mPostVersions.find(sub_msg_id); + + if(it2 != mPostVersions.end()) + { + for(int32_t j=0;j<(*it2).size();++j) + if((*it2)[j].second != sub_msg_id) // dont copy it, since it is already present at slot i + v.append((*it2)[j]) ; + + mPostVersions.erase(it2) ; // it2 is never equal to it + } + } + } + } + + + // Now remove from msg ids, all posts except the most recent one. And make the mPostVersion be indexed by the most recent version of the post, + // which corresponds to the item in the tree widget. + +#ifdef DEBUG_FORUMS + std::cerr << "Final post versions: " << std::endl; +#endif + QMap > > mTmp; + std::map most_recent_versions ; + + for(QMap > >::iterator it(mPostVersions.begin());it!=mPostVersions.end();++it) + { +#ifdef DEBUG_FORUMS + std::cerr << "Original post: " << it.key() << std::endl; +#endif + // Finally, sort the posts from newer to older + + qSort((*it).begin(),(*it).end(),decreasing_time_comp) ; + +#ifdef DEBUG_FORUMS + std::cerr << " most recent version " << (*it)[0].first << " " << (*it)[0].second << std::endl; +#endif + for(int32_t i=1;i<(*it).size();++i) + { + msgs.erase((*it)[i].second) ; + +#ifdef DEBUG_FORUMS + std::cerr << " older version " << (*it)[i].first << " " << (*it)[i].second << std::endl; +#endif + } + + mTmp[(*it)[0].second] = *it ; // index the versions map by the ID of the most recent post. + + // Now make sure that message parents are consistent. Indeed, an old post may have the old version of a post as parent. So we need to change that parent + // to the newest version. So we create a map of which is the most recent version of each message, so that parent messages can be searched in it. + + for(int i=1;i<(*it).size();++i) + most_recent_versions[(*it)[i].second] = (*it)[0].second ; + } + mPostVersions = mTmp ; + + // The next step is to find the top level thread messages. These are defined as the messages without + // any parent message ID. + + // this trick is needed because while we remove messages, the parents a given msg may already have been removed + // and wrongly understand as a missing parent. + + std::map kept_msgs; + + for ( std::map::iterator msgIt = msgs.begin(); msgIt != msgs.end();++msgIt) + { + + if(mFlatView || msgIt->second.mMeta.mParentId.isNull()) + { + + /* add all threads */ + const RsGxsForumMsg& msg = msgIt->second; + +#ifdef DEBUG_FORUMS + std::cerr << "GxsForumsFillThread::run() Adding TopLevel Thread: mId: " << msg.mMeta.mMsgId << std::endl; +#endif + + ForumModelPostEntry entry; + convertMsgToThreadWidget(msg, mUseChildTS, mFilterColumn,NULL,entry); + + ForumModelIndex entry_index = addEntry(posts,entry,0); + + if (!mFlatView) + threadStack.push_back(std::make_pair(msg.mMeta.mMsgId,entry_index)) ; + + //calculateExpand(msg, item); + //mItems.append(entry_index); + } + else + { +#ifdef DEBUG_FORUMS + std::cerr << "GxsForumsFillThread::run() Storing kid " << msgIt->first << " of message " << msgIt->second.mMeta.mParentId << std::endl; +#endif + // The same missing parent may appear multiple times, so we first store them into a unique container. + + RsGxsMessageId parent_msg = msgIt->second.mMeta.mParentId; + + if(msgs.find(parent_msg) == msgs.end()) + { + // also check that the message is not versionned + + std::map::const_iterator mrit = most_recent_versions.find(parent_msg) ; + + if(mrit != most_recent_versions.end()) + parent_msg = mrit->second ; + else + missing_parents.insert(parent_msg); + } + + kids_array[parent_msg].push_back(msgIt->first) ; + kept_msgs.insert(*msgIt) ; + } + } + + msgs = kept_msgs; + + // Also create a list of posts by time, when they are new versions of existing posts. Only the last one will have an item created. + + // Add a fake toplevel item for the parent IDs that we dont actually have. + + for(std::set::const_iterator it(missing_parents.begin());it!=missing_parents.end();++it) + { + // add dummy parent item + ForumModelPostEntry e ; + generateMissingItem(RsGxsMessageId,e); + + ForumModelIndex e_index = addEntry(posts,e,0); // no parent -> parent is level 0 + //mItems.append( e_index ); + + threadStack.push_back(std::make_pair(*it,e_index)) ; + } +#ifdef DEBUG_FORUMS + std::cerr << "GxsForumsFillThread::run() Processing stack:" << std::endl; +#endif + // Now use a stack to go down the hierarchy + + while (!threadStack.empty()) + { + std::pair threadPair = threadStack.front(); + threadStack.pop_front(); + + std::map >::iterator it = kids_array.find(threadPair.first) ; + +#ifdef DEBUG_FORUMS + std::cerr << "GxsForumsFillThread::run() Node: " << threadPair.first << std::endl; +#endif + if(it == kids_array.end()) + continue ; + + + for(std::list::const_iterator it2(it->second.begin());it2!=it->second.end();++it2) + { + // We iterate through the top level thread items, and look for which message has the current item as parent. + // When found, the item is put in the thread list itself, as a potential new parent. + + std::map::iterator mit = msgs.find(*it2) ; + + if(mit == msgs.end()) + { + std::cerr << "GxsForumsFillThread::run() Cannot find submessage " << *it2 << " !!!" << std::endl; + continue ; + } + + const RsGxsForumMsg& msg(mit->second) ; +#ifdef DEBUG_FORUMS + std::cerr << "GxsForumsFillThread::run() adding sub_item " << msg.mMeta.mMsgId << std::endl; +#endif + + + ForumModelPostEntry e ; + convertMsgToPostEntry(forum_group,msg,mUseChildTS,mFilterColumn,e) ; + ForumModelIndex e_index = addEntry(posts,e, threadPair.second); + + //calculateExpand(msg, item); + + /* add item to process list */ + threadStack.push_back(std::make_pair(msg.mMeta.mMsgId, e_index)); + + msgs.erase(mit); + } + +#ifdef DEBUG_FORUMS + std::cerr << "GxsForumsFillThread::run() Erasing entry " << it->first << " from kids tab." << std::endl; +#endif + kids_array.erase(it) ; // This is not strictly needed, but it improves performance by reducing the search space. + } + +#ifdef DEBUG_FORUMS + std::cerr << "Kids array now has " << kids_array.size() << " elements" << std::endl; + for(std::map >::const_iterator it(kids_array.begin());it!=kids_array.end();++it) + { + std::cerr << "Node " << it->first << std::endl; + for(std::list::const_iterator it2(it->second.begin());it2!=it->second.end();++it2) + std::cerr << " " << *it2 << std::endl; + } + + std::cerr << "GxsForumsFillThread::run() stopped: " << (wasStopped() ? "yes" : "no") << std::endl; +#endif +} + + + + diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index 384367097..2de026f1f 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -1,5 +1,4 @@ #ifndef SUSPENDED_CODE -#include "retroshare/rsgxsifacetypes.h" #else #include #include @@ -14,6 +13,8 @@ struct RsMsgMetaData #endif +#include "retroshare/rsgxsforums.h" +#include "retroshare/rsgxsifacetypes.h" #include // This class holds the actual hierarchy of posts, represented by identifiers @@ -38,8 +39,7 @@ struct ForumModelPostEntry uint32_t mPublishTs; uint32_t mPostFlags; int mReputationWarningLevel; - - std::vector meta_versions; // maybe we don't need all this. Could be too large. + int mStatus; std::vector mChildren; ForumModelIndex mParent; @@ -62,6 +62,9 @@ public: StatusRole = Qt::UserRole+4, }; + // This method will asynchroneously update the data + void setForum(const RsGxsGroupId& forumGroup); + int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; @@ -73,12 +76,16 @@ public: QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - QVariant sizeHintRole(int col) const; - QVariant displayRole(const RsMsgMetaData& meta, int col) const; - QVariant userRole(const RsMsgMetaData& meta, int col) const; - QVariant decorationRole(const RsMsgMetaData &meta, int col) const; - - void update_posts(); + QVariant sizeHintRole (int col) const; + QVariant displayRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant userRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant decorationRole(const ForumModelPostEntry& fmpe, int col) const; + QVariant toolTipRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant pinnedRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant missingRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant statusRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant authorRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant sortRole (const ForumModelPostEntry& fmpe, int col) const; private: void *getParentRef(void *ref,int& row) const; @@ -89,5 +96,15 @@ private: static bool convertTabEntryToRefPointer(uint32_t entry,void *& ref); static bool convertRefPointerToTabEntry(void *ref,uint32_t& entry); + void update_posts(const RsGxsGroupId &group_id); + void setForumMessageSummary(const std::vector& messages); + + static void computeMessagesHierarchy(const RsGxsForumGroup& forum_group,const std::vector& msgs_array,std::vector& posts); + static void generateMissingItem(const RsGxsMessageId &msgId,ForumModelPostEntry& entry); + static ForumModelIndex addEntry(std::vector& posts,const ForumModelPostEntry& entry,ForumModelIndex parent); + static void convertMsgToPostEntry(const RsGxsForumGroup &mForumGroup, const RsGxsForumMsg& msg, bool useChildTS, uint32_t filterColumn, ForumModelPostEntry& fentry); + + void setPosts(const std::vector& posts); + std::vector mPosts ; // store the list of posts updated from rsForums. }; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 48609a9c0..34f74cb2c 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -1428,19 +1428,6 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum } -QTreeWidgetItem *GxsForumThreadWidget::generateMissingItem(const RsGxsMessageId &msgId) -{ - GxsIdRSTreeWidgetItem *item = new GxsIdRSTreeWidgetItem(mThreadCompareRole,GxsIdDetails::ICON_TYPE_AVATAR); - - item->setText(COLUMN_THREAD_TITLE, tr("[ ... Missing Message ... ]")); - item->setData(COLUMN_THREAD_MSGID,Qt::DisplayRole, QString::fromStdString(msgId.toStdString())); - item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_MISSING, true); - - item->setId(RsGxsId(), COLUMN_THREAD_AUTHOR, false); // fixed up columnId() - - return item; -} - void GxsForumThreadWidget::insertThreads() { #ifdef DEBUG_FORUMS diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp index f0c61d877..d0bd5ea26 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp @@ -554,75 +554,4 @@ void GxsForumsFillThread::run() deleteLater(); } -QTreeWidgetItem *GxsForumsFillThread::convertMsgToThreadWidget(const RsGxsForumMsg& msg, bool useChildTS, uint32_t filterColumn, ForumModelIndex parent) -{ - ForumModelPostEntry fentry; - fentry.mMsgId = msg.mMeta.mMsgId; - fentry.mPublishTs = msg.mMeta.mPublishTs; - fentry.mParent = parent; - - if(mForumGroup.mPinnedPosts.ids.find(msg.mMeta.mMsgId) != mForumGroup.mPinnedPosts.ids.end()) - fentry.mFlags |= ForumModelPostEntry::FLAG_POST_IS_PINNED; - - // Early check for a message that should be hidden because its author - // is flagged with a bad reputation - - uint32_t idflags =0; - RsReputations::ReputationLevel reputation_level = rsReputations->overallReputationLevel(msg.mMeta.mAuthorId,&idflags) ; - bool redacted = false; - - if(reputation_level == RsReputations::REPUTATION_LOCALLY_NEGATIVE) - fentry.mPostFlags |= ForumModelPostEntry::FLAG_POST_IS_REDACTED; - - // We use a specific item model for forums in order to handle the post pinning. - - if(reputation_level == RsReputations::REPUTATION_UNKNOWN) - fentry.mReputationWarningLevel = 3 ; - else if(reputation_level == RsReputations::REPUTATION_LOCALLY_NEGATIVE) - fentry.mReputationWarningLevel = 2 ; - else if(reputation_level < rsGxsForums->minReputationForForwardingMessages(mForumGroup.mMeta.mSignFlags,idflags)) - fentry.mReputationWarningLevel = 1 ; - else - fentry.mReputationWarningLevel = 0 ; - -#ifdef TODO - // This is an attempt to put pinned posts on the top. We should rather use a QSortFilterProxyModel here. - QString itemSort = QString::number(msg.mMeta.mPublishTs);//Don't need to format it as for sort. - - if (useChildTS) - { - for(QTreeWidgetItem *grandParent = parent; grandParent!=NULL; grandParent = grandParent->parent()) - { - //Update Parent Child TimeStamp - QString oldTSSort = grandParent->data(COLUMN_THREAD_DATE, ROLE_THREAD_SORT).toString(); - - QString oldCTSSort = oldTSSort.split("|").at(0); - QString oldPTSSort = oldTSSort.contains("|") ? oldTSSort.split(" | ").at(1) : oldCTSSort; -#ifdef SHOW_COMBINED_DATES - QString oldTSText = grandParent->text(COLUMN_THREAD_DATE); - QString oldCTSText = oldTSText.split("|").at(0); - QString oldPTSText = oldTSText.contains("|") ? oldTSText.split(" | ").at(1) : oldCTSText;//If first time parent get only its mPublishTs - #endif - if (oldCTSSort.toDouble() < itemSort.toDouble()) - { -#ifdef SHOW_COMBINED_DATES - grandParent->setText(COLUMN_THREAD_DATE, DateTime::formatDateTime(qtime) + " | " + oldPTSText); -#endif - grandParent->setData(COLUMN_THREAD_DATE, ROLE_THREAD_SORT, itemSort + " | " + oldPTSSort); - } - } - } -#endif -//#TODO -#if 0 - if (IS_GROUP_SUBSCRIBED(subscribeFlags) && !(msginfo.mMsgFlags & RS_DISTRIB_MISSING_MSG)) { - rsGxsForums->getMessageStatus(msginfo.forumId, msginfo.msgId, status); - } else { - // show message as read - status = RSGXS_MSG_STATUS_READ; - } -#endif - if (parent) parent->addChild(item); - return item; -} From e01de33e1a1aabda3f32f98283deb254368ad822 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 22 Nov 2018 09:28:07 +0100 Subject: [PATCH 07/79] fixed compilation in new ForumModel --- .../src/gui/gxsforums/GxsForumModel.cpp | 43 +++++++++++++------ .../src/gui/gxsforums/GxsForumModel.h | 13 ++++-- .../gui/gxsforums/GxsForumThreadWidget.cpp | 5 +++ .../src/gui/gxsforums/GxsForumsFillThread.cpp | 1 - 4 files changed, 43 insertions(+), 19 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 08eb676d8..796d80d6f 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -3,6 +3,7 @@ #include #include "util/qtthreadsutils.h" +#include "util/DateTime.h" #include "GxsForumModel.h" #include "retroshare/rsgxsforums.h" @@ -30,6 +31,10 @@ RsGxsForumModel::RsGxsForumModel(QObject *parent) { mPosts.resize(1); // adds a sentinel item + mFilterColumn=0; + mUseChildTS=false; + mFlatView=false; + // // adds some fake posts to debug // // int N=5 ; @@ -303,7 +308,6 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const { case Qt::DisplayRole: return displayRole (fmpe,index.column()) ; case Qt::DecorationRole: return decorationRole(fmpe,index.column()) ; - case Qt::UserRole: return userRole (fmpe,index.column()) ; case Qt::ToolTipRole: return toolTipRole (fmpe,index.column()) ; case ThreadPinnedRole: return pinnedRole (fmpe,index.column()) ; @@ -377,7 +381,7 @@ QVariant RsGxsForumModel::sizeHintRole(int col) const QVariant RsGxsForumModel::authorRole(const ForumModelPostEntry& fmpe,int column) const { if(column == COLUMN_THREAD_DATA) - return QVariant(QString::fromStdString(msg.mMeta.mAuthorId.toStdString())); + return QVariant(QString::fromStdString(fmpe.mAuthorId.toStdString())); return QVariant(); } @@ -387,6 +391,7 @@ QVariant RsGxsForumModel::sortRole(const ForumModelPostEntry& fmpe,int column) c if(column == COLUMN_THREAD_DATA) return QVariant(QString::number(fmpe.mPublishTs)); // we should probably have leading zeroes here + return QVariant(); } QVariant RsGxsForumModel::displayRole(const ForumModelPostEntry& fmpe,int col) const @@ -405,7 +410,7 @@ QVariant RsGxsForumModel::displayRole(const ForumModelPostEntry& fmpe,int col) c QDateTime qtime; qtime.setTime_t(fmpe.mPublishTs); - return QVariant(QDateTime::formatDateTime(qtime)); + return QVariant(DateTime::formatDateTime(qtime)); } case COLUMN_THREAD_AUTHOR: return QVariant(QString::fromStdString(fmpe.mAuthorId.toStdString())); @@ -434,15 +439,22 @@ QVariant RsGxsForumModel::decorationRole(const ForumModelPostEntry& fmpe,int col return QVariant(); } -void RsGxsForumModel::setForum(const RsGxsGroupId& forumGroup) +void RsGxsForumModel::setForum(const RsGxsGroupId& forum_group_id) { - if(mForumGroupId == forumGroup) + if(mForumGroup.mMeta.mGroupId == forum_group_id) return ; - mPosts.clear(); - mForumGroupId = forumGroup; + // we do not set mForumGroupId yet. We'll do it when the forum data is updated. - update_posts(); + update_posts(forum_group_id); +} + +void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector& posts) +{ + mForumGroup = group; + mPosts = posts; + + emit layoutChanged(); } void RsGxsForumModel::update_posts(const RsGxsGroupId& group_id) @@ -472,12 +484,13 @@ void RsGxsForumModel::update_posts(const RsGxsGroupId& group_id) // 2 - sort the messages into a proper hierarchy std::vector *vect = new std::vector(); + RsGxsForumGroup group = groups[0]; - computeMessagesHierarchy(groups[0],messages,*vect); + computeMessagesHierarchy(group,messages,*vect); // 3 - update the model in the UI thread. - RsQThreadUtils::postToObject( [vect,this]() + RsQThreadUtils::postToObject( [group,vect,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 @@ -485,7 +498,7 @@ void RsGxsForumModel::update_posts(const RsGxsGroupId& group_id) * Qt::QueuedConnection is important! */ - setPosts(*vect) ; + setPosts(group,*vect) ; delete vect; @@ -577,7 +590,9 @@ void RsGxsForumModel::convertMsgToPostEntry(const RsGxsForumGroup& mForumGroup,c static bool decreasing_time_comp(const QPair& e1,const QPair& e2) { return e2.first < e1.first ; } -void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_group,const std::vector& msgs_array,std::vector& posts) +void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_group, + const std::vector& msgs_array, + std::vector& posts) { std::cerr << "updating messages data with " << msgs_array.size() << " messages" << std::endl; @@ -757,7 +772,7 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou #endif ForumModelPostEntry entry; - convertMsgToThreadWidget(msg, mUseChildTS, mFilterColumn,NULL,entry); + convertMsgToPostEntry(forum_group,msg, mUseChildTS, mFilterColumn,entry); ForumModelIndex entry_index = addEntry(posts,entry,0); @@ -803,7 +818,7 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou { // add dummy parent item ForumModelPostEntry e ; - generateMissingItem(RsGxsMessageId,e); + generateMissingItem(*it,e); ForumModelIndex e_index = addEntry(posts,e,0); // no parent -> parent is level 0 //mItems.append( e_index ); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index 2de026f1f..cd45158d9 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -27,7 +27,7 @@ typedef uint32_t ForumModelIndex; struct ForumModelPostEntry { - typedef enum { // flags for display of posts + enum { // flags for display of posts FLAG_POST_IS_PINNED = 0x0001, FLAG_POST_IS_MISSING = 0x0002, FLAG_POST_IS_REDACTED = 0x0004, @@ -78,7 +78,6 @@ public: QVariant sizeHintRole (int col) const; QVariant displayRole (const ForumModelPostEntry& fmpe, int col) const; - QVariant userRole (const ForumModelPostEntry& fmpe, int col) const; QVariant decorationRole(const ForumModelPostEntry& fmpe, int col) const; QVariant toolTipRole (const ForumModelPostEntry& fmpe, int col) const; QVariant pinnedRole (const ForumModelPostEntry& fmpe, int col) const; @@ -88,6 +87,12 @@ public: QVariant sortRole (const ForumModelPostEntry& fmpe, int col) const; private: + RsGxsForumGroup mForumGroup; + + bool mUseChildTS; + bool mFlatView; + int mFilterColumn; + void *getParentRef(void *ref,int& row) const; void *getChildRef(void *ref,int row) const; //bool hasIndex(int row,int column,const QModelIndex& parent)const; @@ -99,12 +104,12 @@ private: void update_posts(const RsGxsGroupId &group_id); void setForumMessageSummary(const std::vector& messages); - static void computeMessagesHierarchy(const RsGxsForumGroup& forum_group,const std::vector& msgs_array,std::vector& posts); static void generateMissingItem(const RsGxsMessageId &msgId,ForumModelPostEntry& entry); static ForumModelIndex addEntry(std::vector& posts,const ForumModelPostEntry& entry,ForumModelIndex parent); static void convertMsgToPostEntry(const RsGxsForumGroup &mForumGroup, const RsGxsForumMsg& msg, bool useChildTS, uint32_t filterColumn, ForumModelPostEntry& fentry); - void setPosts(const std::vector& posts); + void computeMessagesHierarchy(const RsGxsForumGroup& forum_group,const std::vector& msgs_array,std::vector& posts); + void setPosts(const RsGxsForumGroup &group, const std::vector& posts); // this method *must* be called from UI thread. std::vector mPosts ; // store the list of posts updated from rsForums. }; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 34f74cb2c..024054cf5 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -2942,3 +2942,8 @@ void GxsForumThreadWidget::loadRequest(const TokenQueue *queue, const TokenReque GxsMessageFrameWidget::loadRequest(queue, req); } + +QTreeWidgetItem *GxsForumThreadWidget::generateMissingItem(const RsGxsMessageId& mid) +{ +return NULL; +} diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp index d0bd5ea26..faff45f74 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp @@ -554,4 +554,3 @@ void GxsForumsFillThread::run() deleteLater(); } - From b28a76e35b71ccc6c0651eca00ab5749e9e1c98f Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 22 Nov 2018 09:47:58 +0100 Subject: [PATCH 08/79] fixed update of posts list in new ForumModel --- .../gui/gxsforums/GxsForumThreadWidget.cpp | 27 ++++++++++--------- .../src/gui/gxsforums/GxsForumThreadWidget.h | 9 ++++--- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 024054cf5..ec022979b 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -202,7 +202,8 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mThreadCompareRole = new RSTreeWidgetItemCompareRole; mThreadCompareRole->setRole(COLUMN_THREAD_DATE, ROLE_THREAD_SORT); - ui->threadTreeWidget->setModel(new RsGxsForumModel(this)); + mThreadModel = new RsGxsForumModel(this); + ui->threadTreeWidget->setModel(mThreadModel); ui->threadTreeWidget->setItemDelegateForColumn(COLUMN_THREAD_DISTRIBUTION,new DistributionItemDelegate()) ; connect(ui->versions_CB, SIGNAL(currentIndexChanged(int)), this, SLOT(changedVersion())); @@ -395,7 +396,8 @@ void GxsForumThreadWidget::groupIdChanged() emit groupChanged(this); - fillComplete(); + mThreadModel->setForum(groupId()); + //fillComplete(); } QString GxsForumThreadWidget::groupName(bool withUnreadCount) @@ -474,7 +476,7 @@ void GxsForumThreadWidget::updateDisplay(bool complete) if (complete) { /* Fill complete */ requestGroupData(); - insertThreads(); + //insertThreads(); insertMessage(); mIgnoredMsgId.clear(); @@ -492,7 +494,7 @@ void GxsForumThreadWidget::updateDisplay(bool complete) if (grpIds.find(groupId())!=grpIds.end()){ updateGroup = true; /* Update threads */ - insertThreads(); + //insertThreads(); } else { std::map > msgIds; getAllMsgIds(msgIds); @@ -504,7 +506,7 @@ void GxsForumThreadWidget::updateDisplay(bool complete) if (msgIds.find(groupId()) != msgIds.end()) { /* Update threads */ - insertThreads(); + //insertThreads(); } } @@ -1427,7 +1429,7 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum return item; } - +#ifdef TO_REMOVE void GxsForumThreadWidget::insertThreads() { #ifdef DEBUG_FORUMS @@ -1502,9 +1504,9 @@ void GxsForumThreadWidget::insertThreads() ui->threadTreeWidget->setRootIsDecorated(!mFillThread->mFlatView); // connect thread - connect(mFillThread, SIGNAL(finished()), this, SLOT(fillThreadFinished()), Qt::BlockingQueuedConnection); - connect(mFillThread, SIGNAL(status(QString)), this, SLOT(fillThreadStatus(QString))); - connect(mFillThread, SIGNAL(progress(int,int)), this, SLOT(fillThreadProgress(int,int))); + // connect(mFillThread, SIGNAL(finished()), this, SLOT(fillThreadFinished()), Qt::BlockingQueuedConnection); + // connect(mFillThread, SIGNAL(status(QString)), this, SLOT(fillThreadStatus(QString))); + // connect(mFillThread, SIGNAL(progress(int,int)), this, SLOT(fillThreadProgress(int,int))); #ifdef DEBUG_FORUMS std::cerr << "ForumsDialog::insertThreads() Start fill thread" << std::endl; @@ -1535,7 +1537,6 @@ static void copyItem(QTreeWidgetItem *item, const QTreeWidgetItem *newItem) void GxsForumThreadWidget::fillThreads(QList &threadList, bool expandNewMessages, QList &itemToExpand) { -#ifdef TODO #ifdef DEBUG_FORUMS std::cerr << "GxsForumThreadWidget::fillThreads()" << std::endl; #endif @@ -1607,9 +1608,10 @@ void GxsForumThreadWidget::fillThreads(QList &threadList, boo #ifdef DEBUG_FORUMS std::cerr << "GxsForumThreadWidget::fillThreads() done" << std::endl; #endif -#endif } +#endif +#ifdef TO_REMOVE void GxsForumThreadWidget::fillChildren(QTreeWidgetItem *parentItem, QTreeWidgetItem *newParentItem, bool expandNewMessages, QList &itemToExpand) { int index = 0; @@ -1673,6 +1675,7 @@ void GxsForumThreadWidget::fillChildren(QTreeWidgetItem *parentItem, QTreeWidget } } } +#endif void GxsForumThreadWidget::insertMessage() { @@ -2487,7 +2490,7 @@ void GxsForumThreadWidget::filterColumnChanged(int column) if (column == COLUMN_THREAD_CONTENT) { // need content ... refill - insertThreads(); + //insertThreads(); } else { filterItems(ui->filterLineEdit->text()); } diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 40aa469cb..a3d227431 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -32,6 +32,7 @@ class RSTreeWidgetItemCompareRole; class RsGxsForumMsg; class GxsForumsFillThread; class RsGxsForumGroup; +class RsGxsForumModel; namespace Ui { class GxsForumThreadWidget; @@ -149,11 +150,11 @@ private slots: private: void insertMessageData(const RsGxsForumMsg &msg); - void insertThreads(); void insertMessage(); - void fillThreads(QList &threadList, bool expandNewMessages, QList &itemToExpand); - void fillChildren(QTreeWidgetItem *parentItem, QTreeWidgetItem *newParentItem, bool expandNewMessages, QList &itemToExpand); + //void insertThreads(); + //void fillThreads(QList &threadList, bool expandNewMessages, QList &itemToExpand); + //void fillChildren(QTreeWidgetItem *parentItem, QTreeWidgetItem *newParentItem, bool expandNewMessages, QList &itemToExpand); int getSelectedMsgCount(QList *pRows, QList *pRowsRead, QList *pRowsUnread); void setMsgReadStatus(QList &rows, bool read); @@ -225,6 +226,8 @@ private: QMap > > mPostVersions ; // holds older versions of posts + RsGxsForumModel *mThreadModel; + Ui::GxsForumThreadWidget *ui; }; From 59220b5c856066e7a1acda144f95216f207cd1e4 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 22 Nov 2018 10:44:06 +0100 Subject: [PATCH 09/79] fixed layout of internal data in ForumModel --- .../src/gui/gxsforums/GxsForumModel.cpp | 65 ++++++++++++++++++- .../src/gui/gxsforums/GxsForumModel.h | 8 +++ 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 796d80d6f..c077bea6c 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -7,7 +7,7 @@ #include "GxsForumModel.h" #include "retroshare/rsgxsforums.h" -#define DEBUG_FORUMMODEL +//#define DEBUG_FORUMMODEL #define COLUMN_THREAD_TITLE 0 #define COLUMN_THREAD_READ 1 @@ -29,7 +29,8 @@ std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsew RsGxsForumModel::RsGxsForumModel(QObject *parent) : QAbstractItemModel(parent) { - mPosts.resize(1); // adds a sentinel item + initEmptyHierarchy(mPosts); + mFilterColumn=0; mUseChildTS=false; @@ -60,6 +61,13 @@ RsGxsForumModel::RsGxsForumModel(QObject *parent) // meta.mMsgName = std::string("message ") + QString::number(N+1).toStdString() ; } +void RsGxsForumModel::initEmptyHierarchy(std::vector& posts) +{ + posts.resize(1); // adds a sentinel item + posts[0].mTitle = "Root sentinel post" ; + posts[0].mParent = 0; +} + int RsGxsForumModel::rowCount(const QModelIndex& parent) const { if(parent.column() > 0) @@ -454,6 +462,16 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector& post posts[N].mParent = parent; posts[parent].mChildren.push_back(N); + std::cerr << "Added new entry " << N << " children of " << parent << std::endl; + + if(N == parent) + std::cerr << "(EE) trying to add a post as its own parent!" << std::endl; return ForumModelIndex(N); } @@ -530,8 +552,11 @@ void RsGxsForumModel::generateMissingItem(const RsGxsMessageId &msgId,ForumModel void RsGxsForumModel::convertMsgToPostEntry(const RsGxsForumGroup& mForumGroup,const RsGxsForumMsg& msg, bool useChildTS, uint32_t filterColumn,ForumModelPostEntry& fentry) { + fentry.mTitle = msg.mMeta.mMsgName; + fentry.mAuthorId = msg.mMeta.mAuthorId; fentry.mMsgId = msg.mMeta.mMsgId; fentry.mPublishTs = msg.mMeta.mPublishTs; + fentry.mPostFlags = 0; fentry.mStatus = msg.mMeta.mMsgStatus; if(mForumGroup.mPinnedPosts.ids.find(msg.mMeta.mMsgId) != mForumGroup.mPinnedPosts.ids.end()) @@ -623,7 +648,7 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou // int steps = count / PROGRESSBAR_MAX; int step = 0; - posts.clear(); + initEmptyHierarchy(posts); QMap > > mPostVersions ; // ThreadList contains the list of parent threads. The algorithm below iterates through all messages @@ -894,6 +919,40 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou #endif } +static void recursPrintModel(const std::vector& entries,ForumModelIndex index,int depth) +{ + const ForumModelPostEntry& e(entries[index]); + + std::cerr << std::string(depth*2,' ') << e.mAuthorId.toStdString() << " " << QString("%1").arg((uint32_t)e.mPostFlags,8,16,QChar('0')).toStdString() + << " " << QDateTime::fromSecsSinceEpoch(e.mPublishTs).toString().toStdString() << " \"" << e.mTitle << "\"" << std::endl; + + for(uint32_t i=0;i& msgs_array,std::vector& posts); void setPosts(const RsGxsForumGroup &group, const std::vector& posts); // this method *must* be called from UI thread. + void initEmptyHierarchy(std::vector& posts); std::vector mPosts ; // store the list of posts updated from rsForums. }; From 3edd1dd0ddce2550360092f56007a1c3eaf13ca6 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 22 Nov 2018 11:24:05 +0100 Subject: [PATCH 10/79] fixed missing case entries in ForumModel --- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index c077bea6c..bb2bffe44 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -256,10 +256,13 @@ QVariant RsGxsForumModel::headerData(int section, Qt::Orientation orientation, i switch(section) { - default: case COLUMN_THREAD_TITLE: return tr("Title"); case COLUMN_THREAD_DATE: return tr("Date"); case COLUMN_THREAD_AUTHOR: return tr("Author"); + case COLUMN_THREAD_DISTRIBUTION: return QString("[icon missing]") ; + case COLUMN_THREAD_READ: return QString("[icon missing]") ; + default: + return QString("[unused]"); } } From 20b8bca8014e3bd1249e836956e15c8d4668be56 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 22 Nov 2018 22:07:58 +0100 Subject: [PATCH 11/79] worked on display of posts and selection in new forum model --- libretroshare/src/retroshare/rsgxsforums.h | 13 ++ libretroshare/src/services/p3gxsforums.cc | 14 ++ libretroshare/src/services/p3gxsforums.h | 3 + .../src/gui/gxsforums/GxsForumModel.cpp | 26 --- .../gui/gxsforums/GxsForumThreadWidget.cpp | 153 +++++++++++++++--- .../src/gui/gxsforums/GxsForumThreadWidget.h | 10 +- 6 files changed, 166 insertions(+), 53 deletions(-) diff --git a/libretroshare/src/retroshare/rsgxsforums.h b/libretroshare/src/retroshare/rsgxsforums.h index 4c6b6e483..ad73a92c2 100644 --- a/libretroshare/src/retroshare/rsgxsforums.h +++ b/libretroshare/src/retroshare/rsgxsforums.h @@ -150,6 +150,19 @@ public: const std::list& forumIds, std::vector& messages ) = 0; + /** + * @brief Get specific list of messages from a single forums. Blocking API + * @jsonapi{development} + * @param[in] forumId id of the forum of which the content is requested + * @param[in] msgs_to_request list of message ids to request + * @param[out] msgs storage for the forum messages + * @return false if something failed, true otherwhise + */ + virtual bool getForumsContent( + const RsGxsGroupId& forumId, + std::set& msgs_to_request, + std::vector& msgs) =0; + /** * @brief Toggle message read status. Blocking API. * @jsonapi{development} diff --git a/libretroshare/src/services/p3gxsforums.cc b/libretroshare/src/services/p3gxsforums.cc index 09680f196..4541f00b7 100644 --- a/libretroshare/src/services/p3gxsforums.cc +++ b/libretroshare/src/services/p3gxsforums.cc @@ -456,6 +456,20 @@ bool p3GxsForums::getForumsInfo( return getGroupData(token, forumsInfo); } +bool p3GxsForums::getForumsContent( const RsGxsGroupId& forumId, std::set& msgs_to_request,std::vector& msgs) +{ + uint32_t token; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; + + GxsMsgReq msgIds; + msgIds[forumId] = msgs_to_request; + + if( !requestMsgInfo(token, opts, msgIds) || waitToken(token) != RsTokenService::COMPLETE ) return false; + + return getMsgData(token, msgs) ; +} + bool p3GxsForums::getForumsContent( const std::list& forumIds, std::vector& messages ) diff --git a/libretroshare/src/services/p3gxsforums.h b/libretroshare/src/services/p3gxsforums.h index 36b40a972..29260c8cf 100644 --- a/libretroshare/src/services/p3gxsforums.h +++ b/libretroshare/src/services/p3gxsforums.h @@ -77,6 +77,9 @@ public: const std::list& forumIds, std::vector& messages ); + /// @see RsGxsForums::getForumsContent + virtual bool getForumsContent( const RsGxsGroupId& forumId, std::set& msgs_to_request,std::vector& msgs) ; + /// @see RsGxsForums::markRead virtual bool markRead(const RsGxsGrpMsgIdPair& messageId, bool read); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index bb2bffe44..13d9fc2a3 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -223,32 +223,6 @@ int RsGxsForumModel::getChildrenCount(void *ref) const return mPosts[entry].mChildren.size(); } - - -//bool RsGxsForumModel::hasIndex(int row,int column,const QModelIndex& parent) const -//{ -// if(row < 0 || column < 0 || column >= COLUMN_COUNT) -// return false; -// -// if(!parent.isValid()) -// return false; -// -// ForumModelIndex entry; -// -// convertRefPointerToTabEntry(parent.internalPointer(),entry); -// -// if(entry >= mPosts.size()) -// return false; -// -// if(row >= mPosts[entry].children.size()) -// return false; -// -// if(mPosts[entry].children[row] >= mPosts.size()) -// return false; -// -// return true; -//} - QVariant RsGxsForumModel::headerData(int section, Qt::Orientation orientation, int role) const { if(role != Qt::DisplayRole) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index ec022979b..fed5854d5 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -24,6 +24,7 @@ #include #include +#include "util/qtthreadsutils.h" #include "GxsForumThreadWidget.h" #include "ui_GxsForumThreadWidget.h" #include "GxsForumsFillThread.h" @@ -475,7 +476,7 @@ void GxsForumThreadWidget::updateDisplay(bool complete) { if (complete) { /* Fill complete */ - requestGroupData(); + updateGroupData(); //insertThreads(); insertMessage(); @@ -511,7 +512,7 @@ void GxsForumThreadWidget::updateDisplay(bool complete) } if (updateGroup) { - requestGroupData(); + updateGroupData(); } } @@ -777,25 +778,25 @@ void GxsForumThreadWidget::changedVersion() void GxsForumThreadWidget::changedThread() { -#ifdef TODO /* just grab the ids of the current item */ - QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); + QModelIndexList selected_indexes = ui->threadTreeWidget->selectionModel()->selectedIndexes(); - if (!item || !item->isSelected()) { + if(selected_indexes.size() != 1) + { mThreadId.clear(); mOrigThreadId.clear(); - } else { + return; + } - mThreadId = mOrigThreadId = RsGxsMessageId(item->data(COLUMN_THREAD_MSGID, Qt::DisplayRole).toString().toStdString()); - } + QModelIndex index = *selected_indexes.begin(); - if (mFillThread) { - return; - } - ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages()) ; + mThreadId = mOrigThreadId = RsGxsMessageId(index.sibling(index.row(),COLUMN_THREAD_MSGID).data(Qt::DisplayRole).toString().toStdString()); + + std::cerr << "Switched to new thread ID " << mThreadId << std::endl; + + //ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages()) ; insertMessage(); -#endif } void GxsForumThreadWidget::clickedThread(QTreeWidgetItem *item, int column) @@ -1679,7 +1680,6 @@ void GxsForumThreadWidget::fillChildren(QTreeWidgetItem *parentItem, QTreeWidget void GxsForumThreadWidget::insertMessage() { -#ifdef TODO if (groupId().isNull()) { mStateHelper->setActive(mTokenTypeMessageData, false); @@ -1689,7 +1689,6 @@ void GxsForumThreadWidget::insertMessage() ui->time_label->show(); ui->postText->clear(); - //ui->threadTitle->clear(); return; } @@ -1701,14 +1700,15 @@ void GxsForumThreadWidget::insertMessage() ui->versions_CB->hide(); ui->time_label->show(); - //ui->threadTitle->setText(tr("Forum Description")); ui->postText->setText(mForumDescription); return; } mStateHelper->setActive(mTokenTypeMessageData, true); +#ifdef TODO QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); + if (item) { QTreeWidgetItem *parentItem = item->parent(); int index = parentItem ? parentItem->indexOfChild(item) : ui->threadTreeWidget->indexOfTopLevelItem(item); @@ -1723,6 +1723,7 @@ void GxsForumThreadWidget::insertMessage() ui->time_label->show(); return; } +#endif mStateHelper->setWidgetEnabled(ui->newmessageButton, (IS_GROUP_SUBSCRIBED(mSubscribeFlags) && mThreadId.isNull() == false)); @@ -1738,7 +1739,7 @@ void GxsForumThreadWidget::insertMessage() // add/show combobox for versions, if applicable, and enable it. If no older versions of the post available, hide the combobox. std::cerr << "Looking into existing versions for post " << mThreadId << ", thread history: " << mPostVersions.size() << std::endl; - +#ifdef TODO QMap > >::const_iterator it = mPostVersions.find(mOrigThreadId) ; ui->versions_CB->blockSignals(true) ; @@ -1773,13 +1774,13 @@ void GxsForumThreadWidget::insertMessage() ui->versions_CB->hide(); ui->time_label->show(); } +#endif ui->versions_CB->blockSignals(false) ; /* request Post */ - RsGxsGrpMsgIdPair msgId = std::make_pair(groupId(), mThreadId); - requestMessageData(msgId); -#endif + //RsGxsGrpMsgIdPair msgId = std::make_pair(groupId(), mThreadId); + updateMessageData(mThreadId); } void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) @@ -2542,6 +2543,111 @@ bool GxsForumThreadWidget::filterItem(QTreeWidgetItem *item, const QString &text /** Request / Response of Data ********************************/ /*********************** **** **** **** ***********************/ +void GxsForumThreadWidget::updateGroupData() +{ + mSubscribeFlags = 0; + mSignFlags = 0; + mForumDescription.clear(); + + emit groupChanged(this); + + RsThread::async([this]() + { + // 1 - get message data from p3GxsForums + + std::list forumIds; + std::vector groups; + + forumIds.push_back(groupId()); + + if(!rsGxsForums->getForumsInfo(forumIds,groups)) + { + std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve forum group info for forum " << groupId() << std::endl; + return; + } + + if(groups.size() != 1) + { + mStateHelper->setActive(mTokenTypeGroupData, false); + mStateHelper->clear(mTokenTypeGroupData); + return; + } + + // 2 - sort the messages into a proper hierarchy + + RsGxsForumGroup group = groups[0]; + + // 3 - update the model in the UI thread. + + 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, note that + * Qt::QueuedConnection is important! + */ + + mForumGroup = group; + insertGroupData(); + + ui->threadTreeWidget->setColumnHidden(COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); + ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mSubscribeFlags)) ; + + }, this ); + + }); +} + +void GxsForumThreadWidget::updateMessageData(const RsGxsMessageId& msgId) +{ + RsThread::async([msgId,this]() + { + // 1 - get message data from p3GxsForums + + std::set msgs_to_request ; + std::vector msgs; + + msgs_to_request.insert(msgId); + + if(!rsGxsForums->getForumsContent(groupId(),msgs_to_request,msgs)) + { + std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve forum group info for forum " << groupId() << std::endl; + return; + } + + if(msgs.size() != 1) + { + mStateHelper->setActive(mTokenTypeGroupData, false); + mStateHelper->clear(mTokenTypeGroupData); + return; + } + + // 2 - sort the messages into a proper hierarchy + + RsGxsForumMsg msg = msgs[0]; + + // 3 - update the model in the UI thread. + + 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, note that + * Qt::QueuedConnection is important! + */ + + insertMessageData(msg); + + ui->threadTreeWidget->setColumnHidden(COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); + ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mSubscribeFlags)) ; + + }, this ); + + }); + +} + +#ifdef TO_REMOVE void GxsForumThreadWidget::requestGroupData() { mSubscribeFlags = 0; @@ -2549,19 +2655,17 @@ void GxsForumThreadWidget::requestGroupData() mForumDescription.clear(); mTokenQueue->cancelActiveRequestTokens(mTokenTypeGroupData); + emit groupChanged(this); if (groupId().isNull()) { mStateHelper->setActive(mTokenTypeGroupData, false); mStateHelper->setLoading(mTokenTypeGroupData, false); mStateHelper->clear(mTokenTypeGroupData); - emit groupChanged(this); - return; } mStateHelper->setLoading(mTokenTypeGroupData, true); - emit groupChanged(this); RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; @@ -2666,6 +2770,7 @@ void GxsForumThreadWidget::loadMessageData(const uint32_t &token) mStateHelper->clear(mTokenTypeMessageData); } } +#endif /*********************** **** **** **** ***********************/ /*********************** **** **** **** ***********************/ @@ -2897,6 +3002,7 @@ void GxsForumThreadWidget::loadRequest(const TokenQueue *queue, const TokenReque if (queue == mTokenQueue) { +#ifdef TO_REMOVE /* now switch on req */ if (req.mUserType == mTokenTypeGroupData) { loadGroupData(req.mToken); @@ -2907,6 +3013,7 @@ void GxsForumThreadWidget::loadRequest(const TokenQueue *queue, const TokenReque loadMessageData(req.mToken); return; } +#endif if (req.mUserType == mTokenTypeReplyMessage) { loadMsgData_ReplyMessage(req.mToken); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index a3d227431..f2bec6933 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -151,6 +151,7 @@ private: void insertMessageData(const RsGxsForumMsg &msg); void insertMessage(); + void insertGroupData(); //void insertThreads(); //void fillThreads(QList &threadList, bool expandNewMessages, QList &itemToExpand); @@ -169,18 +170,19 @@ private: void processSettings(bool bLoad); - void requestGroupData(); - void loadGroupData(const uint32_t &token); - void insertGroupData(); + void updateGroupData(); static void loadAuthorIdCallback(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &/*data*/); - void requestMessageData(const RsGxsGrpMsgIdPair &msgId); + void updateMessageData(const RsGxsMessageId& msgId); + void requestMsgData_ReplyWithPrivateMessage(const RsGxsGrpMsgIdPair &msgId); void requestMsgData_ShowAuthorInPeople(const RsGxsGrpMsgIdPair &msgId); void requestMsgData_ReplyForumMessage(const RsGxsGrpMsgIdPair &msgId); void requestMsgData_EditForumMessage(const RsGxsGrpMsgIdPair &msgId); +#ifdef TO_REMOVE void loadMessageData(const uint32_t &token); +#endif void loadMsgData_ReplyMessage(const uint32_t &token); void loadMsgData_ReplyForumMessage(const uint32_t &token); void loadMsgData_EditForumMessage(const uint32_t &token); From 543a7f280d2a3dd988c7a30fba42a1e358d2883c Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 22 Nov 2018 22:52:27 +0100 Subject: [PATCH 12/79] fixed display of current post in new Forum Model --- .../src/gui/gxsforums/GxsForumModel.cpp | 6 ++--- .../gui/gxsforums/GxsForumThreadWidget.cpp | 24 +++++++++---------- .../src/gui/gxsforums/GxsForumThreadWidget.h | 2 +- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 13d9fc2a3..c5d300816 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -83,7 +83,7 @@ int RsGxsForumModel::rowCount(const QModelIndex& parent) const } int RsGxsForumModel::columnCount(const QModelIndex &parent) const { - return COLUMN_THREAD_COUNT ; + return COLUMN_THREAD_NB_COLUMNS ; } bool RsGxsForumModel::hasChildren(const QModelIndex &parent) const @@ -139,7 +139,7 @@ bool RsGxsForumModel::convertRefPointerToTabEntry(void *ref,uint32_t& entry) QModelIndex RsGxsForumModel::index(int row, int column, const QModelIndex & parent) const { // if(!hasIndex(row,column,parent)) - if(row < 0 || column < 0 || column >= COLUMN_THREAD_COUNT) + if(row < 0 || column < 0 || column >= COLUMN_THREAD_NB_COLUMNS) return QModelIndex(); void *ref = getChildRef(parent.internalPointer(),row); @@ -918,7 +918,7 @@ void RsGxsForumModel::debug_dump() { const ForumModelPostEntry& e(mPosts[i]); - std::cerr << " " << i << " : " << e.mAuthorId.toStdString() << " " << QString("%1").arg((uint32_t)e.mPostFlags,8,16,QChar('0')).toStdString(); + std::cerr << " " << i << " : " << e.mMsgId << " (from " << e.mAuthorId.toStdString() << ") " << QString("%1").arg((uint32_t)e.mPostFlags,8,16,QChar('0')).toStdString(); for(uint32_t i=0;inewmessageButton->setText(tr("Reply")); ui->newthreadButton->setText(tr("New thread")); - connect(ui->threadTreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(changedThread())); + connect(ui->threadTreeWidget, SIGNAL(clicked(QModelIndex)), this, SLOT(changedThread(QModelIndex))); connect(ui->threadTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(clickedThread(QTreeWidgetItem*,int))); connect(ui->viewBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changedViewBox())); @@ -776,21 +776,16 @@ void GxsForumThreadWidget::changedVersion() insertMessage(); } -void GxsForumThreadWidget::changedThread() +void GxsForumThreadWidget::changedThread(QModelIndex index) { - /* just grab the ids of the current item */ - QModelIndexList selected_indexes = ui->threadTreeWidget->selectionModel()->selectedIndexes(); - - if(selected_indexes.size() != 1) + if(!index.isValid()) { mThreadId.clear(); mOrigThreadId.clear(); return; } - QModelIndex index = *selected_indexes.begin(); - - mThreadId = mOrigThreadId = RsGxsMessageId(index.sibling(index.row(),COLUMN_THREAD_MSGID).data(Qt::DisplayRole).toString().toStdString()); + mThreadId = mOrigThreadId = RsGxsMessageId(mThreadModel->data(index.sibling(index.row(),COLUMN_THREAD_MSGID),Qt::DisplayRole).toString().toStdString()); std::cerr << "Switched to new thread ID " << mThreadId << std::endl; @@ -1785,7 +1780,6 @@ void GxsForumThreadWidget::insertMessage() void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) { -#ifdef TODO /* As some time has elapsed since request - check that this is still the current msg. * otherwise, another request will fill the data */ @@ -1811,11 +1805,13 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) mStateHelper->setActive(mTokenTypeMessageData, true); - QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); + //mThreadId = mOrigThreadId = RsGxsMessageId(mThreadModel->data(index.sibling(index.row(),COLUMN_THREAD_MSGID),Qt::DisplayRole).toString().toStdString()); + //QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); bool setToReadOnActive = Settings->getForumMsgSetToReadOnActivate(); - uint32_t status = item->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); + uint32_t status = msg.mMeta.mMsgStatus ;//item->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); +#ifdef TODO QList row; row.append(item); @@ -1833,6 +1829,7 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) setMsgReadStatus(row, true); } } +#endif ui->time_label->setText(DateTime::formatLongDateTime(msg.mMeta.mPublishTs)); ui->by_label->setId(msg.mMeta.mAuthorId); @@ -1860,7 +1857,6 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) ui->postText->setHtml(extraTxt); } // ui->threadTitle->setText(QString::fromUtf8(msg.mMeta.mMsgName.c_str())); -#endif } void GxsForumThreadWidget::previousMessage() @@ -2604,6 +2600,8 @@ void GxsForumThreadWidget::updateMessageData(const RsGxsMessageId& msgId) { // 1 - get message data from p3GxsForums + std::cerr << "Retrieving post data for post " << msgId << std::endl; + std::set msgs_to_request ; std::vector msgs; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index f2bec6933..89ec7b9d9 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -96,7 +96,7 @@ private slots: void threadListCustomPopupMenu(QPoint point); void contextMenuTextBrowser(QPoint point); - void changedThread(); + void changedThread(QModelIndex index); void changedVersion(); void clickedThread (QTreeWidgetItem *item, int column); From 52a5aeb1f8c448f7ba4bd39be9134fae836fe214 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 23 Nov 2018 23:17:12 +0100 Subject: [PATCH 13/79] added item delegate for author in new model --- retroshare-gui/src/gui/gxs/GxsIdDetails.cpp | 4 +- retroshare-gui/src/gui/gxs/GxsIdDetails.h | 2 +- .../gui/gxsforums/GxsForumThreadWidget.cpp | 44 +++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp index 939b81708..16399aed1 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp @@ -897,7 +897,7 @@ QIcon GxsIdDetails::getLoadingIcon(const RsGxsId &/*id*/) return QIcon(IMAGE_LOADING); } -bool GxsIdDetails::MakeIdDesc(const RsGxsId &id, bool doIcons, QString &str, QList &icons, QString& comment) +bool GxsIdDetails::MakeIdDesc(const RsGxsId &id, bool doIcons, QString &str, QList &icons, QString& comment,uint32_t icon_types) { RsIdentityDetails details; @@ -921,7 +921,7 @@ bool GxsIdDetails::MakeIdDesc(const RsGxsId &id, bool doIcons, QString &str, QLi comment += getComment(details); if (doIcons) - getIcons(details, icons); + getIcons(details, icons,icon_types); // Cyril: I disabled these three which I believe to have been put for testing purposes. // diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.h b/retroshare-gui/src/gui/gxs/GxsIdDetails.h index 6a48d73c5..30edffd7e 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.h +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.h @@ -76,7 +76,7 @@ public: static void cleanup(); /* Information */ - static bool MakeIdDesc(const RsGxsId &id, bool doIcons, QString &desc, QList &icons, QString& comment); + static bool MakeIdDesc(const RsGxsId &id, bool doIcons, QString &desc, QList &icons, QString& comment, uint32_t icon_types=ICON_TYPE_ALL); static QString getName(const RsIdentityDetails &details); static QString getComment(const RsIdentityDetails &details); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 7c51e06e4..778804102 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -149,6 +149,49 @@ public: } }; +class AuthorItemDelegate: public QStyledItemDelegate +{ +public: + AuthorItemDelegate() {} + + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const + { + if(!index.isValid()) + { + std::cerr << "(EE) attempt to draw an invalid index." << std::endl; + return ; + } + + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + + // disable default icon + opt.icon = QIcon(); + // draw default item + QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, 0); + + const QRect r = option.rect; + + RsGxsId id(index.data(Qt::DisplayRole).toString().toStdString()); + QString str; + QList icons; + QString comment; + + QIcon icon ; + + if(!GxsIdDetails::MakeIdDesc(id, true, str, icons, comment,GxsIdDetails::ICON_TYPE_AVATAR)) + icon = GxsIdDetails::getLoadingIcon(id); + else + icon = *icons.begin(); + + QPixmap pix = icon.pixmap(r.size()); + + // draw pixmap at center of item + const QPoint p = QPoint((r.width() - pix.width())/2, (r.height() - pix.height())/2); + painter->drawPixmap(r.topLeft() + p, pix); + } +}; + GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget *parent) : GxsMessageFrameWidget(rsGxsForums, parent), ui(new Ui::GxsForumThreadWidget) @@ -206,6 +249,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mThreadModel = new RsGxsForumModel(this); ui->threadTreeWidget->setModel(mThreadModel); ui->threadTreeWidget->setItemDelegateForColumn(COLUMN_THREAD_DISTRIBUTION,new DistributionItemDelegate()) ; + ui->threadTreeWidget->setItemDelegateForColumn(COLUMN_THREAD_AUTHOR,new AuthorItemDelegate()) ; connect(ui->versions_CB, SIGNAL(currentIndexChanged(int)), this, SLOT(changedVersion())); connect(ui->threadTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(threadListCustomPopupMenu(QPoint))); From c2686d1a9477da81cf074be5f4766aab7d786c7f Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 24 Nov 2018 16:11:40 +0100 Subject: [PATCH 14/79] fixed display of author in new ForumModel --- .../src/gui/gxsforums/GxsForumModel.cpp | 41 +++++++++--- .../src/gui/gxsforums/GxsForumModel.h | 6 +- .../gui/gxsforums/GxsForumThreadWidget.cpp | 67 +++++++++++++++---- 3 files changed, 89 insertions(+), 25 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index c5d300816..dc098a09f 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -5,6 +5,7 @@ #include "util/qtthreadsutils.h" #include "util/DateTime.h" #include "GxsForumModel.h" +#include "retroshare/rsgxsflags.h" #include "retroshare/rsgxsforums.h" //#define DEBUG_FORUMMODEL @@ -14,11 +15,9 @@ #define COLUMN_THREAD_DATE 2 #define COLUMN_THREAD_DISTRIBUTION 3 #define COLUMN_THREAD_AUTHOR 4 -#define COLUMN_THREAD_SIGNED 5 -#define COLUMN_THREAD_CONTENT 6 -#define COLUMN_THREAD_COUNT 7 -#define COLUMN_THREAD_MSGID 8 -#define COLUMN_THREAD_NB_COLUMNS 9 +#define COLUMN_THREAD_CONTENT 5 +#define COLUMN_THREAD_MSGID 6 +#define COLUMN_THREAD_NB_COLUMNS 7 #define COLUMN_THREAD_DATA 0 // column for storing the userdata like parentid @@ -252,6 +251,7 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const switch(role) { case Qt::SizeHintRole: return sizeHintRole(index.column()) ; + case Qt::FontRole: case Qt::TextAlignmentRole: case Qt::TextColorRole: case Qt::WhatsThisRole: @@ -285,6 +285,14 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const const ForumModelPostEntry& fmpe(mPosts[entry]); + if(role == Qt::FontRole) + { + QFont font ; + + font.setBold(IS_MSG_UNREAD(fmpe.mMsgStatus)); + + return QVariant(font); + } #ifdef DEBUG_FORUMMODEL std::cerr << " [ok]" << std::endl; #endif @@ -294,6 +302,7 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: return displayRole (fmpe,index.column()) ; case Qt::DecorationRole: return decorationRole(fmpe,index.column()) ; case Qt::ToolTipRole: return toolTipRole (fmpe,index.column()) ; + case Qt::UserRole: return userRole (fmpe,index.column()) ; case ThreadPinnedRole: return pinnedRole (fmpe,index.column()) ; case MissingRole: return missingRole (fmpe,index.column()) ; @@ -308,7 +317,7 @@ QVariant RsGxsForumModel::statusRole(const ForumModelPostEntry& fmpe,int column) if(column != COLUMN_THREAD_DATA) return QVariant(); - return QVariant(fmpe.mStatus); + return QVariant(fmpe.mMsgStatus); } QVariant RsGxsForumModel::missingRole(const ForumModelPostEntry& fmpe,int column) const @@ -390,7 +399,7 @@ QVariant RsGxsForumModel::displayRole(const ForumModelPostEntry& fmpe,int col) c else return QVariant(QString::fromUtf8(fmpe.mTitle.c_str())); - //case COLUMN_THREAD_READ_STATUS:return QVariant(fmpe.mMsgStatus); + case COLUMN_THREAD_READ:return QVariant(); case COLUMN_THREAD_DATE: { QDateTime qtime; qtime.setTime_t(fmpe.mPublishTs); @@ -398,8 +407,9 @@ QVariant RsGxsForumModel::displayRole(const ForumModelPostEntry& fmpe,int col) c return QVariant(DateTime::formatDateTime(qtime)); } - case COLUMN_THREAD_AUTHOR: return QVariant(QString::fromStdString(fmpe.mAuthorId.toStdString())); - case COLUMN_THREAD_MSGID: return QVariant(QString::fromStdString(fmpe.mMsgId.toStdString())); + case COLUMN_THREAD_DISTRIBUTION: + case COLUMN_THREAD_AUTHOR: return QVariant(); + case COLUMN_THREAD_MSGID: return QVariant(); #ifdef TODO if (filterColumn == COLUMN_THREAD_CONTENT) { // need content for filter @@ -416,6 +426,17 @@ QVariant RsGxsForumModel::displayRole(const ForumModelPostEntry& fmpe,int col) c return QVariant("[ERROR]"); } +QVariant RsGxsForumModel::userRole(const ForumModelPostEntry& fmpe,int col) const +{ + switch(col) + { + case COLUMN_THREAD_AUTHOR: return QVariant(QString::fromStdString(fmpe.mAuthorId.toStdString())); + case COLUMN_THREAD_MSGID: return QVariant(QString::fromStdString(fmpe.mMsgId.toStdString())); + default: + return QVariant(); + } +} + QVariant RsGxsForumModel::decorationRole(const ForumModelPostEntry& fmpe,int col) const { if(col == COLUMN_THREAD_DISTRIBUTION) @@ -534,7 +555,7 @@ void RsGxsForumModel::convertMsgToPostEntry(const RsGxsForumGroup& mForumGroup,c fentry.mMsgId = msg.mMeta.mMsgId; fentry.mPublishTs = msg.mMeta.mPublishTs; fentry.mPostFlags = 0; - fentry.mStatus = msg.mMeta.mMsgStatus; + fentry.mMsgStatus = msg.mMeta.mMsgStatus; if(mForumGroup.mPinnedPosts.ids.find(msg.mMeta.mMsgId) != mForumGroup.mPinnedPosts.ids.end()) fentry.mPostFlags |= ForumModelPostEntry::FLAG_POST_IS_PINNED; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index a0726b3fe..aef4602d8 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -27,7 +27,7 @@ typedef uint32_t ForumModelIndex; struct ForumModelPostEntry { - ForumModelPostEntry() : mPublishTs(0),mPostFlags(0),mReputationWarningLevel(0),mStatus(0),prow(0) {} + ForumModelPostEntry() : mPublishTs(0),mPostFlags(0),mReputationWarningLevel(0),mMsgStatus(0),prow(0) {} enum { // flags for display of posts FLAG_POST_IS_PINNED = 0x0001, @@ -41,7 +41,7 @@ struct ForumModelPostEntry uint32_t mPublishTs; uint32_t mPostFlags; int mReputationWarningLevel; - int mStatus; + int mMsgStatus; std::vector mChildren; ForumModelIndex mParent; @@ -82,11 +82,13 @@ public: QVariant displayRole (const ForumModelPostEntry& fmpe, int col) const; QVariant decorationRole(const ForumModelPostEntry& fmpe, int col) const; QVariant toolTipRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant userRole (const ForumModelPostEntry& fmpe, int col) const; QVariant pinnedRole (const ForumModelPostEntry& fmpe, int col) const; QVariant missingRole (const ForumModelPostEntry& fmpe, int col) const; QVariant statusRole (const ForumModelPostEntry& fmpe, int col) const; QVariant authorRole (const ForumModelPostEntry& fmpe, int col) const; QVariant sortRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant fontRole (const ForumModelPostEntry& fmpe, int col) const; /*! * \brief debug_dump diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 778804102..55353fca2 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -80,16 +80,16 @@ #define VIEW_FLAT 2 /* Thread constants */ + +// We need consts for that!! Defined in multiple places. #define COLUMN_THREAD_TITLE 0 #define COLUMN_THREAD_READ 1 #define COLUMN_THREAD_DATE 2 #define COLUMN_THREAD_DISTRIBUTION 3 #define COLUMN_THREAD_AUTHOR 4 -#define COLUMN_THREAD_SIGNED 5 -#define COLUMN_THREAD_CONTENT 6 -#define COLUMN_THREAD_COUNT 7 -#define COLUMN_THREAD_MSGID 8 -#define COLUMN_THREAD_NB_COLUMNS 9 +#define COLUMN_THREAD_CONTENT 5 +#define COLUMN_THREAD_MSGID 6 +#define COLUMN_THREAD_NB_COLUMNS 7 #define COLUMN_THREAD_DATA 0 // column for storing the userdata like parentid @@ -154,7 +154,36 @@ class AuthorItemDelegate: public QStyledItemDelegate public: AuthorItemDelegate() {} - virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override + { + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + + // disable default icon + opt.icon = QIcon(); + const QRect r = option.rect; + + RsGxsId id(index.data(Qt::UserRole).toString().toStdString()); + QString str; + QList icons; + QString comment; + + QFontMetricsF fm(option.font); + float f = fm.height(); + + QIcon icon ; + + if(!GxsIdDetails::MakeIdDesc(id, true, str, icons, comment,GxsIdDetails::ICON_TYPE_AVATAR)) + icon = GxsIdDetails::getLoadingIcon(id); + else + icon = *icons.begin(); + + QPixmap pix = icon.pixmap(r.size()); + + return QSize(pix.width() + fm.width(str),fm.height()); + } + + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const override { if(!index.isValid()) { @@ -172,11 +201,14 @@ public: const QRect r = option.rect; - RsGxsId id(index.data(Qt::DisplayRole).toString().toStdString()); + RsGxsId id(index.data(Qt::UserRole).toString().toStdString()); QString str; QList icons; QString comment; + QFontMetricsF fm(painter->font()); + float f = fm.height(); + QIcon icon ; if(!GxsIdDetails::MakeIdDesc(id, true, str, icons, comment,GxsIdDetails::ICON_TYPE_AVATAR)) @@ -189,6 +221,7 @@ public: // draw pixmap at center of item const QPoint p = QPoint((r.width() - pix.width())/2, (r.height() - pix.height())/2); painter->drawPixmap(r.topLeft() + p, pix); + painter->drawText(r.topLeft() + p + QPoint(pix.width()+f/2.0,f*0.8), str); } }; @@ -565,10 +598,18 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) if (mFillThread) { return; } -#ifdef TODO QMenu contextMnu(this); - QList selectedItems = ui->threadTreeWidget->selectedItems(); + QModelIndexList selectedIndexes = ui->threadTreeWidget->selectionModel()->selectedIndexes(); + if(selectedIndexes.size() != 1) + return; + + QModelIndex index = *selectedIndexes.begin(); + + RsGxsMessageId mid(mThreadModel->data(index.sibling(index.row(),COLUMN_THREAD_MSGID),Qt::UserRole).toString().toStdString()); + + std::cerr << "Clicked on msg " << mid << std::endl; +#ifdef TODO QAction *editAct = new QAction(QIcon(IMAGE_MESSAGEEDIT), tr("Edit"), &contextMnu); connect(editAct, SIGNAL(triggered()), this, SLOT(editforummessage())); @@ -829,7 +870,7 @@ void GxsForumThreadWidget::changedThread(QModelIndex index) return; } - mThreadId = mOrigThreadId = RsGxsMessageId(mThreadModel->data(index.sibling(index.row(),COLUMN_THREAD_MSGID),Qt::DisplayRole).toString().toStdString()); + mThreadId = mOrigThreadId = RsGxsMessageId(mThreadModel->data(index.sibling(index.row(),COLUMN_THREAD_MSGID),Qt::UserRole).toString().toStdString()); std::cerr << "Switched to new thread ID " << mThreadId << std::endl; @@ -867,7 +908,7 @@ void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item, bool &h bool isNew = IS_MSG_NEW(status); bool unread = IS_MSG_UNREAD(status); bool missing = item->data(COLUMN_THREAD_DATA, ROLE_THREAD_MISSING).toBool(); - RsGxsMessageId msgId(item->data(COLUMN_THREAD_MSGID,Qt::DisplayRole).toString().toStdString()); + RsGxsMessageId msgId(item->data(COLUMN_THREAD_MSGID,Qt::UserRole).toString().toStdString()); // set icon if (missing) { @@ -899,7 +940,7 @@ void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item, bool &h bool is_pinned = mForumGroup.mPinnedPosts.ids.find(msgId) != mForumGroup.mPinnedPosts.ids.end(); // set font - for (int i = 0; i < COLUMN_THREAD_COUNT; ++i) { + for (int i = 0; i < COLUMN_THREAD_NB_COLUMNS; ++i) { QFont qf = item->font(i); if (!IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { @@ -1452,7 +1493,7 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum item->setText(COLUMN_THREAD_CONTENT, doc.toPlainText().replace(QString("\n"), QString(" "))); } - item->setData(COLUMN_THREAD_MSGID,Qt::DisplayRole, QString::fromStdString(msg.mMeta.mMsgId.toStdString())); + item->setData(COLUMN_THREAD_MSGID,Qt::UserRole, QString::fromStdString(msg.mMeta.mMsgId.toStdString())); //#TODO #if 0 if (IS_GROUP_SUBSCRIBED(subscribeFlags) && !(msginfo.mMsgFlags & RS_DISTRIB_MISSING_MSG)) { From 9cec56f1ecd7abfa25be24289cb266b462d99dde Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 24 Nov 2018 17:57:19 +0100 Subject: [PATCH 15/79] added info for read/unread status and resurrected context menu in new forum model --- .../src/gui/gxsforums/GxsForumModel.cpp | 59 ++- .../src/gui/gxsforums/GxsForumModel.h | 24 +- .../gui/gxsforums/GxsForumThreadWidget.cpp | 362 +++++++++--------- .../src/gui/gxsforums/GxsForumThreadWidget.h | 2 + 4 files changed, 247 insertions(+), 200 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index dc098a09f..3a1d4f507 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -10,15 +10,6 @@ //#define DEBUG_FORUMMODEL -#define COLUMN_THREAD_TITLE 0 -#define COLUMN_THREAD_READ 1 -#define COLUMN_THREAD_DATE 2 -#define COLUMN_THREAD_DISTRIBUTION 3 -#define COLUMN_THREAD_AUTHOR 4 -#define COLUMN_THREAD_CONTENT 5 -#define COLUMN_THREAD_MSGID 6 -#define COLUMN_THREAD_NB_COLUMNS 7 - #define COLUMN_THREAD_DATA 0 // column for storing the userdata like parentid Q_DECLARE_METATYPE(RsMsgMetaData); @@ -85,6 +76,23 @@ int RsGxsForumModel::columnCount(const QModelIndex &parent) const return COLUMN_THREAD_NB_COLUMNS ; } +bool RsGxsForumModel::getPostData(const QModelIndex& i,ForumModelPostEntry& fmpe) const +{ + if(!i.isValid()) + return true; + + void *ref = i.internalPointer(); + uint32_t entry = 0; + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + return false ; + + fmpe = mPosts[entry]; + + return true; + +} + bool RsGxsForumModel::hasChildren(const QModelIndex &parent) const { if(!parent.isValid()) @@ -915,6 +923,39 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou std::cerr << "GxsForumsFillThread::run() stopped: " << (wasStopped() ? "yes" : "no") << std::endl; #endif + + bool has_unread_below,has_read_below ; + + recursUpdateReadStatus(0,has_unread_below,has_read_below) ; +} + +void RsGxsForumModel::recursUpdateReadStatus(ForumModelIndex i,bool& has_unread_below,bool& has_read_below) +{ + has_unread_below = IS_MSG_UNREAD(mPosts[i].mMsgStatus); + has_read_below = !IS_MSG_UNREAD(mPosts[i].mMsgStatus); + + for(uint32_t j=0;j& entries,ForumModelIndex index,int depth) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index aef4602d8..eac629b59 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -29,10 +29,12 @@ struct ForumModelPostEntry { ForumModelPostEntry() : mPublishTs(0),mPostFlags(0),mReputationWarningLevel(0),mMsgStatus(0),prow(0) {} - enum { // flags for display of posts - FLAG_POST_IS_PINNED = 0x0001, - FLAG_POST_IS_MISSING = 0x0002, - FLAG_POST_IS_REDACTED = 0x0004, + enum { // flags for display of posts. To be used in mPostFlags + FLAG_POST_IS_PINNED = 0x0001, + FLAG_POST_IS_MISSING = 0x0002, + FLAG_POST_IS_REDACTED = 0x0004, + FLAG_POST_HAS_UNREAD_CHILDREN = 0x0008, + FLAG_POST_HAS_READ_CHILDREN = 0x0010, }; std::string mTitle ; @@ -58,6 +60,17 @@ public: explicit RsGxsForumModel(QObject *parent = NULL); ~RsGxsForumModel(){} + enum Columns { + COLUMN_THREAD_TITLE =0x00, + COLUMN_THREAD_READ =0x01, + COLUMN_THREAD_DATE =0x02, + COLUMN_THREAD_DISTRIBUTION =0x03, + COLUMN_THREAD_AUTHOR =0x04, + COLUMN_THREAD_CONTENT =0x05, + COLUMN_THREAD_MSGID =0x06, + COLUMN_THREAD_NB_COLUMNS =0x07, + }; + enum Roles{ SortRole = Qt::UserRole+1, ThreadPinnedRole = Qt::UserRole+2, MissingRole = Qt::UserRole+3, @@ -71,6 +84,8 @@ public: int columnCount(const QModelIndex &parent = QModelIndex()) const override; bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; + bool getPostData(const QModelIndex& i,ForumModelPostEntry& fmpe) const ; + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex& child) const override; Qt::ItemFlags flags(const QModelIndex& index) const override; @@ -112,6 +127,7 @@ private: void update_posts(const RsGxsGroupId &group_id); void setForumMessageSummary(const std::vector& messages); + void recursUpdateReadStatus(ForumModelIndex i,bool& has_unread_below,bool& has_read_below); static void generateMissingItem(const RsGxsMessageId &msgId,ForumModelPostEntry& entry); static ForumModelIndex addEntry(std::vector& posts,const ForumModelPostEntry& entry,ForumModelIndex parent); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 55353fca2..3d62a2982 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -82,16 +82,6 @@ /* Thread constants */ // We need consts for that!! Defined in multiple places. -#define COLUMN_THREAD_TITLE 0 -#define COLUMN_THREAD_READ 1 -#define COLUMN_THREAD_DATE 2 -#define COLUMN_THREAD_DISTRIBUTION 3 -#define COLUMN_THREAD_AUTHOR 4 -#define COLUMN_THREAD_CONTENT 5 -#define COLUMN_THREAD_MSGID 6 -#define COLUMN_THREAD_NB_COLUMNS 7 - -#define COLUMN_THREAD_DATA 0 // column for storing the userdata like parentid #define ROLE_THREAD_MSGID Qt::UserRole #define ROLE_THREAD_STATUS Qt::UserRole + 1 @@ -277,12 +267,12 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mInMsgAsReadUnread = false; mThreadCompareRole = new RSTreeWidgetItemCompareRole; - mThreadCompareRole->setRole(COLUMN_THREAD_DATE, ROLE_THREAD_SORT); + mThreadCompareRole->setRole(RsGxsForumModel::COLUMN_THREAD_DATE, ROLE_THREAD_SORT); mThreadModel = new RsGxsForumModel(this); ui->threadTreeWidget->setModel(mThreadModel); - ui->threadTreeWidget->setItemDelegateForColumn(COLUMN_THREAD_DISTRIBUTION,new DistributionItemDelegate()) ; - ui->threadTreeWidget->setItemDelegateForColumn(COLUMN_THREAD_AUTHOR,new AuthorItemDelegate()) ; + ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,new DistributionItemDelegate()) ; + ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_AUTHOR,new AuthorItemDelegate()) ; connect(ui->versions_CB, SIGNAL(currentIndexChanged(int)), this, SLOT(changedVersion())); connect(ui->threadTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(threadListCustomPopupMenu(QPoint))); @@ -319,15 +309,15 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget /* Set header resize modes and initial section sizes */ QHeaderView * ttheader = ui->threadTreeWidget->header () ; - QHeaderView_setSectionResizeModeColumn(ttheader, COLUMN_THREAD_TITLE, QHeaderView::Interactive); - QHeaderView_setSectionResizeModeColumn(ttheader, COLUMN_THREAD_DISTRIBUTION, QHeaderView::ResizeToContents); + QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_TITLE, QHeaderView::Interactive); + QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, QHeaderView::ResizeToContents); float f = QFontMetricsF(font()).height()/14.0f ; - ttheader->resizeSection (COLUMN_THREAD_DATE, 140*f); - ttheader->resizeSection (COLUMN_THREAD_TITLE, 440*f); - ttheader->resizeSection (COLUMN_THREAD_DISTRIBUTION, 24*f); - ttheader->resizeSection (COLUMN_THREAD_AUTHOR, 150*f); + ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_DATE, 140*f); + ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_TITLE, 440*f); + ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, 24*f); + ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_AUTHOR, 150*f); #ifdef SUSPENDED_CODE /* Set text of column "Read" to empty - without this the column has a number as header text */ @@ -339,10 +329,10 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget #endif /* add filter actions */ - ui->filterLineEdit->addFilter(QIcon(), tr("Title"), COLUMN_THREAD_TITLE, tr("Search Title")); - ui->filterLineEdit->addFilter(QIcon(), tr("Date"), COLUMN_THREAD_DATE, tr("Search Date")); - ui->filterLineEdit->addFilter(QIcon(), tr("Author"), COLUMN_THREAD_AUTHOR, tr("Search Author")); - ui->filterLineEdit->addFilter(QIcon(), tr("Content"), COLUMN_THREAD_CONTENT, tr("Search Content")); + ui->filterLineEdit->addFilter(QIcon(), tr("Title"), RsGxsForumModel::COLUMN_THREAD_TITLE, tr("Search Title")); + ui->filterLineEdit->addFilter(QIcon(), tr("Date"), RsGxsForumModel::COLUMN_THREAD_DATE, tr("Search Date")); + ui->filterLineEdit->addFilter(QIcon(), tr("Author"), RsGxsForumModel::COLUMN_THREAD_AUTHOR, tr("Search Author")); + ui->filterLineEdit->addFilter(QIcon(), tr("Content"), RsGxsForumModel::COLUMN_THREAD_CONTENT, tr("Search Content")); // see processSettings //ui->filterLineEdit->setCurrentFilter(COLUMN_THREAD_TITLE); @@ -352,9 +342,9 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget processSettings(true); /* Set header sizes for the fixed columns and resize modes, must be set after processSettings */ - ttheader->resizeSection (COLUMN_THREAD_READ, 24*f); - QHeaderView_setSectionResizeModeColumn(ttheader, COLUMN_THREAD_READ, QHeaderView::Fixed); - ttheader->hideSection (COLUMN_THREAD_CONTENT); + ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_READ, 24*f); + QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_READ, QHeaderView::Fixed); + ttheader->hideSection (RsGxsForumModel::COLUMN_THREAD_CONTENT); ui->progressBar->hide(); ui->progressText->hide(); @@ -381,7 +371,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget #ifdef SUSPENDED_CODE ui->threadTreeWidget->enableColumnCustomize(true); - ui->threadTreeWidget->sortItems(COLUMN_THREAD_DATE, Qt::DescendingOrder); + ui->threadTreeWidget->sortItems(RsGxsForumModel::COLUMN_THREAD_DATE, Qt::DescendingOrder); #endif } @@ -442,7 +432,7 @@ void GxsForumThreadWidget::processSettings(bool load) togglethreadview_internal(); // filterColumn - ui->filterLineEdit->setCurrentFilter(Settings->value("filterColumn", COLUMN_THREAD_TITLE).toInt()); + ui->filterLineEdit->setCurrentFilter(Settings->value("filterColumn", RsGxsForumModel::COLUMN_THREAD_TITLE).toInt()); // index of viewBox ui->viewBox->setCurrentIndex(Settings->value("viewBox", VIEW_THREADED).toInt()); @@ -593,23 +583,26 @@ void GxsForumThreadWidget::updateDisplay(bool complete) } } -void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) +bool GxsForumThreadWidget::getCurrentPost(ForumModelPostEntry& fmpe) const { - if (mFillThread) { - return; - } - QMenu contextMnu(this); QModelIndexList selectedIndexes = ui->threadTreeWidget->selectionModel()->selectedIndexes(); - if(selectedIndexes.size() != 1) - return; + if(selectedIndexes.size() != RsGxsForumModel::COLUMN_THREAD_NB_COLUMNS) // check that a single row is selected + return false; QModelIndex index = *selectedIndexes.begin(); - RsGxsMessageId mid(mThreadModel->data(index.sibling(index.row(),COLUMN_THREAD_MSGID),Qt::UserRole).toString().toStdString()); + return mThreadModel->getPostData(index,fmpe); +} - std::cerr << "Clicked on msg " << mid << std::endl; -#ifdef TODO +void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) +{ + QMenu contextMnu(this); + + ForumModelPostEntry current_post ; + bool has_current_post = getCurrentPost(current_post); + + std::cerr << "Clicked on msg " << current_post.mMsgId << std::endl; QAction *editAct = new QAction(QIcon(IMAGE_MESSAGEEDIT), tr("Edit"), &contextMnu); connect(editAct, SIGNAL(triggered()), this, SLOT(editforummessage())); @@ -664,40 +657,39 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) connect(showinpeopleAct, SIGNAL(triggered()), this, SLOT(showInPeopleTab())); if (IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { - QList rows; - QList rowsRead; - QList rowsUnread; - int nCount = getSelectedMsgCount(&rows, &rowsRead, &rowsUnread); + //QList rows; + //QList rowsRead; + //QList rowsUnread; + //int nCount = getSelectedMsgCount(&rows, &rowsRead, &rowsUnread); - if (rowsUnread.isEmpty()) { - markMsgAsRead->setDisabled(true); - } - if (rowsRead.isEmpty()) { - markMsgAsUnread->setDisabled(true); - } + //if (rowsUnread.isEmpty()) { + // markMsgAsRead->setDisabled(true); + //} + //if (rowsRead.isEmpty()) { + // markMsgAsUnread->setDisabled(true); + //} - bool hasUnreadChildren = false; - bool hasReadChildren = false; - int rowCount = rows.count(); - for (int i = 0; i < rowCount; ++i) { - if (hasUnreadChildren || rows[i]->data(COLUMN_THREAD_DATA, ROLE_THREAD_UNREADCHILDREN).toBool()) { - hasUnreadChildren = true; - } - if (hasReadChildren || rows[i]->data(COLUMN_THREAD_DATA, ROLE_THREAD_READCHILDREN).toBool()) { - hasReadChildren = true; - } - } - markMsgAsReadChildren->setEnabled(hasUnreadChildren); - markMsgAsUnreadChildren->setEnabled(hasReadChildren); + //bool hasUnreadChildren = false; + //bool hasReadChildren = false; - if (nCount == 1) { - replyAct->setEnabled (true); - replyauthorAct->setEnabled (true); - } else { - replyAct->setDisabled (true); - replyauthorAct->setDisabled (true); - } - } else { + //int rowCount = rows.count(); + + //for (int i = 0; i < rowCount; ++i) { + // if (hasUnreadChildren || rows[i]->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_UNREADCHILDREN).toBool()) { + // hasUnreadChildren = true; + // } + // if (hasReadChildren || rows[i]->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_READCHILDREN).toBool()) { + // hasReadChildren = true; + // } + //} + markMsgAsReadChildren->setEnabled(current_post.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN); + markMsgAsUnreadChildren->setEnabled(current_post.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_READ_CHILDREN); + + replyAct->setEnabled (true); + replyauthorAct->setEnabled (true); + } + else + { markMsgAsRead->setDisabled(true); markMsgAsReadChildren->setDisabled(true); markMsgAsUnread->setDisabled(true); @@ -706,17 +698,14 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) replyauthorAct->setDisabled (true); } - if(selectedItems.size() == 1) + if(has_current_post) { - QTreeWidgetItem *item = *selectedItems.begin(); - GxsIdRSTreeWidgetItem *gxsIdItem = dynamic_cast(item); - - bool is_pinned = mForumGroup.mPinnedPosts.ids.find( RsGxsMessageId(item->data(COLUMN_THREAD_MSGID,Qt::DisplayRole).toString().toStdString()) ) != mForumGroup.mPinnedPosts.ids.end(); + bool is_pinned = mForumGroup.mPinnedPosts.ids.find( current_post.mMsgId ) != mForumGroup.mPinnedPosts.ids.end(); if(!is_pinned) { RsGxsId author_id; - if(gxsIdItem && gxsIdItem->getId(author_id) && rsIdentity->isOwnId(author_id)) + if(rsIdentity->isOwnId(current_post.mAuthorId)) contextMnu.addAction(editAct); else { @@ -735,7 +724,7 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) } } - if(IS_GROUP_ADMIN(mSubscribeFlags) && (*selectedItems.begin())->parent() == NULL) + if(IS_GROUP_ADMIN(mSubscribeFlags) && (current_post.mParent == 0)) contextMnu.addAction(pinUpPostAct); } @@ -752,42 +741,33 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) contextMnu.addAction(expandAll); contextMnu.addAction(collapseAll); - if(selectedItems.size() == 1) + if(has_current_post) { - QTreeWidgetItem *item = *selectedItems.begin(); - GxsIdRSTreeWidgetItem *gxsIdItem = dynamic_cast(item); + std::cerr << "Author is: " << current_post.mAuthorId << std::endl; - RsGxsId author_id; - if(gxsIdItem && gxsIdItem->getId(author_id)) + contextMnu.addSeparator(); + + RsReputations::Opinion op ; + + if(!rsIdentity->isOwnId(current_post.mAuthorId) && rsReputations->getOwnOpinion(current_post.mAuthorId,op)) { - std::cerr << "Author is: " << author_id << std::endl; + QMenu *submenu1 = contextMnu.addMenu(tr("Author's reputation")) ; - contextMnu.addSeparator(); + if(op != RsReputations::OPINION_POSITIVE) + submenu1->addAction(flagaspositiveAct); - RsReputations::Opinion op ; + if(op != RsReputations::OPINION_NEUTRAL) + submenu1->addAction(flagasneutralAct); - if(!rsIdentity->isOwnId(author_id) && rsReputations->getOwnOpinion(author_id,op)) - { - QMenu *submenu1 = contextMnu.addMenu(tr("Author's reputation")) ; - - if(op != RsReputations::OPINION_POSITIVE) - submenu1->addAction(flagaspositiveAct); - - if(op != RsReputations::OPINION_NEUTRAL) - submenu1->addAction(flagasneutralAct); - - if(op != RsReputations::OPINION_NEGATIVE) - submenu1->addAction(flagasnegativeAct); - } - - contextMnu.addAction(showinpeopleAct); - contextMnu.addAction(replyauthorAct); + if(op != RsReputations::OPINION_NEGATIVE) + submenu1->addAction(flagasnegativeAct); } + contextMnu.addAction(showinpeopleAct); + contextMnu.addAction(replyauthorAct); } contextMnu.exec(QCursor::pos()); -#endif } void GxsForumThreadWidget::contextMenuTextBrowser(QPoint point) @@ -818,7 +798,7 @@ bool GxsForumThreadWidget::eventFilter(QObject *obj, QEvent *event) if (keyEvent && keyEvent->key() == Qt::Key_Space) { // Space pressed QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); - clickedThread (item, COLUMN_THREAD_READ); + clickedThread (item, RsGxsForumModel::COLUMN_THREAD_READ); return true; // eat event } } @@ -870,7 +850,7 @@ void GxsForumThreadWidget::changedThread(QModelIndex index) return; } - mThreadId = mOrigThreadId = RsGxsMessageId(mThreadModel->data(index.sibling(index.row(),COLUMN_THREAD_MSGID),Qt::UserRole).toString().toStdString()); + mThreadId = mOrigThreadId = RsGxsMessageId(mThreadModel->data(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_MSGID),Qt::UserRole).toString().toStdString()); std::cerr << "Switched to new thread ID " << mThreadId << std::endl; @@ -893,37 +873,40 @@ void GxsForumThreadWidget::clickedThread(QTreeWidgetItem *item, int column) return; } - if (column == COLUMN_THREAD_READ) { + if (column == RsGxsForumModel::COLUMN_THREAD_READ) { QList rows; rows.append(item); - uint32_t status = item->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); +#ifdef TODO + uint32_t status = item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); setMsgReadStatus(rows, IS_MSG_UNREAD(status)); +#endif } } void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item, bool &hasReadChilddren, bool &hasUnreadChilddren) { - uint32_t status = item->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); +#ifdef TODO + uint32_t status = item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); bool isNew = IS_MSG_NEW(status); bool unread = IS_MSG_UNREAD(status); - bool missing = item->data(COLUMN_THREAD_DATA, ROLE_THREAD_MISSING).toBool(); - RsGxsMessageId msgId(item->data(COLUMN_THREAD_MSGID,Qt::UserRole).toString().toStdString()); + bool missing = item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_MISSING).toBool(); + RsGxsMessageId msgId(item->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::UserRole).toString().toStdString()); // set icon if (missing) { - item->setIcon(COLUMN_THREAD_READ, QIcon()); - item->setIcon(COLUMN_THREAD_TITLE, QIcon()); + item->setIcon(RsGxsForumModel::COLUMN_THREAD_READ, QIcon()); + item->setIcon(RsGxsForumModel::COLUMN_THREAD_TITLE, QIcon()); } else { if (unread) { - item->setIcon(COLUMN_THREAD_READ, QIcon(":/images/message-state-unread.png")); + item->setIcon(RsGxsForumModel::COLUMN_THREAD_READ, QIcon(":/images/message-state-unread.png")); } else { - item->setIcon(COLUMN_THREAD_READ, QIcon(":/images/message-state-read.png")); + item->setIcon(RsGxsForumModel::COLUMN_THREAD_READ, QIcon(":/images/message-state-read.png")); } if (isNew) { - item->setIcon(COLUMN_THREAD_TITLE, QIcon(":/images/message-state-new.png")); + item->setIcon(RsGxsForumModel::COLUMN_THREAD_TITLE, QIcon(":/images/message-state-new.png")); } else { - item->setIcon(COLUMN_THREAD_TITLE, QIcon()); + item->setIcon(RsGxsForumModel::COLUMN_THREAD_TITLE, QIcon()); } } @@ -940,7 +923,7 @@ void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item, bool &h bool is_pinned = mForumGroup.mPinnedPosts.ids.find(msgId) != mForumGroup.mPinnedPosts.ids.end(); // set font - for (int i = 0; i < COLUMN_THREAD_NB_COLUMNS; ++i) { + for (int i = 0; i < RsGxsForumModel::COLUMN_THREAD_NB_COLUMNS; ++i) { QFont qf = item->font(i); if (!IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { @@ -972,11 +955,12 @@ void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item, bool &h item->setFont(i, qf); } - item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_READCHILDREN, hasReadChilddren || myReadChilddren); - item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_UNREADCHILDREN, hasUnreadChilddren || myUnreadChilddren); + item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_READCHILDREN, hasReadChilddren || myReadChilddren); + item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_UNREADCHILDREN, hasUnreadChilddren || myUnreadChilddren); hasReadChilddren = hasReadChilddren || myReadChilddren || !unread; hasUnreadChilddren = hasUnreadChilddren || myUnreadChilddren || unread; +#endif } void GxsForumThreadWidget::calculateUnreadCount() @@ -990,7 +974,7 @@ void GxsForumThreadWidget::calculateUnreadCount() while ((item = *itemIterator) != NULL) { ++itemIterator; - uint32_t status = item->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); + uint32_t status = item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); if (IS_MSG_UNREAD(status)) { ++unreadCount; } @@ -1243,16 +1227,16 @@ void GxsForumThreadWidget::fillThreadFinished() while ((item = *itemIterator) != NULL) { ++itemIterator; - QString gxsId = item->data(COLUMN_THREAD_DATA, ROLE_THREAD_AUTHOR).toString(); + QString gxsId = item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_AUTHOR).toString(); if (gxsId.isEmpty()) { continue; } - item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_AUTHOR, QVariant()); + item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_AUTHOR, QVariant()); GxsIdRSTreeWidgetItem *gxsIdItem = dynamic_cast(item); if (gxsIdItem) { - gxsIdItem->setId(RsGxsId(gxsId.toStdString()), COLUMN_THREAD_AUTHOR, false); + gxsIdItem->setId(RsGxsId(gxsId.toStdString()), RsGxsForumModel::COLUMN_THREAD_AUTHOR, false); } } @@ -1267,7 +1251,7 @@ void GxsForumThreadWidget::fillThreadFinished() while ((item = *itemIterator) != NULL) { ++itemIterator; - if (item->data(COLUMN_THREAD_MSGID,Qt::DisplayRole).toString().toStdString() == thread->mFocusMsgId) { + if (item->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString().toStdString() == thread->mFocusMsgId) { ui->threadTreeWidget->setCurrentItem(item); ui->threadTreeWidget->setFocus(); break; @@ -1334,13 +1318,13 @@ public: bool operator<(const QTreeWidgetItem& other) const { - bool left_is_not_pinned = ! data(COLUMN_THREAD_DATE,ROLE_THREAD_PINNED).toBool(); - bool right_is_not_pinned = !other.data(COLUMN_THREAD_DATE,ROLE_THREAD_PINNED).toBool(); + bool left_is_not_pinned = ! data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_PINNED).toBool(); + bool right_is_not_pinned = !other.data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_PINNED).toBool(); #ifdef DEBUG_PINNED_POST_SORTING - std::cerr << "Comparing item date \"" << data(COLUMN_THREAD_DATE,Qt::DisplayRole).toString().toStdString() << "\" (" - << data(COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toUInt() << ", \"" << data(COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toString().toStdString() << "\" --> " << left_is_not_pinned << ") to \"" - << other.data(COLUMN_THREAD_DATE,Qt::DisplayRole).toString().toStdString() << "\" (" - << other.data(COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toUInt() << ", \"" << other.data(COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toString().toStdString() << "\" --> " << right_is_not_pinned << ") "; + std::cerr << "Comparing item date \"" << data(RsGxsForumModel::COLUMN_THREAD_DATE,Qt::DisplayRole).toString().toStdString() << "\" (" + << data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toUInt() << ", \"" << data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toString().toStdString() << "\" --> " << left_is_not_pinned << ") to \"" + << other.data(RsGxsForumModel::COLUMN_THREAD_DATE,Qt::DisplayRole).toString().toStdString() << "\" (" + << other.data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toUInt() << ", \"" << other.data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toString().toStdString() << "\" --> " << right_is_not_pinned << ") "; #endif if(left_is_not_pinned ^ right_is_not_pinned) @@ -1380,11 +1364,11 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum item->moveToThread(ui->threadTreeWidget->thread()); if(redacted) - item->setText(COLUMN_THREAD_TITLE, tr("[ ... Redacted message ... ]")); + item->setText(RsGxsForumModel::COLUMN_THREAD_TITLE, tr("[ ... Redacted message ... ]")); else if(is_pinned) - item->setText(COLUMN_THREAD_TITLE, tr("[PINNED] ") + QString::fromUtf8(msg.mMeta.mMsgName.c_str())); + item->setText(RsGxsForumModel::COLUMN_THREAD_TITLE, tr("[PINNED] ") + QString::fromUtf8(msg.mMeta.mMsgName.c_str())); else - item->setText(COLUMN_THREAD_TITLE, QString::fromUtf8(msg.mMeta.mMsgName.c_str())); + item->setText(RsGxsForumModel::COLUMN_THREAD_TITLE, QString::fromUtf8(msg.mMeta.mMsgName.c_str())); QString rep_tooltip_str ; uint32_t rep_warning_level ; @@ -1410,8 +1394,8 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum rep_tooltip_str = tr("Message will be forwarded to your friends.") ; } - item->setData(COLUMN_THREAD_DISTRIBUTION,Qt::ToolTipRole,rep_tooltip_str) ; - item->setData(COLUMN_THREAD_DISTRIBUTION,Qt::DecorationRole,rep_warning_level) ; + item->setData(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,Qt::ToolTipRole,rep_tooltip_str) ; + item->setData(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,Qt::DecorationRole,rep_warning_level) ; //msg.mMeta.mChildTs Was not updated when received new child // so do it here. @@ -1429,35 +1413,37 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum for(QTreeWidgetItem *grandParent = parent; grandParent!=NULL; grandParent = grandParent->parent()) { //Update Parent Child TimeStamp - QString oldTSSort = grandParent->data(COLUMN_THREAD_DATE, ROLE_THREAD_SORT).toString(); + QString oldTSSort = grandParent->data(RsGxsForumModel::COLUMN_THREAD_DATE, ROLE_THREAD_SORT).toString(); QString oldCTSSort = oldTSSort.split("|").at(0); QString oldPTSSort = oldTSSort.contains("|") ? oldTSSort.split(" | ").at(1) : oldCTSSort; #ifdef SHOW_COMBINED_DATES - QString oldTSText = grandParent->text(COLUMN_THREAD_DATE); + QString oldTSText = grandParent->text(RsGxsForumModel::COLUMN_THREAD_DATE); QString oldCTSText = oldTSText.split("|").at(0); QString oldPTSText = oldTSText.contains("|") ? oldTSText.split(" | ").at(1) : oldCTSText;//If first time parent get only its mPublishTs #endif if (oldCTSSort.toDouble() < itemSort.toDouble()) { #ifdef SHOW_COMBINED_DATES - grandParent->setText(COLUMN_THREAD_DATE, DateTime::formatDateTime(qtime) + " | " + oldPTSText); + grandParent->setText(RsGxsForumModel::COLUMN_THREAD_DATE, DateTime::formatDateTime(qtime) + " | " + oldPTSText); #endif - grandParent->setData(COLUMN_THREAD_DATE, ROLE_THREAD_SORT, itemSort + " | " + oldPTSSort); + grandParent->setData(RsGxsForumModel::COLUMN_THREAD_DATE, ROLE_THREAD_SORT, itemSort + " | " + oldPTSSort); } } } - item->setText(COLUMN_THREAD_DATE, itemText); - item->setData(COLUMN_THREAD_DATE,ROLE_THREAD_SORT, itemSort); + item->setText(RsGxsForumModel::COLUMN_THREAD_DATE, itemText); + item->setData(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT, itemSort); if(is_pinned) - item->setData(COLUMN_THREAD_DATE,ROLE_THREAD_PINNED, QVariant(true)); // this is used by the sorting model to put all posts on top + item->setData(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_PINNED, QVariant(true)); // this is used by the sorting model to put all posts on top else - item->setData(COLUMN_THREAD_DATE,ROLE_THREAD_PINNED, QVariant(false)); + item->setData(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_PINNED, QVariant(false)); // Set later with GxsIdRSTreeWidgetItem::setId - item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_AUTHOR, QString::fromStdString(msg.mMeta.mAuthorId.toStdString())); +#ifdef TODO + item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_AUTHOR, QString::fromStdString(msg.mMeta.mAuthorId.toStdString())); +#endif //#TODO #if 0 @@ -1465,35 +1451,35 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum if (text.isEmpty()) { - item->setText(COLUMN_THREAD_AUTHOR, tr("Anonymous")); + item->setText(RsGxsForumModel::COLUMN_THREAD_AUTHOR, tr("Anonymous")); } else { - item->setText(COLUMN_THREAD_AUTHOR, text); + item->setText(RsGxsForumModel::COLUMN_THREAD_AUTHOR, text); } #endif //#TODO #ifdef TOGXS if (msgInfo.mMeta.mMsgFlags & RS_DISTRIB_AUTHEN_REQ) { - item->setText(COLUMN_THREAD_SIGNED, tr("signed")); - item->setIcon(COLUMN_THREAD_SIGNED, QIcon(":/images/mail-signed.png")); + item->setText(RsGxsForumModel::COLUMN_THREAD_SIGNED, tr("signed")); + item->setIcon(RsGxsForumModel::COLUMN_THREAD_SIGNED, QIcon(":/images/mail-signed.png")); } else { - item->setText(COLUMN_THREAD_SIGNED, tr("none")); - item->setIcon(COLUMN_THREAD_SIGNED, QIcon(":/images/mail-signature-unknown.png")); + item->setText(RsGxsForumModel::COLUMN_THREAD_SIGNED, tr("none")); + item->setIcon(RsGxsForumModel::COLUMN_THREAD_SIGNED, QIcon(":/images/mail-signature-unknown.png")); } #endif - if (filterColumn == COLUMN_THREAD_CONTENT) { + if (filterColumn == RsGxsForumModel::COLUMN_THREAD_CONTENT) { // need content for filter QTextDocument doc; doc.setHtml(QString::fromUtf8(msg.mMsg.c_str())); - item->setText(COLUMN_THREAD_CONTENT, doc.toPlainText().replace(QString("\n"), QString(" "))); + item->setText(RsGxsForumModel::COLUMN_THREAD_CONTENT, doc.toPlainText().replace(QString("\n"), QString(" "))); } - item->setData(COLUMN_THREAD_MSGID,Qt::UserRole, QString::fromStdString(msg.mMeta.mMsgId.toStdString())); + item->setData(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::UserRole, QString::fromStdString(msg.mMeta.mMsgId.toStdString())); //#TODO #if 0 if (IS_GROUP_SUBSCRIBED(subscribeFlags) && !(msginfo.mMsgFlags & RS_DISTRIB_MISSING_MSG)) { @@ -1502,9 +1488,9 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum // show message as read status = RSGXS_MSG_STATUS_READ; } + item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS, msg.mMeta.mMsgStatus); + item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_MISSING, false); #endif - item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS, msg.mMeta.mMsgStatus); - item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_MISSING, false); if (parent) parent->addChild(item); return item; @@ -1601,19 +1587,19 @@ void GxsForumThreadWidget::insertThreads() static void copyItem(QTreeWidgetItem *item, const QTreeWidgetItem *newItem) { int i; - for (i = 0; i < COLUMN_THREAD_COUNT; ++i) { - if (i != COLUMN_THREAD_AUTHOR) { + for (i = 0; i < RsGxsForumModel::COLUMN_THREAD_COUNT; ++i) { + if (i != RsGxsForumModel::COLUMN_THREAD_AUTHOR) { /* Copy text */ item->setText(i, newItem->text(i)); } } for (i = 0; i < ROLE_THREAD_COUNT; ++i) { - item->setData(COLUMN_THREAD_DATA, Qt::UserRole + i, newItem->data(COLUMN_THREAD_DATA, Qt::UserRole + i)); + item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, Qt::UserRole + i, newItem->data(RsGxsForumModel::COLUMN_THREAD_DATA, Qt::UserRole + i)); } - item->setData(COLUMN_THREAD_DISTRIBUTION,Qt::DecorationRole,newItem->data(COLUMN_THREAD_DISTRIBUTION,Qt::DecorationRole)); - item->setData(COLUMN_THREAD_DISTRIBUTION,Qt::ToolTipRole, newItem->data(COLUMN_THREAD_DISTRIBUTION,Qt::ToolTipRole )); - item->setData(COLUMN_THREAD_MSGID, Qt::DisplayRole, newItem->data(COLUMN_THREAD_MSGID, Qt::DisplayRole )); + item->setData(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,Qt::DecorationRole,newItem->data(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,Qt::DecorationRole)); + item->setData(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,Qt::ToolTipRole, newItem->data(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,Qt::ToolTipRole )); + item->setData(RsGxsForumModel::COLUMN_THREAD_MSGID, Qt::DisplayRole, newItem->data(RsGxsForumModel::COLUMN_THREAD_MSGID, Qt::DisplayRole )); } void GxsForumThreadWidget::fillThreads(QList &threadList, bool expandNewMessages, QList &itemToExpand) @@ -1630,14 +1616,14 @@ void GxsForumThreadWidget::fillThreads(QList &threadList, boo std::map newThreadMap ; for(QList::iterator newThread = threadList.begin (); newThread != threadList.end (); ++newThread) - newThreadMap[(*newThread)->data(COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()] = *newThread ; + newThreadMap[(*newThread)->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()] = *newThread ; // delete not existing while (index < ui->threadTreeWidget->topLevelItemCount()) { threadItem = ui->threadTreeWidget->topLevelItem(index); - if(newThreadMap.find(threadItem->data(COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()) == newThreadMap.end()) + if(newThreadMap.find(threadItem->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()) == newThreadMap.end()) delete(ui->threadTreeWidget->takeTopLevelItem(index)); else ++index; @@ -1646,16 +1632,16 @@ void GxsForumThreadWidget::fillThreads(QList &threadList, boo //(csoler) QTreeWidget::findItems apparently does not always work so I need to make the search manually, which I do using a map for efficiency reasons. std::map oldThreadMap; for(int i=0; ithreadTreeWidget->topLevelItemCount(); ++i) - oldThreadMap[ui->threadTreeWidget->topLevelItem(i)->data(COLUMN_THREAD_MSGID, Qt::DisplayRole).toString()] = ui->threadTreeWidget->topLevelItem(i); + oldThreadMap[ui->threadTreeWidget->topLevelItem(i)->data(RsGxsForumModel::COLUMN_THREAD_MSGID, Qt::DisplayRole).toString()] = ui->threadTreeWidget->topLevelItem(i); // iterate all new threads for (QList::iterator newThread = threadList.begin (); newThread != threadList.end (); ++newThread) { // search existing thread #ifdef DEBUG_FORUMS - std::cerr << "Makign a search for string \"" << (*newThread)->data(COLUMN_THREAD_MSGID,Qt::DisplayRole).toString().toStdString() << "\"" << std::endl; + std::cerr << "Makign a search for string \"" << (*newThread)->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString().toStdString() << "\"" << std::endl; #endif - std::map::const_iterator it = oldThreadMap.find((*newThread)->data(COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()) ; + std::map::const_iterator it = oldThreadMap.find((*newThread)->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()) ; if(it != oldThreadMap.end()) { @@ -1675,7 +1661,7 @@ void GxsForumThreadWidget::fillThreads(QList &threadList, boo *newThread = NULL; } - uint32_t status = threadItem->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); + uint32_t status = threadItem->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); if (expandNewMessages && IS_MSG_UNREAD(status)) { QTreeWidgetItem *parentItem = threadItem; while ((parentItem = parentItem->parent()) != NULL) { @@ -1704,15 +1690,15 @@ void GxsForumThreadWidget::fillChildren(QTreeWidgetItem *parentItem, QTreeWidget std::map newParentItemMap, parentItemMap ; - for(index = 0; index < newParentItem->childCount(); ++index) newParentItemMap[newParentItem->child(index)->data(COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()] = newParentItem->child(index); - for(index = 0; index < parentItem->childCount(); ++index) parentItemMap[ parentItem->child(index)->data(COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()] = parentItem->child(index); + for(index = 0; index < newParentItem->childCount(); ++index) newParentItemMap[newParentItem->child(index)->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()] = newParentItem->child(index); + for(index = 0; index < parentItem->childCount(); ++index) parentItemMap[ parentItem->child(index)->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()] = parentItem->child(index); // delete not existing while (index < parentItem->childCount()) { childItem = parentItem->child(index); - if(newParentItemMap.find(childItem->data(COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()) == newParentItemMap.end()) + if(newParentItemMap.find(childItem->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()) == newParentItemMap.end()) delete(parentItem->takeChild (index)); else ++index; @@ -1725,7 +1711,7 @@ void GxsForumThreadWidget::fillChildren(QTreeWidgetItem *parentItem, QTreeWidget // search existing child - std::map::const_iterator it = parentItemMap.find(newChildItem->data(COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()) ; + std::map::const_iterator it = parentItemMap.find(newChildItem->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()) ; if(it != parentItemMap.end()) { @@ -1745,7 +1731,7 @@ void GxsForumThreadWidget::fillChildren(QTreeWidgetItem *parentItem, QTreeWidget newCount--; } - uint32_t status = childItem->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); + uint32_t status = childItem->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); if (expandNewMessages && IS_MSG_UNREAD(status)) { QTreeWidgetItem *parentItem = childItem; while ((parentItem = parentItem->parent()) != NULL) { @@ -1890,11 +1876,11 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) mStateHelper->setActive(mTokenTypeMessageData, true); - //mThreadId = mOrigThreadId = RsGxsMessageId(mThreadModel->data(index.sibling(index.row(),COLUMN_THREAD_MSGID),Qt::DisplayRole).toString().toStdString()); + //mThreadId = mOrigThreadId = RsGxsMessageId(mThreadModel->data(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_MSGID),Qt::DisplayRole).toString().toStdString()); //QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); bool setToReadOnActive = Settings->getForumMsgSetToReadOnActivate(); - uint32_t status = msg.mMeta.mMsgStatus ;//item->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); + uint32_t status = msg.mMeta.mMsgStatus ;//item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); #ifdef TODO QList row; @@ -2013,7 +1999,7 @@ void GxsForumThreadWidget::nextUnreadMessage() continue; } - uint32_t status = item->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); + uint32_t status = item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); if (IS_MSG_UNREAD(status)) { ui->threadTreeWidget->setCurrentItem(item); ui->threadTreeWidget->scrollToItem(item, QAbstractItemView::EnsureVisible); @@ -2043,7 +2029,7 @@ int GxsForumThreadWidget::getSelectedMsgCount(QList *rows, QLi for(QList::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it) { if (rows) rows->append(*it); if (rowsRead || rowsUnread) { - uint32_t status = (*it)->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); + uint32_t status = (*it)->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); if (IS_MSG_UNREAD(status)) { if (rowsUnread) rowsUnread->append(*it); } else { @@ -2059,18 +2045,19 @@ int GxsForumThreadWidget::getSelectedMsgCount(QList *rows, QLi void GxsForumThreadWidget::setMsgReadStatus(QList &rows, bool read) { +#ifdef TODO QList::iterator row; std::list changedItems; mInMsgAsReadUnread = true; for (row = rows.begin(); row != rows.end(); ++row) { - if ((*row)->data(COLUMN_THREAD_DATA, ROLE_THREAD_MISSING).toBool()) { + if ((*row)->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_MISSING).toBool()) { /* Missing message */ continue; } - uint32_t status = (*row)->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); + uint32_t status = (*row)->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); uint32_t statusNew = (status & ~(GXS_SERV::GXS_MSG_STATUS_GUI_NEW | GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD)); // orig status, without NEW AND UNREAD if (!read) { @@ -2079,11 +2066,11 @@ void GxsForumThreadWidget::setMsgReadStatus(QList &rows, bool if (status != statusNew) // is it different? { - std::string msgId = (*row)->data(COLUMN_THREAD_MSGID,Qt::DisplayRole).toString().toStdString(); + std::string msgId = (*row)->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString().toStdString(); // NB: MUST BE PART OF ACTIVE THREAD--- OR ELSE WE MUST STORE GROUPID SOMEWHERE!. // LIKE THIS BELOW... - //std::string grpId = (*Row)->data(COLUMN_THREAD_DATA, ROLE_THREAD_GROUPID).toString().toStdString(); + //std::string grpId = (*Row)->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_GROUPID).toString().toStdString(); RsGxsGrpMsgIdPair msgPair = std::make_pair( groupId(), RsGxsMessageId(msgId) ); @@ -2109,7 +2096,7 @@ void GxsForumThreadWidget::setMsgReadStatus(QList &rows, bool /* Add message id to ignore list for the next updateDisplay */ mIgnoredMsgId.push_back(RsGxsMessageId(msgId)); - (*row)->setData(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS, statusNew); + (*row)->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS, statusNew); QTreeWidgetItem *parentItem = *row; while (parentItem->parent()) { @@ -2129,6 +2116,7 @@ void GxsForumThreadWidget::setMsgReadStatus(QList &rows, bool } calculateUnreadCount(); } +#endif } void GxsForumThreadWidget::showInPeopleTab() @@ -2168,7 +2156,7 @@ void GxsForumThreadWidget::markMsgAsReadUnread (bool read, bool children, bool f QTreeWidgetItem *row = rows.takeFirst(); /* add only items with the right state or with not RSGXS_MSG_STATUS_READ */ - uint32_t status = row->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); + uint32_t status = row->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); bool isUnread = IS_MSG_UNREAD(status); if (isUnread == read || IS_MSG_NEW(status)) { allRows.append(row); @@ -2237,7 +2225,7 @@ bool GxsForumThreadWidget::navigate(const RsGxsMessageId &msgId) while ((item = *itemIterator) != NULL) { ++itemIterator; - if (item->data(COLUMN_THREAD_MSGID,Qt::DisplayRole).toString() == msgIdString) { + if (item->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString() == msgIdString) { ui->threadTreeWidget->setCurrentItem(item); ui->threadTreeWidget->setFocus(); return true; @@ -2265,7 +2253,7 @@ void GxsForumThreadWidget::copyMessageLink() #ifdef TODO QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); - QString thread_title = (item != NULL)?item->text(COLUMN_THREAD_TITLE):QString() ; + QString thread_title = (item != NULL)?item->text(RsGxsForumModel::COLUMN_THREAD_TITLE):QString() ; RetroShareLink link = RetroShareLink::createGxsMessageLink(RetroShareLink::TYPE_FORUM, groupId(), mThreadId, thread_title); @@ -2316,7 +2304,7 @@ void GxsForumThreadWidget::togglePinUpPost() return ; } - QString thread_title = (item != NULL)?item->text(COLUMN_THREAD_TITLE):QString() ; + QString thread_title = (item != NULL)?item->text(RsGxsForumModel::COLUMN_THREAD_TITLE):QString() ; std::cerr << "Toggling Pin-up state of post " << mThreadId.toStdString() << ": \"" << thread_title.toStdString() << "\"" << std::endl; @@ -2570,7 +2558,7 @@ void GxsForumThreadWidget::filterColumnChanged(int column) return; } - if (column == COLUMN_THREAD_CONTENT) { + if (column == RsGxsForumModel::COLUMN_THREAD_CONTENT) { // need content ... refill //insertThreads(); } else { @@ -2671,7 +2659,7 @@ void GxsForumThreadWidget::updateGroupData() mForumGroup = group; insertGroupData(); - ui->threadTreeWidget->setColumnHidden(COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); + ui->threadTreeWidget->setColumnHidden(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mSubscribeFlags)) ; }, this ); @@ -2721,7 +2709,7 @@ void GxsForumThreadWidget::updateMessageData(const RsGxsMessageId& msgId) insertMessageData(msg); - ui->threadTreeWidget->setColumnHidden(COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); + ui->threadTreeWidget->setColumnHidden(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mSubscribeFlags)) ; }, this ); @@ -2785,7 +2773,7 @@ void GxsForumThreadWidget::loadGroupData(const uint32_t &token) mStateHelper->setActive(mTokenTypeGroupData, true); // Don't show the distribution column if the forum has no anti-spam - ui->threadTreeWidget->setColumnHidden(COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); + ui->threadTreeWidget->setColumnHidden(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mSubscribeFlags)) ; } else diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 89ec7b9d9..3f5a5c92f 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -33,6 +33,7 @@ class RsGxsForumMsg; class GxsForumsFillThread; class RsGxsForumGroup; class RsGxsForumModel; +class ForumModelPostEntry; namespace Ui { class GxsForumThreadWidget; @@ -149,6 +150,7 @@ private slots: private: void insertMessageData(const RsGxsForumMsg &msg); + bool getCurrentPost(ForumModelPostEntry& fmpe) const ; void insertMessage(); void insertGroupData(); From 6f83bb520e44c36a4f705a7b0f06c5bb4cf92d59 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 24 Nov 2018 20:50:09 +0100 Subject: [PATCH 16/79] fixed mark as read/unread and display of read status in forum model --- .../src/gui/gxsforums/GxsForumModel.cpp | 76 ++++++++++++++----- .../src/gui/gxsforums/GxsForumModel.h | 19 +++++ .../gui/gxsforums/GxsForumThreadWidget.cpp | 51 ++++++++++--- .../src/gui/gxsforums/GxsForumThreadWidget.h | 11 +-- 4 files changed, 122 insertions(+), 35 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 3a1d4f507..ce28e9191 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -258,13 +258,8 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const switch(role) { - case Qt::SizeHintRole: return sizeHintRole(index.column()) ; - case Qt::FontRole: - case Qt::TextAlignmentRole: - case Qt::TextColorRole: - case Qt::WhatsThisRole: - case Qt::EditRole: - case Qt::StatusTipRole: return QVariant(); + case Qt::SizeHintRole: return sizeHintRole(index.column()) ; + case Qt::StatusTipRole:return QVariant(); default: break; } @@ -297,7 +292,7 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const { QFont font ; - font.setBold(IS_MSG_UNREAD(fmpe.mMsgStatus)); + font.setBold(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN); return QVariant(font); } @@ -311,6 +306,7 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const case Qt::DecorationRole: return decorationRole(fmpe,index.column()) ; case Qt::ToolTipRole: return toolTipRole (fmpe,index.column()) ; case Qt::UserRole: return userRole (fmpe,index.column()) ; + case Qt::TextColorRole: return textColorRole (fmpe,index.column()) ; case ThreadPinnedRole: return pinnedRole (fmpe,index.column()) ; case MissingRole: return missingRole (fmpe,index.column()) ; @@ -320,6 +316,14 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const } } +QVariant RsGxsForumModel::textColorRole(const ForumModelPostEntry& fmpe,int column) const +{ + if( (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN) && !IS_MSG_UNREAD(fmpe.mMsgStatus)) + return QVariant(mTextColorUnreadChildren); + + return QVariant(); +} + QVariant RsGxsForumModel::statusRole(const ForumModelPostEntry& fmpe,int column) const { if(column != COLUMN_THREAD_DATA) @@ -476,6 +480,9 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector= mPosts.size()) + return ; + + bool has_unread_below,has_read_below; + recursSetMsgReadStatus(entry,read_status,with_children) ; + recursUpdateReadStatus(0,has_unread_below,has_read_below); +} + +void RsGxsForumModel::recursSetMsgReadStatus(ForumModelIndex i,bool read_status,bool with_children) +{ + if(read_status) + mPosts[i].mMsgStatus = 0; + else + mPosts[i].mMsgStatus = GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD; + + uint32_t token; + rsGxsForums->setMessageReadStatus(token,std::make_pair( mForumGroup.mMeta.mGroupId, mPosts[i].mMsgId ), read); + + if(!with_children) + return; + + for(uint32_t j=0;j& entries,For { const ForumModelPostEntry& e(entries[index]); - std::cerr << std::string(depth*2,' ') << e.mAuthorId.toStdString() << " " << QString("%1").arg((uint32_t)e.mPostFlags,8,16,QChar('0')).toStdString() - << " " << QDateTime::fromSecsSinceEpoch(e.mPublishTs).toString().toStdString() << " \"" << e.mTitle << "\"" << std::endl; + std::cerr << std::string(depth*2,' ') << e.mAuthorId.toStdString() << " " + << QString("%1").arg((uint32_t)e.mPostFlags,8,16,QChar('0')).toStdString() << " " + << QString("%1").arg((uint32_t)e.mMsgStatus,8,16,QChar('0')).toStdString() << " " + << QDateTime::fromSecsSinceEpoch(e.mPublishTs).toString().toStdString() << " \"" << e.mTitle << "\"" << std::endl; for(uint32_t i=0;i +#include // This class holds the actual hierarchy of posts, represented by identifiers // It is responsible for auto-updating when necessary and holds a mutex to allow the Model to @@ -77,9 +78,19 @@ public: StatusRole = Qt::UserRole+4, }; + QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} + // This method will asynchroneously update the data void setForum(const RsGxsGroupId& forumGroup); + void setTextColorRead (QColor color) { mTextColorRead = color;} + void setTextColorUnread (QColor color) { mTextColorUnread = color;} + void setTextColorUnreadChildren(QColor color) { mTextColorUnreadChildren = color;} + void setTextColorNotSubscribed (QColor color) { mTextColorNotSubscribed = color;} + void setTextColorMissing (QColor color) { mTextColorMissing = color;} + + void setMsgReadStatus(const QModelIndex &i, bool read_status, bool with_children); + int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; @@ -104,6 +115,7 @@ public: QVariant authorRole (const ForumModelPostEntry& fmpe, int col) const; QVariant sortRole (const ForumModelPostEntry& fmpe, int col) const; QVariant fontRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant textColorRole(const ForumModelPostEntry& fmpe, int col) const; /*! * \brief debug_dump @@ -128,6 +140,7 @@ private: void update_posts(const RsGxsGroupId &group_id); void setForumMessageSummary(const std::vector& messages); void recursUpdateReadStatus(ForumModelIndex i,bool& has_unread_below,bool& has_read_below); + void recursSetMsgReadStatus(ForumModelIndex i,bool read_status,bool with_children); static void generateMissingItem(const RsGxsMessageId &msgId,ForumModelPostEntry& entry); static ForumModelIndex addEntry(std::vector& posts,const ForumModelPostEntry& entry,ForumModelIndex parent); @@ -138,4 +151,10 @@ private: void initEmptyHierarchy(std::vector& posts); std::vector mPosts ; // store the list of posts updated from rsForums. + + QColor mTextColorRead ; + QColor mTextColorUnread ; + QColor mTextColorUnreadChildren; + QColor mTextColorNotSubscribed ; + QColor mTextColorMissing ; }; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 3d62a2982..44c530ed6 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -170,7 +170,7 @@ public: QPixmap pix = icon.pixmap(r.size()); - return QSize(pix.width() + fm.width(str),fm.height()); + return QSize(pix.width() + fm.width(str),1.2*fm.height()); } virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const override @@ -215,6 +215,12 @@ public: } }; +void GxsForumThreadWidget::setTextColorRead (QColor color) { mTextColorRead = color; mThreadModel->setTextColorRead (color);} +void GxsForumThreadWidget::setTextColorUnread (QColor color) { mTextColorUnread = color; mThreadModel->setTextColorUnread (color);} +void GxsForumThreadWidget::setTextColorUnreadChildren(QColor color) { mTextColorUnreadChildren = color; mThreadModel->setTextColorUnreadChildren(color);} +void GxsForumThreadWidget::setTextColorNotSubscribed (QColor color) { mTextColorNotSubscribed = color; mThreadModel->setTextColorNotSubscribed (color);} +void GxsForumThreadWidget::setTextColorMissing (QColor color) { mTextColorMissing = color; mThreadModel->setTextColorMissing (color);} + GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget *parent) : GxsMessageFrameWidget(rsGxsForums, parent), ui(new Ui::GxsForumThreadWidget) @@ -234,6 +240,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget setUpdateWhenInvisible(true); +#ifdef TODO /* Setup UI helper */ mStateHelper->addWidget(mTokenTypeGroupData, ui->subscribeToolButton); mStateHelper->addWidget(mTokenTypeGroupData, ui->newthreadButton); @@ -257,6 +264,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mStateHelper->addLoadPlaceholder(mTokenTypeMessageData, ui->postText); //mStateHelper->addLoadPlaceholder(mTokenTypeMessageData, ui->threadTitle); +#endif mSubscribeFlags = 0; mSignFlags = 0; @@ -583,14 +591,21 @@ void GxsForumThreadWidget::updateDisplay(bool complete) } } -bool GxsForumThreadWidget::getCurrentPost(ForumModelPostEntry& fmpe) const +QModelIndex GxsForumThreadWidget::GxsForumThreadWidget::getCurrentIndex() const { QModelIndexList selectedIndexes = ui->threadTreeWidget->selectionModel()->selectedIndexes(); if(selectedIndexes.size() != RsGxsForumModel::COLUMN_THREAD_NB_COLUMNS) // check that a single row is selected - return false; + return QModelIndex(); - QModelIndex index = *selectedIndexes.begin(); + return *selectedIndexes.begin(); +} +bool GxsForumThreadWidget::getCurrentPost(ForumModelPostEntry& fmpe) const +{ + QModelIndex index = getCurrentIndex() ; + + if(!index.isValid()) + return false ; return mThreadModel->getPostData(index,fmpe); } @@ -1882,25 +1897,22 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) bool setToReadOnActive = Settings->getForumMsgSetToReadOnActivate(); uint32_t status = msg.mMeta.mMsgStatus ;//item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); -#ifdef TODO - QList row; - row.append(item); + QModelIndex index = getCurrentIndex(); if (IS_MSG_NEW(status)) { if (setToReadOnActive) { /* set to read */ - setMsgReadStatus(row, true); + mThreadModel->setMsgReadStatus(index,true,false); } else { /* set to unread by user */ - setMsgReadStatus(row, false); + mThreadModel->setMsgReadStatus(index,false,false); } } else { if (setToReadOnActive && IS_MSG_UNREAD(status)) { /* set to read */ - setMsgReadStatus(row, true); + mThreadModel->setMsgReadStatus(index, true,false); } } -#endif ui->time_label->setText(DateTime::formatLongDateTime(msg.mMeta.mPublishTs)); ui->by_label->setId(msg.mMeta.mAuthorId); @@ -2045,6 +2057,7 @@ int GxsForumThreadWidget::getSelectedMsgCount(QList *rows, QLi void GxsForumThreadWidget::setMsgReadStatus(QList &rows, bool read) { + #ifdef TODO QList::iterator row; std::list changedItems; @@ -2132,11 +2145,25 @@ void GxsForumThreadWidget::showInPeopleTab() void GxsForumThreadWidget::markMsgAsReadUnread (bool read, bool children, bool forum) { -#ifdef TODO if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { return; } + if(forum) + mThreadModel->setMsgReadStatus(mThreadModel->root(),read,children); + else + { + QModelIndexList selectedIndexes = ui->threadTreeWidget->selectionModel()->selectedIndexes(); + + if(selectedIndexes.size() != RsGxsForumModel::COLUMN_THREAD_NB_COLUMNS) // check that a single row is selected + return ; + + QModelIndex index = *selectedIndexes.begin(); + + mThreadModel->setMsgReadStatus(index,read,children); + } + +#ifdef TODO /* get selected messages */ QList rows; if (forum) { diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 3f5a5c92f..b32296d65 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -59,11 +59,11 @@ public: QColor textColorNotSubscribed() const { return mTextColorNotSubscribed; } QColor textColorMissing() const { return mTextColorMissing; } - void setTextColorRead(QColor color) { mTextColorRead = color; } - void setTextColorUnread(QColor color) { mTextColorUnread = color; } - void setTextColorUnreadChildren(QColor color) { mTextColorUnreadChildren = color; } - void setTextColorNotSubscribed(QColor color) { mTextColorNotSubscribed = color; } - void setTextColorMissing(QColor color) { mTextColorMissing = color; } + void setTextColorRead (QColor color) ; + void setTextColorUnread (QColor color) ; + void setTextColorUnreadChildren(QColor color) ; + void setTextColorNotSubscribed (QColor color) ; + void setTextColorMissing (QColor color) ; /* GxsMessageFrameWidget */ virtual void groupIdChanged(); @@ -151,6 +151,7 @@ private slots: private: void insertMessageData(const RsGxsForumMsg &msg); bool getCurrentPost(ForumModelPostEntry& fmpe) const ; + QModelIndex getCurrentIndex() const; void insertMessage(); void insertGroupData(); From 73840158504dd6714fc683565ee0775f54421879 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 24 Nov 2018 22:06:34 +0100 Subject: [PATCH 17/79] fixed update of QTreeView when something changes in Forum model using dataChanged() signal --- .../src/gui/gxsforums/GxsForumModel.cpp | 64 +++++------ .../src/gui/gxsforums/GxsForumModel.h | 5 +- .../gui/gxsforums/GxsForumThreadWidget.cpp | 105 +++++++++++------- .../src/gui/gxsforums/GxsForumThreadWidget.h | 2 +- 4 files changed, 92 insertions(+), 84 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index ce28e9191..da5c1c281 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "util/qtthreadsutils.h" #include "util/DateTime.h" @@ -10,8 +11,6 @@ //#define DEBUG_FORUMMODEL -#define COLUMN_THREAD_DATA 0 // column for storing the userdata like parentid - Q_DECLARE_METATYPE(RsMsgMetaData); std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere @@ -25,30 +24,6 @@ RsGxsForumModel::RsGxsForumModel(QObject *parent) mFilterColumn=0; mUseChildTS=false; mFlatView=false; - -// // adds some fake posts to debug -// -// int N=5 ; -// mPosts.resize(N+1); -// -// for(int i=1;i<=N;++i) -// { -// mPosts[0].mChildren.push_back(ForumModelIndex(i)); -// mPosts[i].mParent = ForumModelIndex(0); -// mPosts[i].prow = i-1; -// -// RsMsgMetaData meta; -// meta.mMsgName = std::string("message ") + QString::number(i).toStdString() ; -// } -// -// // add one child to last post -// mPosts.resize(N+2); -// mPosts[N].mChildren.push_back(ForumModelIndex(N+1)); -// mPosts[N+1].mParent = ForumModelIndex(N); -// mPosts[N+1].prow = 0; -// -// RsMsgMetaData meta; -// meta.mMsgName = std::string("message ") + QString::number(N+1).toStdString() ; } void RsGxsForumModel::initEmptyHierarchy(std::vector& posts) @@ -232,19 +207,27 @@ int RsGxsForumModel::getChildrenCount(void *ref) const QVariant RsGxsForumModel::headerData(int section, Qt::Orientation orientation, int role) const { - if(role != Qt::DisplayRole) - return QVariant(); + if(role == Qt::DisplayRole) + switch(section) + { + case COLUMN_THREAD_TITLE: return tr("Title"); + case COLUMN_THREAD_DATE: return tr("Date"); + case COLUMN_THREAD_AUTHOR: return tr("Author"); + case COLUMN_THREAD_DISTRIBUTION: return tr("Distribution"); + default: + return QVariant(); + } - switch(section) - { - case COLUMN_THREAD_TITLE: return tr("Title"); - case COLUMN_THREAD_DATE: return tr("Date"); - case COLUMN_THREAD_AUTHOR: return tr("Author"); - case COLUMN_THREAD_DISTRIBUTION: return QString("[icon missing]") ; - case COLUMN_THREAD_READ: return QString("[icon missing]") ; - default: - return QString("[unused]"); - } + if(role == Qt::DecorationRole) + switch(section) + { + case COLUMN_THREAD_DISTRIBUTION: return QIcon(":/icons/flag_green.png"); + case COLUMN_THREAD_READ: return QIcon(":/images/message-state-read.png"); + default: + return QVariant(); + } + + return QVariant(); } QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const @@ -453,6 +436,8 @@ QVariant RsGxsForumModel::decorationRole(const ForumModelPostEntry& fmpe,int col { if(col == COLUMN_THREAD_DISTRIBUTION) return QVariant(fmpe.mReputationWarningLevel); + else if(col == COLUMN_THREAD_READ) + return QVariant(fmpe.mMsgStatus); else return QVariant(); } @@ -486,6 +471,7 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vectordrawControl(QStyle::CE_ItemViewItem, &opt, painter, 0); + + const QRect r = option.rect; + + QIcon icon ; + + // get pixmap + unsigned int read_status = qvariant_cast(index.data(Qt::DecorationRole)); + + bool unread = IS_MSG_UNREAD(read_status); + bool missing = index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_DATA).data(ROLE_THREAD_MISSING).toBool(); + + // set icon + if (missing) + icon = QIcon(); + else + { + if (unread) + icon = QIcon(":/images/message-state-unread.png"); + else + icon = QIcon(":/images/message-state-read.png"); + } + + QPixmap pix = icon.pixmap(r.size()); + + // draw pixmap at center of item + const QPoint p = QPoint((r.width() - pix.width())/2, (r.height() - pix.height())/2); + painter->drawPixmap(r.topLeft() + p, pix); + } +}; + class AuthorItemDelegate: public QStyledItemDelegate { public: @@ -281,6 +330,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->threadTreeWidget->setModel(mThreadModel); ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,new DistributionItemDelegate()) ; ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_AUTHOR,new AuthorItemDelegate()) ; + ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_READ,new ReadStatusItemDelegate()) ; connect(ui->versions_CB, SIGNAL(currentIndexChanged(int)), this, SLOT(changedVersion())); connect(ui->threadTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(threadListCustomPopupMenu(QPoint))); @@ -295,7 +345,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->newthreadButton->setText(tr("New thread")); connect(ui->threadTreeWidget, SIGNAL(clicked(QModelIndex)), this, SLOT(changedThread(QModelIndex))); - connect(ui->threadTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(clickedThread(QTreeWidgetItem*,int))); + connect(ui->threadTreeWidget, SIGNAL(clicked(QModelIndex)), this, SLOT(clickedThread(QModelIndex))); connect(ui->viewBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changedViewBox())); connect(ui->expandButton, SIGNAL(clicked()), this, SLOT(togglethreadview())); @@ -671,32 +721,8 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) QAction *showinpeopleAct = new QAction(QIcon(":/images/info16.png"), tr("Show author in people tab"), &contextMnu); connect(showinpeopleAct, SIGNAL(triggered()), this, SLOT(showInPeopleTab())); - if (IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { - //QList rows; - //QList rowsRead; - //QList rowsUnread; - //int nCount = getSelectedMsgCount(&rows, &rowsRead, &rowsUnread); - - //if (rowsUnread.isEmpty()) { - // markMsgAsRead->setDisabled(true); - //} - //if (rowsRead.isEmpty()) { - // markMsgAsUnread->setDisabled(true); - //} - - //bool hasUnreadChildren = false; - //bool hasReadChildren = false; - - //int rowCount = rows.count(); - - //for (int i = 0; i < rowCount; ++i) { - // if (hasUnreadChildren || rows[i]->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_UNREADCHILDREN).toBool()) { - // hasUnreadChildren = true; - // } - // if (hasReadChildren || rows[i]->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_READCHILDREN).toBool()) { - // hasReadChildren = true; - // } - //} + if (IS_GROUP_SUBSCRIBED(mSubscribeFlags)) + { markMsgAsReadChildren->setEnabled(current_post.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN); markMsgAsUnreadChildren->setEnabled(current_post.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_READ_CHILDREN); @@ -874,27 +900,19 @@ void GxsForumThreadWidget::changedThread(QModelIndex index) insertMessage(); } -void GxsForumThreadWidget::clickedThread(QTreeWidgetItem *item, int column) +void GxsForumThreadWidget::clickedThread(QModelIndex index) { - if (item == NULL) { + if(!index.isValid()) return; - } - if (mFillThread) { + if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mSubscribeFlags)) return; - } - if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { - return; - } - - if (column == RsGxsForumModel::COLUMN_THREAD_READ) { - QList rows; - rows.append(item); -#ifdef TODO - uint32_t status = item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); - setMsgReadStatus(rows, IS_MSG_UNREAD(status)); -#endif + if (index.column() == RsGxsForumModel::COLUMN_THREAD_READ) + { + ForumModelPostEntry fmpe; + mThreadModel->getPostData(index,fmpe); + mThreadModel->setMsgReadStatus(index, IS_MSG_UNREAD(fmpe.mMsgStatus),false); } } @@ -2685,6 +2703,7 @@ void GxsForumThreadWidget::updateGroupData() mForumGroup = group; insertGroupData(); + mSubscribeFlags = group.mMeta.mSubscribeFlags; ui->threadTreeWidget->setColumnHidden(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mSubscribeFlags)) ; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index b32296d65..416bd0aaf 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -99,7 +99,7 @@ private slots: void changedThread(QModelIndex index); void changedVersion(); - void clickedThread (QTreeWidgetItem *item, int column); + void clickedThread (QModelIndex index); void reply_with_private_message(); void replytoforummessage(); From 0b0e58bd3ded0543745a9f83a53f178ba1954d21 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 24 Nov 2018 22:25:23 +0100 Subject: [PATCH 18/79] fixed bug in coloring of read/unread property --- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 9 +++++++-- .../src/gui/gxsforums/GxsForumThreadWidget.cpp | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index da5c1c281..0b7d6becf 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -301,8 +301,13 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const QVariant RsGxsForumModel::textColorRole(const ForumModelPostEntry& fmpe,int column) const { - if( (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN) && !IS_MSG_UNREAD(fmpe.mMsgStatus)) - return QVariant(mTextColorUnreadChildren); + if( (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING)) + return QVariant(mTextColorMissing); + + if(IS_MSG_UNREAD(fmpe.mMsgStatus)) + return QVariant(mTextColorUnread); + else + return QVariant(mTextColorRead); return QVariant(); } diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index ad6d6bcb1..d9aa36817 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -219,7 +219,7 @@ public: QPixmap pix = icon.pixmap(r.size()); - return QSize(pix.width() + fm.width(str),1.2*fm.height()); + return QSize(pix.width() + fm.width(str),std::max(1.1*pix.height(),1.4*fm.height())); } virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const override From 419bd2157a3aed70c7eccfb997e2392f97692cd8 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 25 Nov 2018 17:11:08 +0100 Subject: [PATCH 19/79] factored all methods that apply to msg data using pointer to member function trick --- .../gui/gxsforums/GxsForumThreadWidget.cpp | 174 +++++++++--------- .../src/gui/gxsforums/GxsForumThreadWidget.h | 10 +- 2 files changed, 94 insertions(+), 90 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index d9aa36817..31b55093a 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -683,17 +683,17 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) QAction *flagaspositiveAct = new QAction(QIcon(IMAGE_POSITIVE_OPINION), tr("Give positive opinion"), &contextMnu); flagaspositiveAct->setToolTip(tr("This will block/hide messages from this person, and notify friend nodes.")) ; - flagaspositiveAct->setData(mTokenTypePositiveAuthor) ; + flagaspositiveAct->setData(RsReputations::OPINION_POSITIVE) ; connect(flagaspositiveAct, SIGNAL(triggered()), this, SLOT(flagperson())); QAction *flagasneutralAct = new QAction(QIcon(IMAGE_NEUTRAL_OPINION), tr("Give neutral opinion"), &contextMnu); flagasneutralAct->setToolTip(tr("Doing this, you trust your friends to decide to forward this message or not.")) ; - flagasneutralAct->setData(mTokenTypeNeutralAuthor) ; + flagasneutralAct->setData(RsReputations::OPINION_NEUTRAL) ; connect(flagasneutralAct, SIGNAL(triggered()), this, SLOT(flagperson())); QAction *flagasnegativeAct = new QAction(QIcon(IMAGE_NEGATIVE_OPINION), tr("Give negative opinion"), &contextMnu); flagasnegativeAct->setToolTip(tr("This will block/hide messages from this person, and notify friend nodes.")) ; - flagasnegativeAct->setData(mTokenTypeNegativeAuthor) ; + flagasnegativeAct->setData(RsReputations::OPINION_NEGATIVE) ; connect(flagasnegativeAct, SIGNAL(triggered()), this, SLOT(flagperson())); QAction *newthreadAct = new QAction(QIcon(IMAGE_MESSAGE), tr("Start New Thread"), &contextMnu); @@ -898,6 +898,7 @@ void GxsForumThreadWidget::changedThread(QModelIndex index) //ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages()) ; insertMessage(); + mThreadModel->setMsgReadStatus(index, true,false); } void GxsForumThreadWidget::clickedThread(QModelIndex index) @@ -905,8 +906,14 @@ void GxsForumThreadWidget::clickedThread(QModelIndex index) if(!index.isValid()) return; - if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mSubscribeFlags)) - return; + RsGxsMessageId tmp(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_MSGID).data(Qt::UserRole).toString().toStdString()); + + if( tmp.isNull()) + return; + + mThreadId = tmp; + + std::cerr << "Clicked on message ID " << mThreadId << std::endl; if (index.column() == RsGxsForumModel::COLUMN_THREAD_READ) { @@ -1880,6 +1887,8 @@ void GxsForumThreadWidget::insertMessage() /* request Post */ //RsGxsGrpMsgIdPair msgId = std::make_pair(groupId(), mThreadId); updateMessageData(mThreadId); + + markMsgAsRead(); } void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) @@ -2150,17 +2159,6 @@ void GxsForumThreadWidget::setMsgReadStatus(QList &rows, bool #endif } -void GxsForumThreadWidget::showInPeopleTab() -{ - if (groupId().isNull() || mThreadId.isNull()) { - QMessageBox::information(this, tr("RetroShare"),tr("You cant act on the author to a non-existant Message")); - return; - } - - RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId); - requestMsgData_ShowAuthorInPeople(postId) ; -} - void GxsForumThreadWidget::markMsgAsReadUnread (bool read, bool children, bool forum) { if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { @@ -2405,8 +2403,17 @@ void GxsForumThreadWidget::flagperson() return; } - uint32_t token_type = qobject_cast(sender())->data().toUInt(); + RsReputations::Opinion opinion = static_cast(qobject_cast(sender())->data().toUInt()); + ForumModelPostEntry fmpe ; + getCurrentPost(fmpe); + RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId); + + std::cerr << "Setting own opinion for author " << fmpe.mAuthorId << " to " << opinion << std::endl; + + rsReputations->setOwnOpinion(fmpe.mAuthorId,opinion) ; + +#ifdef TO_REMOVE // Get Message ... then complete replyMessageData(). RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId); @@ -2424,40 +2431,60 @@ void GxsForumThreadWidget::flagperson() uint32_t token; mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, token_type); +#endif } -void GxsForumThreadWidget::reply_with_private_message() +void GxsForumThreadWidget::replytoforummessage() { async_msg_action( &GxsForumThreadWidget::replyForumMessageData ); } +void GxsForumThreadWidget::editforummessage() { async_msg_action( &GxsForumThreadWidget::editForumMessageData ); } +void GxsForumThreadWidget::reply_with_private_message() { async_msg_action( &GxsForumThreadWidget::replyMessageData ); } +void GxsForumThreadWidget::showInPeopleTab() { async_msg_action( &GxsForumThreadWidget::showAuthorInPeople ); } + +void GxsForumThreadWidget::async_msg_action(const MsgMethod &action) { if (groupId().isNull() || mThreadId.isNull()) { QMessageBox::information(this, tr("RetroShare"),tr("You cant reply to a non-existant Message")); return; } - // Get Message ... then complete replyMessageData(). - RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId); - requestMsgData_ReplyWithPrivateMessage(postId); -} -void GxsForumThreadWidget::editforummessage() -{ - if (groupId().isNull() || mThreadId.isNull()) { - QMessageBox::information(this, tr("RetroShare"),tr("You cant reply to a non-existant Message")); - return; - } + RsThread::async([this,action]() + { + // 1 - get message data from p3GxsForums - // Get Message ... then complete replyMessageData(). - RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId); - requestMsgData_EditForumMessage(postId); -} -void GxsForumThreadWidget::replytoforummessage() -{ - if (groupId().isNull() || mThreadId.isNull()) { - QMessageBox::information(this, tr("RetroShare"),tr("You cant reply to a non-existant Message")); - return; - } + std::cerr << "Retrieving post data for post " << mThreadId << std::endl; - // Get Message ... then complete replyMessageData(). - RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId); - requestMsgData_ReplyForumMessage(postId); + std::set msgs_to_request ; + std::vector msgs; + + msgs_to_request.insert(mThreadId); + + if(!rsGxsForums->getForumsContent(groupId(),msgs_to_request,msgs)) + { + std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve forum group info for forum " << groupId() << std::endl; + return; + } + + if(msgs.size() != 1) + return; + + // 2 - sort the messages into a proper hierarchy + + RsGxsForumMsg msg = msgs[0]; + + // 3 - update the model in the UI thread. + + RsQThreadUtils::postToObject( [msg,action,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, note that + * Qt::QueuedConnection is important! + */ + + (this->*action)(msg); + + }, this ); + + }); } void GxsForumThreadWidget::replyMessageData(const RsGxsForumMsg &msg) @@ -2488,18 +2515,6 @@ void GxsForumThreadWidget::replyMessageData(const RsGxsForumMsg &msg) } } -void GxsForumThreadWidget::showAuthorInPeople(const RsGxsForumMsg& msg) -{ - if ((msg.mMeta.mGroupId != groupId()) || (msg.mMeta.mMsgId != mThreadId)) - { - std::cerr << "GxsForumThreadWidget::replyMessageData() ERROR Message Ids have changed!"; - std::cerr << std::endl; - return; - } - RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId); - requestMsgData_ShowAuthorInPeople(postId); -} - void GxsForumThreadWidget::editForumMessageData(const RsGxsForumMsg& msg) { if ((msg.mMeta.mGroupId != groupId()) || (msg.mMeta.mMsgId != mThreadId)) @@ -2887,7 +2902,6 @@ void GxsForumThreadWidget::loadMessageData(const uint32_t &token) mStateHelper->clear(mTokenTypeMessageData); } } -#endif /*********************** **** **** **** ***********************/ /*********************** **** **** **** ***********************/ @@ -3038,43 +3052,27 @@ void GxsForumThreadWidget::loadMsgData_ReplyForumMessage(const uint32_t &token) std::cerr << std::endl; } } - -void GxsForumThreadWidget::loadMsgData_ShowAuthorInPeople(const uint32_t &token) -{ -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage()"; - std::cerr << std::endl; #endif - std::vector msgs; - if (rsGxsForums->getMsgData(token, msgs)) +void GxsForumThreadWidget::showAuthorInPeople(const RsGxsForumMsg& msg) +{ + if(msg.mMeta.mAuthorId.isNull()) { - if (msgs.size() != 1) - { - std::cerr << "GxsForumThreadWidget::loadMsgData_showAuthorInPeople() ERROR Wrong number of answers"; - std::cerr << std::endl; - return; - } - - if(msgs[0].mMeta.mAuthorId.isNull()) - { - std::cerr << "GxsForumThreadWidget::loadMsgData_showAuthorInPeople() ERROR Missing Message Data..."; - std::cerr << std::endl; - } - - /* window will destroy itself! */ - IdDialog *idDialog = dynamic_cast(MainWindow::getPage(MainWindow::People)); - - if (!idDialog) - return ; - - MainWindow::showWindow(MainWindow::People); - idDialog->navigate(RsGxsId(msgs[0].mMeta.mAuthorId)); - } - else std::cerr << "GxsForumThreadWidget::loadMsgData_showAuthorInPeople() ERROR Missing Message Data..."; + std::cerr << std::endl; + } + + /* window will destroy itself! */ + IdDialog *idDialog = dynamic_cast(MainWindow::getPage(MainWindow::People)); + + if (!idDialog) + return ; + + MainWindow::showWindow(MainWindow::People); + idDialog->navigate(RsGxsId(msg.mMeta.mAuthorId)); } +#ifdef TO_REMOVE void GxsForumThreadWidget::loadMsgData_SetAuthorOpinion(const uint32_t &token,RsReputations::Opinion opinion) { #ifdef DEBUG_FORUMS @@ -3107,6 +3105,7 @@ void GxsForumThreadWidget::loadMsgData_SetAuthorOpinion(const uint32_t &token,Rs std::cerr << __PRETTY_FUNCTION__ << ": need to implement the update of GxsTreeWidgetItems icons too." << std::endl; } +#endif /*********************** **** **** **** ***********************/ /*********************** **** **** **** ***********************/ @@ -3130,7 +3129,6 @@ void GxsForumThreadWidget::loadRequest(const TokenQueue *queue, const TokenReque loadMessageData(req.mToken); return; } -#endif if (req.mUserType == mTokenTypeReplyMessage) { loadMsgData_ReplyMessage(req.mToken); @@ -3141,7 +3139,7 @@ void GxsForumThreadWidget::loadRequest(const TokenQueue *queue, const TokenReque loadMsgData_ReplyForumMessage(req.mToken); return; } - + if (req.mUserType == mTokenTypeEditForumMessage) { loadMsgData_EditForumMessage(req.mToken); return; @@ -3150,7 +3148,6 @@ void GxsForumThreadWidget::loadRequest(const TokenQueue *queue, const TokenReque loadMsgData_ShowAuthorInPeople(req.mToken); return; } - if (req.mUserType == mTokenTypePositiveAuthor) { loadMsgData_SetAuthorOpinion(req.mToken,RsReputations::OPINION_POSITIVE); return; @@ -3165,6 +3162,7 @@ void GxsForumThreadWidget::loadRequest(const TokenQueue *queue, const TokenReque loadMsgData_SetAuthorOpinion(req.mToken,RsReputations::OPINION_NEUTRAL); return; } +#endif } GxsMessageFrameWidget::loadRequest(queue, req); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 416bd0aaf..fc085e4d1 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -33,6 +33,7 @@ class RsGxsForumMsg; class GxsForumsFillThread; class RsGxsForumGroup; class RsGxsForumModel; +class RsGxsForumMsg; class ForumModelPostEntry; namespace Ui { @@ -43,6 +44,8 @@ class GxsForumThreadWidget : public GxsMessageFrameWidget { Q_OBJECT + typedef void (GxsForumThreadWidget::*MsgMethod)(const RsGxsForumMsg&) ; + Q_PROPERTY(QColor textColorRead READ textColorRead WRITE setTextColorRead) Q_PROPERTY(QColor textColorUnread READ textColorUnread WRITE setTextColorUnread) Q_PROPERTY(QColor textColorUnreadChildren READ textColorUnreadChildren WRITE setTextColorUnreadChildren) @@ -110,6 +113,9 @@ private slots: void replyForumMessageData(const RsGxsForumMsg &msg); void showAuthorInPeople(const RsGxsForumMsg& msg); + // This method is used to perform an asynchroneous action on the message data. Any of the methods above can be used as parameter. + void async_msg_action(const MsgMethod& method); + void saveImage(); @@ -178,19 +184,19 @@ private: void updateMessageData(const RsGxsMessageId& msgId); +#ifdef TO_REMOVE void requestMsgData_ReplyWithPrivateMessage(const RsGxsGrpMsgIdPair &msgId); void requestMsgData_ShowAuthorInPeople(const RsGxsGrpMsgIdPair &msgId); void requestMsgData_ReplyForumMessage(const RsGxsGrpMsgIdPair &msgId); void requestMsgData_EditForumMessage(const RsGxsGrpMsgIdPair &msgId); -#ifdef TO_REMOVE void loadMessageData(const uint32_t &token); -#endif void loadMsgData_ReplyMessage(const uint32_t &token); void loadMsgData_ReplyForumMessage(const uint32_t &token); void loadMsgData_EditForumMessage(const uint32_t &token); void loadMsgData_ShowAuthorInPeople(const uint32_t &token); void loadMsgData_SetAuthorOpinion(const uint32_t &token, RsReputations::Opinion opinion); +#endif private: RsGxsGroupId mLastForumID; From dc913e37c977979e0e96365255311651486795cb Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 25 Nov 2018 17:40:48 +0100 Subject: [PATCH 20/79] fixed update of threads in new model --- .../src/gui/gxsforums/GxsForumModel.cpp | 3 ++- .../gui/gxsforums/GxsForumThreadWidget.cpp | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 0b7d6becf..9f766788f 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -459,6 +459,8 @@ void RsGxsForumModel::setForum(const RsGxsGroupId& forum_group_id) void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector& posts) { + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); + mForumGroup = group; mPosts = posts; @@ -476,7 +478,6 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vectorthreadTreeWidget->header () ; - QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_TITLE, QHeaderView::Interactive); + QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_TITLE, QHeaderView::Interactive); QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, QHeaderView::ResizeToContents); float f = QFontMetricsF(font()).height()/14.0f ; @@ -451,9 +451,11 @@ void GxsForumThreadWidget::blank() #endif ui->forumName->setText(""); +#ifdef SUSPENDED_CODE mStateHelper->setWidgetEnabled(ui->newthreadButton, false); mStateHelper->setWidgetEnabled(ui->previousButton, false); mStateHelper->setWidgetEnabled(ui->nextButton, false); +#endif ui->versions_CB->hide(); } @@ -520,10 +522,8 @@ void GxsForumThreadWidget::groupIdChanged() mNewCount = 0; mUnreadCount = 0; - emit groupChanged(this); - mThreadModel->setForum(groupId()); - //fillComplete(); + updateDisplay(true); } QString GxsForumThreadWidget::groupName(bool withUnreadCount) @@ -1077,7 +1077,7 @@ void GxsForumThreadWidget::insertGroupData() #ifdef DEBUG_FORUMS std::cerr << "GxsForumThreadWidget::insertGroupData" << std::endl; #endif - GxsIdDetails::process(mForumGroup.mMeta.mAuthorId, &loadAuthorIdCallback, this); + //GxsIdDetails::process(mForumGroup.mMeta.mAuthorId, &loadAuthorIdCallback, this); calculateIconsAndFonts(); } @@ -1788,9 +1788,10 @@ void GxsForumThreadWidget::insertMessage() { if (groupId().isNull()) { +#ifdef SUSPENDED_CODE mStateHelper->setActive(mTokenTypeMessageData, false); mStateHelper->clear(mTokenTypeMessageData); - +#endif ui->versions_CB->hide(); ui->time_label->show(); @@ -1800,8 +1801,10 @@ void GxsForumThreadWidget::insertMessage() if (mThreadId.isNull()) { +#ifdef SUSPENDED_CODE mStateHelper->setActive(mTokenTypeMessageData, false); mStateHelper->clear(mTokenTypeMessageData); +#endif ui->versions_CB->hide(); ui->time_label->show(); @@ -1810,7 +1813,9 @@ void GxsForumThreadWidget::insertMessage() return; } +#ifdef SUSPENDED_CODE mStateHelper->setActive(mTokenTypeMessageData, true); +#endif #ifdef TODO QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); @@ -2717,7 +2722,7 @@ void GxsForumThreadWidget::updateGroupData() */ mForumGroup = group; - insertGroupData(); + //insertGroupData(); mSubscribeFlags = group.mMeta.mSubscribeFlags; ui->threadTreeWidget->setColumnHidden(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); From 114a11af75a1b5f6d452008dd56056cfe9e1faaf Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 25 Nov 2018 17:44:56 +0100 Subject: [PATCH 21/79] fixed bug in read status update in new ForumModel --- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 9f766788f..62413404f 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -950,7 +950,7 @@ void RsGxsForumModel::recursSetMsgReadStatus(ForumModelIndex i,bool read_status, mPosts[i].mMsgStatus = GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD; uint32_t token; - rsGxsForums->setMessageReadStatus(token,std::make_pair( mForumGroup.mMeta.mGroupId, mPosts[i].mMsgId ), read); + rsGxsForums->setMessageReadStatus(token,std::make_pair( mForumGroup.mMeta.mGroupId, mPosts[i].mMsgId ), read_status); if(!with_children) return; From 65f2d26651d2e45b1f040f42256079d55b786689 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 25 Nov 2018 21:12:26 +0100 Subject: [PATCH 22/79] fixed author tooltip in ForumModel --- .../src/gui/gxsforums/GxsForumModel.cpp | 45 ++++++++++++++----- .../gui/gxsforums/GxsForumThreadWidget.cpp | 3 ++ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 62413404f..f79ecddf3 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -4,7 +4,9 @@ #include #include "util/qtthreadsutils.h" +#include "util/HandleRichText.h" #include "util/DateTime.h" +#include "gui/gxs/GxsIdDetails.h" #include "GxsForumModel.h" #include "retroshare/rsgxsflags.h" #include "retroshare/rsgxsforums.h" @@ -333,18 +335,36 @@ QVariant RsGxsForumModel::missingRole(const ForumModelPostEntry& fmpe,int column QVariant RsGxsForumModel::toolTipRole(const ForumModelPostEntry& fmpe,int column) const { - if(column != COLUMN_THREAD_DISTRIBUTION) - return QVariant(); + if(column == COLUMN_THREAD_DISTRIBUTION) + switch(fmpe.mReputationWarningLevel) + { + case 3: return QVariant(tr("Information for this identity is currently missing.")) ; + case 2: return QVariant(tr("You have banned this ID. The message will not be\ndisplayed nor forwarded to your friends.")) ; + case 1: return QVariant(tr("You have not set an opinion for this person,\n and your friends do not vote positively: Spam regulation \nprevents the message to be forwarded to your friends.")) ; + case 0: return QVariant(tr("Message will be forwarded to your friends.")) ; + default: + return QVariant("[ERROR: missing reputation level information - contact the developers]"); + } - switch(fmpe.mReputationWarningLevel) - { - case 3: return QVariant(tr("Information for this identity is currently missing.")) ; - case 2: return QVariant(tr("You have banned this ID. The message will not be\ndisplayed nor forwarded to your friends.")) ; - case 1: return QVariant(tr("You have not set an opinion for this person,\n and your friends do not vote positively: Spam regulation \nprevents the message to be forwarded to your friends.")) ; - case 0: return QVariant(tr("Message will be forwarded to your friends.")) ; - default: - return QVariant("[ERROR: missing reputation level information - contact the developers]"); - } + if(column == COLUMN_THREAD_AUTHOR) + { + QString str,comment ; + QList icons; + + if(!GxsIdDetails::MakeIdDesc(fmpe.mAuthorId, true, str, icons, comment,GxsIdDetails::ICON_TYPE_AVATAR)) + return QVariant(); + + int S = QFontMetricsF(QApplication::font()).height(); + QImage pix( (*icons.begin()).pixmap(QSize(4*S,4*S)).toImage()); + + QString embeddedImage; + if(RsHtml::makeEmbeddedImage(pix.scaled(QSize(4*S,4*S), Qt::KeepAspectRatio, Qt::SmoothTransformation), embeddedImage, 8*S * 8*S)) + comment = "
" + embeddedImage + "" + comment + "
"; + + return comment; + } + + return QVariant(); } QVariant RsGxsForumModel::pinnedRole(const ForumModelPostEntry& fmpe,int column) const @@ -474,8 +494,9 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector Date: Sun, 25 Nov 2018 22:07:59 +0100 Subject: [PATCH 23/79] saving work for next unread msg in forum model --- .../src/gui/gxsforums/GxsForumModel.cpp | 36 ++++++++ .../src/gui/gxsforums/GxsForumModel.h | 2 + .../gui/gxsforums/GxsForumThreadWidget.cpp | 84 +++++-------------- 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index f79ecddf3..9a8a0005f 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -1022,6 +1022,42 @@ static void recursPrintModel(const std::vector& entries,For recursPrintModel(entries,e.mChildren[i],depth+1); } +QModelIndex RsGxsForumModel::getIndexOfMessage(const RsGxsMessageId& mid) const +{ + // brutal search. This is not so nice, so dont call that in a loop! + + for(uint32_t i=0;i parent_stack ; + + for(ForumModelIndex tmp(fmi);tmp!=0;tmp=mPosts[tmp].mParent) + parent_stack.push_front(tmp); + + // now get to next unread item + + if(!mPosts[fmi].mChildren.empty()) +#endif + return QModelIndex(); +} + void RsGxsForumModel::debug_dump() { std::cerr << "Model data dump:" << std::endl; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index 1b6348221..9f3468e7f 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -80,6 +80,8 @@ public: }; QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} + QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const; + QModelIndex getNextIndex(const QModelIndex& i,bool unread_only) const; // This method will asynchroneously update the data void setForum(const RsGxsGroupId& forumGroup); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index d7bbaf13a..ed678afff 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -100,6 +100,12 @@ class DistributionItemDelegate: public QStyledItemDelegate public: DistributionItemDelegate() {} + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override + { + const QRect r = option.rect; + return QSize(r.height(),r.height()); + } + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if(!index.isValid()) @@ -518,7 +524,9 @@ void GxsForumThreadWidget::processSettings(bool load) void GxsForumThreadWidget::groupIdChanged() { +#ifdef TO_REMOVE ui->forumName->setText(groupId().isNull () ? "" : tr("Loading")); +#endif mNewCount = 0; mUnreadCount = 0; @@ -2029,43 +2037,17 @@ void GxsForumThreadWidget::downloadAllFiles() void GxsForumThreadWidget::nextUnreadMessage() { -#ifdef TODO - QTreeWidgetItem *currentItem = ui->threadTreeWidget->currentItem(); + QModelIndex index = mThreadModel->getNextIndex(getCurrentIndex(),true); - while (true) { - QTreeWidgetItemIterator itemIterator = currentItem ? QTreeWidgetItemIterator(currentItem, QTreeWidgetItemIterator::NotHidden) : QTreeWidgetItemIterator(ui->threadTreeWidget, QTreeWidgetItemIterator::NotHidden); - - QTreeWidgetItem *item; - while ((item = *itemIterator) != NULL) { - ++itemIterator; - - if (item == currentItem) { - continue; - } - - uint32_t status = item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); - if (IS_MSG_UNREAD(status)) { - ui->threadTreeWidget->setCurrentItem(item); - ui->threadTreeWidget->scrollToItem(item, QAbstractItemView::EnsureVisible); - return; - } - } - - if (currentItem == NULL) { - break; - } - - /* start from top */ - currentItem = NULL; - } -#endif + ui->threadTreeWidget->setCurrentIndex(index); + ui->threadTreeWidget->setFocus(); } +#ifdef TO_REMOVE /* get selected messages the messages tree is single selected, but who knows ... */ int GxsForumThreadWidget::getSelectedMsgCount(QList *rows, QList *rowsRead, QList *rowsUnread) { -#ifdef TODO if (rowsRead) rowsRead->clear(); if (rowsUnread) rowsUnread->clear(); @@ -2083,14 +2065,11 @@ int GxsForumThreadWidget::getSelectedMsgCount(QList *rows, QLi } return selectedItems.size(); -#endif return 0; } void GxsForumThreadWidget::setMsgReadStatus(QList &rows, bool read) { - -#ifdef TODO QList::iterator row; std::list changedItems; @@ -2161,8 +2140,8 @@ void GxsForumThreadWidget::setMsgReadStatus(QList &rows, bool } calculateUnreadCount(); } -#endif } +#endif void GxsForumThreadWidget::markMsgAsReadUnread (bool read, bool children, bool forum) { @@ -2257,31 +2236,14 @@ void GxsForumThreadWidget::setAllMessagesReadDo(bool read, uint32_t &/*token*/) bool GxsForumThreadWidget::navigate(const RsGxsMessageId &msgId) { -#ifdef TODO - if (mStateHelper->isLoading(mTokenTypeInsertThreads)) { - mNavigatePendingMsgId = msgId; + QModelIndex index = mThreadModel->getIndexOfMessage(msgId); - /* No information if message is available */ - return true; - } + if(!index.isValid()) + return false; - QString msgIdString = QString::fromStdString(msgId.toStdString()); - - /* Search exisiting item */ - QTreeWidgetItemIterator itemIterator(ui->threadTreeWidget); - QTreeWidgetItem *item = NULL; - while ((item = *itemIterator) != NULL) { - ++itemIterator; - - if (item->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString() == msgIdString) { - ui->threadTreeWidget->setCurrentItem(item); - ui->threadTreeWidget->setFocus(); - return true; - } - } -#endif - - return false; + ui->threadTreeWidget->setCurrentIndex(index); + ui->threadTreeWidget->setFocus(); + return true; } bool GxsForumThreadWidget::isLoading() @@ -2298,10 +2260,11 @@ void GxsForumThreadWidget::copyMessageLink() if (groupId().isNull() || mThreadId.isNull()) { return; } -#ifdef TODO - QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); - QString thread_title = (item != NULL)?item->text(RsGxsForumModel::COLUMN_THREAD_TITLE):QString() ; + ForumModelPostEntry fmpe ; + getCurrentPost(fmpe); + + QString thread_title = QString::fromUtf8(fmpe.mTitle.c_str()); RetroShareLink link = RetroShareLink::createGxsMessageLink(RetroShareLink::TYPE_FORUM, groupId(), mThreadId, thread_title); @@ -2310,7 +2273,6 @@ void GxsForumThreadWidget::copyMessageLink() urls.push_back(link); RSLinkClipboard::copyLinks(urls); } -#endif } void GxsForumThreadWidget::subscribeGroup(bool subscribe) From 581e892d94a7bd59c0b0ffa85da38e6f4f0f2cc0 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 26 Nov 2018 21:18:28 +0100 Subject: [PATCH 24/79] create an index iterator in ForumModel --- .../src/gui/gxsforums/GxsForumModel.cpp | 88 +++++++++++++++++-- .../src/gui/gxsforums/GxsForumModel.h | 19 ++++ 2 files changed, 99 insertions(+), 8 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 9a8a0005f..a8729f480 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -1040,22 +1040,94 @@ QModelIndex RsGxsForumModel::getIndexOfMessage(const RsGxsMessageId& mid) const QModelIndex RsGxsForumModel::getNextIndex(const QModelIndex& i,bool unread_only) const { -#ifdef TODO ForumModelIndex fmi ; convertRefPointerToTabEntry(i.internalPointer(),fmi); // Algorithm is simple: visit children recursively. When none available, go to parent. We need of course a stack of parents to the current index. - std::list parent_stack ; + const_iterator it(*this,fmi); - for(ForumModelIndex tmp(fmi);tmp!=0;tmp=mPosts[tmp].mParent) - parent_stack.push_front(tmp); + do {++it;} while(bool(it) && (!unread_only || IS_MSG_UNREAD(mPosts[*it].mMsgStatus))); - // now get to next unread item + if(!it) + return QModelIndex(); - if(!mPosts[fmi].mChildren.empty()) -#endif - return QModelIndex(); + void *ref ; + convertTabEntryToRefPointer(*it,ref); + + return createIndex(mPosts[*it].prow,0,ref); +} + + +RsGxsForumModel::const_iterator::const_iterator(const RsGxsForumModel &Model, ForumModelIndex i) + : model(Model) +{ + if(i >= model.mPosts.size()) + { + std::cerr << "(EE) constructed a RsGxsForumModel::const_iterator from invalid index " << i << std::endl; + kid = -1; + return; + } + // create a stack or parents + parent_stack.clear(); + + if(i==0) + { + current_parent = 0; + kid =0; + return; + } + current_parent = model.mPosts[i].mParent; + ForumModelIndex j(i); + kid = model.mPosts[i].prow; + + while(j != 0) + { + parent_stack.push_front(model.mPosts[j].prow); + j = model.mPosts[i].mParent; + } +} + +ForumModelIndex RsGxsForumModel::const_iterator::operator*() const +{ + if(current_parent >= model.mPosts.size() || kid < 0 || kid >= (int)model.mPosts[current_parent].mChildren.size()) + { + std::cerr << "(EE) operator* on an invalid RsGxsForumModel::const_iterator"<< std::endl; + return 0; + } + + return model.mPosts[current_parent].mChildren[kid]; +} + +void RsGxsForumModel::const_iterator::operator++() +{ + kid++; + while(kid >= (int)model.mPosts[current_parent].mChildren.size()) + { + current_parent = model.mPosts[current_parent].mParent; + kid = parent_stack.back()+1; + + parent_stack.pop_back(); + + } + + if(current_parent == 0 && kid >= (int)model.mPosts[current_parent].mChildren.size()) + { + kid = -1; + return; + } + + while(!model.mPosts[model.mPosts[current_parent].mChildren[kid]].mChildren.empty()) + { + parent_stack.push_back(kid); + current_parent = model.mPosts[current_parent].mChildren[kid]; + kid = 0; + } +} + +RsGxsForumModel::const_iterator::operator bool() const +{ + return kid >= 0; } void RsGxsForumModel::debug_dump() diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index 9f3468e7f..71218c8e8 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -83,6 +83,23 @@ public: QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const; QModelIndex getNextIndex(const QModelIndex& i,bool unread_only) const; + class const_iterator + { + public: + const_iterator(const RsGxsForumModel& Model,ForumModelIndex = 0) ; + + ForumModelIndex operator*() const ; + void operator++(); + + inline operator bool() const ; + + private: + std::list parent_stack; + int kid; + ForumModelIndex current_parent; + const RsGxsForumModel& model; + }; + // This method will asynchroneously update the data void setForum(const RsGxsGroupId& forumGroup); @@ -160,4 +177,6 @@ private: QColor mTextColorUnreadChildren; QColor mTextColorNotSubscribed ; QColor mTextColorMissing ; + + friend class const_iterator; }; From 3a76f2515252c77244c86a325bb7ad060353271a Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 26 Nov 2018 22:07:10 +0100 Subject: [PATCH 25/79] resurrected prev/next buttons --- .../src/gui/gxsforums/GxsForumModel.cpp | 42 ++++++---- .../src/gui/gxsforums/GxsForumModel.h | 1 + .../gui/gxsforums/GxsForumThreadWidget.cpp | 84 +++++++++++-------- 3 files changed, 77 insertions(+), 50 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index a8729f480..435cef0c2 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -494,7 +494,7 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector& entries,ForumModelIndex index,int depth) -{ - const ForumModelPostEntry& e(entries[index]); - - std::cerr << std::string(depth*2,' ') << e.mAuthorId.toStdString() << " " - << QString("%1").arg((uint32_t)e.mPostFlags,8,16,QChar('0')).toStdString() << " " - << QString("%1").arg((uint32_t)e.mMsgStatus,8,16,QChar('0')).toStdString() << " " - << QDateTime::fromSecsSinceEpoch(e.mPublishTs).toString().toStdString() << " \"" << e.mTitle << "\"" << std::endl; - - for(uint32_t i=0;i= 0; } +static void recursPrintModel(const std::vector& entries,ForumModelIndex index,int depth) +{ + const ForumModelPostEntry& e(entries[index]); + + std::cerr << std::string(depth*2,' ') << index << " : " << e.mAuthorId.toStdString() << " " + << QString("%1").arg((uint32_t)e.mPostFlags,8,16,QChar('0')).toStdString() << " " + << QString("%1").arg((uint32_t)e.mMsgStatus,8,16,QChar('0')).toStdString() << " " + << QDateTime::fromSecsSinceEpoch(e.mPublishTs).toString().toStdString() << " \"" << e.mTitle << "\"" << std::endl; + + for(uint32_t i=0;isetActive(mTokenTypeMessageData, true); #endif -#ifdef TODO - QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); + QModelIndex index = getCurrentIndex(); - if (item) { - QTreeWidgetItem *parentItem = item->parent(); - int index = parentItem ? parentItem->indexOfChild(item) : ui->threadTreeWidget->indexOfTopLevelItem(item); - int count = parentItem ? parentItem->childCount() : ui->threadTreeWidget->topLevelItemCount(); - mStateHelper->setWidgetEnabled(ui->previousButton, (index > 0)); - mStateHelper->setWidgetEnabled(ui->nextButton, (index < count - 1)); + if (index.isValid()) + { + QModelIndex parentIndex = index.parent(); + int curr_index = index.row(); + int count = mThreadModel->rowCount(parentIndex); + + ui->previousButton->setEnabled(curr_index > 0); + ui->nextButton->setEnabled(curr_index < count - 1); } else { // there is something wrong - mStateHelper->setWidgetEnabled(ui->previousButton, false); - mStateHelper->setWidgetEnabled(ui->nextButton, false); + ui->previousButton->setEnabled(false); + ui->nextButton->setEnabled(false); ui->versions_CB->hide(); ui->time_label->show(); return; } -#endif mStateHelper->setWidgetEnabled(ui->newmessageButton, (IS_GROUP_SUBSCRIBED(mSubscribeFlags) && mThreadId.isNull() == false)); @@ -1984,41 +1984,53 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) void GxsForumThreadWidget::previousMessage() { -#ifdef TODO - QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); - if (item == NULL) { - return; - } + QModelIndex current_index = getCurrentIndex(); - QTreeWidgetItem *parentItem = item->parent(); - int index = parentItem ? parentItem->indexOfChild(item) : ui->threadTreeWidget->indexOfTopLevelItem(item); - if (index > 0) { - QTreeWidgetItem *previousItem = parentItem ? parentItem->child(index - 1) : ui->threadTreeWidget->topLevelItem(index - 1); - if (previousItem) { - ui->threadTreeWidget->setCurrentItem(previousItem); + if (!current_index.isValid()) + return; + + QModelIndex parentIndex = current_index.parent(); + + int index = current_index.row(); + int count = mThreadModel->rowCount(parentIndex) ; + + if (index > 0) + { + QModelIndex prevItem = mThreadModel->index(index - 1,0,parentIndex) ; + + if (prevItem.isValid()) { + ui->threadTreeWidget->setCurrentIndex(prevItem); + ui->threadTreeWidget->setFocus(); } } -#endif + ui->previousButton->setEnabled(index-1 > 0); + ui->nextButton->setEnabled(true); + } void GxsForumThreadWidget::nextMessage() { -#ifdef TODO - QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); - if (item == NULL) { - return; - } + QModelIndex current_index = getCurrentIndex(); - QTreeWidgetItem *parentItem = item->parent(); - int index = parentItem ? parentItem->indexOfChild(item) : ui->threadTreeWidget->indexOfTopLevelItem(item); - int count = parentItem ? parentItem->childCount() : ui->threadTreeWidget->topLevelItemCount(); - if (index < count - 1) { - QTreeWidgetItem *nextItem = parentItem ? parentItem->child(index + 1) : ui->threadTreeWidget->topLevelItem(index + 1); - if (nextItem) { - ui->threadTreeWidget->setCurrentItem(nextItem); + if (!current_index.isValid()) + return; + + QModelIndex parentIndex = current_index.parent(); + + int index = current_index.row(); + int count = mThreadModel->rowCount(parentIndex) ; + + if (index < count - 1) + { + QModelIndex nextItem = mThreadModel->index(index + 1,0,parentIndex) ; + + if (nextItem.isValid()) { + ui->threadTreeWidget->setCurrentIndex(nextItem); + ui->threadTreeWidget->setFocus(); } } -#endif + ui->previousButton->setEnabled(true); + ui->nextButton->setEnabled(index+1 < count - 1); } void GxsForumThreadWidget::downloadAllFiles() From b179cb57965e7936b251267880e6fd9a8eae1dcc Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 26 Nov 2018 22:48:47 +0100 Subject: [PATCH 26/79] fixed next/prev item and next unread selection --- .../src/gui/gxsforums/GxsForumModel.cpp | 4 ++++ retroshare-gui/src/gui/gxsforums/GxsForumModel.h | 9 +++++---- .../src/gui/gxsforums/GxsForumThreadWidget.cpp | 15 ++++++++++++++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 435cef0c2..62542e799 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -281,6 +281,10 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const return QVariant(font); } + + if(role == UnreadChildrenRole) + return bool(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN); + #ifdef DEBUG_FORUMMODEL std::cerr << " [ok]" << std::endl; #endif diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index 9779263f7..c42ba9e1d 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -73,10 +73,11 @@ public: COLUMN_THREAD_NB_COLUMNS =0x08, }; - enum Roles{ SortRole = Qt::UserRole+1, - ThreadPinnedRole = Qt::UserRole+2, - MissingRole = Qt::UserRole+3, - StatusRole = Qt::UserRole+4, + enum Roles{ SortRole = Qt::UserRole+1, + ThreadPinnedRole = Qt::UserRole+2, + MissingRole = Qt::UserRole+3, + StatusRole = Qt::UserRole+4, + UnreadChildrenRole = Qt::UserRole+5, }; QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 2c95ff8e3..8760f9b00 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -2001,6 +2001,7 @@ void GxsForumThreadWidget::previousMessage() if (prevItem.isValid()) { ui->threadTreeWidget->setCurrentIndex(prevItem); ui->threadTreeWidget->setFocus(); + changedThread(prevItem); } } ui->previousButton->setEnabled(index-1 > 0); @@ -2027,6 +2028,7 @@ void GxsForumThreadWidget::nextMessage() if (nextItem.isValid()) { ui->threadTreeWidget->setCurrentIndex(nextItem); ui->threadTreeWidget->setFocus(); + changedThread(nextItem); } } ui->previousButton->setEnabled(true); @@ -2049,10 +2051,20 @@ void GxsForumThreadWidget::downloadAllFiles() void GxsForumThreadWidget::nextUnreadMessage() { - QModelIndex index = mThreadModel->getNextIndex(getCurrentIndex(),true); + QModelIndex index = getCurrentIndex(); + + do + { + if(index.data(RsGxsForumModel::UnreadChildrenRole).toBool()) + ui->threadTreeWidget->expand(index); + + index = ui->threadTreeWidget->indexBelow(index); + } + while(index.isValid() && !IS_MSG_UNREAD(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_DATA).data(RsGxsForumModel::StatusRole).toUInt())); ui->threadTreeWidget->setCurrentIndex(index); ui->threadTreeWidget->setFocus(); + changedThread(index); } #ifdef TO_REMOVE @@ -2255,6 +2267,7 @@ bool GxsForumThreadWidget::navigate(const RsGxsMessageId &msgId) ui->threadTreeWidget->setCurrentIndex(index); ui->threadTreeWidget->setFocus(); + changedThread(index); return true; } From 73e285805e9ca9009983b79344aff30d60cc0aed Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 26 Nov 2018 23:07:05 +0100 Subject: [PATCH 27/79] simplified comment in GxsIdDetails and hid columns in new ForumModel --- retroshare-gui/src/gui/gxs/GxsIdDetails.cpp | 6 +++--- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 2 ++ retroshare-gui/src/gui/gxsforums/GxsForumModel.h | 3 +++ retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp | 6 +++++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp index 16399aed1..fac557122 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp @@ -973,7 +973,7 @@ QString nickname ; if (details.mFlags & RS_IDENTITY_FLAGS_PGP_LINKED) { - comment += QString("
%1:%2 ").arg(QApplication::translate("GxsIdDetails", "Authentication"), QApplication::translate("GxsIdDetails", "Signed by")); + comment += QString("
%1: ").arg(QApplication::translate("GxsIdDetails", "Node")); if (details.mFlags & RS_IDENTITY_FLAGS_PGP_KNOWN) { @@ -985,8 +985,8 @@ QString nickname ; else comment += QApplication::translate("GxsIdDetails", "unknown Key"); } - else - comment += QString("
%1: %2").arg(QApplication::translate("GxsIdDetails", "Authentication"), QApplication::translate("GxsIdDetails", "anonymous")); + //else + // comment += QString("
%1: %2").arg(QApplication::translate("GxsIdDetails", "Node:"), QApplication::translate("GxsIdDetails", "anonymous")); if(details.mReputation.mFriendsPositiveVotes || details.mReputation.mFriendsNegativeVotes) { diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 62542e799..c52e89797 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -1029,6 +1029,7 @@ QModelIndex RsGxsForumModel::getIndexOfMessage(const RsGxsMessageId& mid) const return QModelIndex(); } +#ifdef TO_REMVOVE void RsGxsForumModel::test_iterator() const { const_iterator it(*this); @@ -1133,6 +1134,7 @@ RsGxsForumModel::const_iterator::operator bool() const { return kid >= 0; } +#endif static void recursPrintModel(const std::vector& entries,ForumModelIndex index,int depth) { diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index c42ba9e1d..12661c14c 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -82,6 +82,8 @@ public: QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const; + +#ifdef TO_REMOVE QModelIndex getNextIndex(const QModelIndex& i,bool unread_only) const; class const_iterator @@ -101,6 +103,7 @@ public: const RsGxsForumModel& model; }; void test_iterator() const; +#endif // This method will asynchroneously update the data void setForum(const RsGxsGroupId& forumGroup); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 8760f9b00..6bda288c7 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -350,7 +350,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->newmessageButton->setText(tr("Reply")); ui->newthreadButton->setText(tr("New thread")); - connect(ui->threadTreeWidget, SIGNAL(clicked(QModelIndex)), this, SLOT(changedThread(QModelIndex))); + //connect(ui->threadTreeWidget, SIGNAL(clicked(QModelIndex)), this, SLOT(changedThread(QModelIndex))); connect(ui->threadTreeWidget, SIGNAL(clicked(QModelIndex)), this, SLOT(clickedThread(QModelIndex))); connect(ui->viewBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changedViewBox())); @@ -409,6 +409,8 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_READ, 24*f); QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_READ, QHeaderView::Fixed); ttheader->hideSection (RsGxsForumModel::COLUMN_THREAD_CONTENT); + ttheader->hideSection (RsGxsForumModel::COLUMN_THREAD_MSGID); + ttheader->hideSection (RsGxsForumModel::COLUMN_THREAD_DATA); ui->progressBar->hide(); ui->progressText->hide(); @@ -929,6 +931,8 @@ void GxsForumThreadWidget::clickedThread(QModelIndex index) mThreadModel->getPostData(index,fmpe); mThreadModel->setMsgReadStatus(index, IS_MSG_UNREAD(fmpe.mMsgStatus),false); } + else + changedThread(index); } void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item, bool &hasReadChilddren, bool &hasUnreadChilddren) From c0e87dbb3ba943b3fe6891b31e7cc3f5a4d50ceb Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 27 Nov 2018 09:37:34 +0100 Subject: [PATCH 28/79] attempt at fixing column resize --- .../src/gui/gxsforums/GxsForumThreadWidget.cpp | 17 ++++++++++------- .../src/gui/gxsforums/GxsForumThreadWidget.ui | 3 +++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 6bda288c7..c406e6032 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -264,7 +264,7 @@ public: QPixmap pix = icon.pixmap(r.size()); // draw pixmap at center of item - const QPoint p = QPoint((r.width() - pix.width())/2, (r.height() - pix.height())/2); + const QPoint p = QPoint(pix.width()/2.0, (r.height() - pix.height())/2); painter->drawPixmap(r.topLeft() + p, pix); painter->drawText(r.topLeft() + p + QPoint(pix.width()+f/2.0,f*0.8), str); } @@ -371,13 +371,9 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget itemDelegate->setOnlyPlainText(true); ui->threadTreeWidget->setItemDelegate(itemDelegate); - /* Set header resize modes and initial section sizes */ - QHeaderView * ttheader = ui->threadTreeWidget->header () ; - QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_TITLE, QHeaderView::Interactive); - QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, QHeaderView::ResizeToContents); - float f = QFontMetricsF(font()).height()/14.0f ; + QHeaderView * ttheader = ui->threadTreeWidget->header () ; ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_DATE, 140*f); ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_TITLE, 440*f); ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, 24*f); @@ -405,9 +401,16 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget // load settings processSettings(true); + /* Set header resize modes and initial section sizes */ + QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_TITLE, QHeaderView::Interactive); + QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_READ, QHeaderView::Fixed); + QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_DATE, QHeaderView::Interactive); + QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, QHeaderView::ResizeToContents); + QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_AUTHOR, QHeaderView::Interactive); + ui->threadTreeWidget->header()->setCascadingSectionResizes(true); + /* Set header sizes for the fixed columns and resize modes, must be set after processSettings */ ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_READ, 24*f); - QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_READ, QHeaderView::Fixed); ttheader->hideSection (RsGxsForumModel::COLUMN_THREAD_CONTENT); ttheader->hideSection (RsGxsForumModel::COLUMN_THREAD_MSGID); ttheader->hideSection (RsGxsForumModel::COLUMN_THREAD_DATA); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui index fa372b940..ae79bd607 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui @@ -225,6 +225,9 @@ true + + true +
From 02c6a92f4844d59c05e446b9998778157ec2acdf Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 27 Nov 2018 10:13:03 +0100 Subject: [PATCH 29/79] fixed resizing+CPU bug due to inconsistent return in eventFilter() --- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 1 + retroshare-gui/src/gui/gxsforums/GxsForumModel.h | 6 +++++- .../src/gui/gxsforums/GxsForumThreadWidget.cpp | 13 +++++++++---- .../src/gui/gxsforums/GxsForumThreadWidget.h | 1 + 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index c52e89797..0546ca43b 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -503,6 +503,7 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vectornewmessageButton, SIGNAL(clicked()), this, SLOT(replytoforummessage())); connect(ui->newthreadButton, SIGNAL(clicked()), this, SLOT(createthread())); + connect(mThreadModel,SIGNAL(forumLoaded()),this,SLOT(updateGroupName())); + ui->newmessageButton->setText(tr("Reply")); ui->newthreadButton->setText(tr("New thread")); @@ -529,9 +531,8 @@ void GxsForumThreadWidget::processSettings(bool load) void GxsForumThreadWidget::groupIdChanged() { -#ifdef TO_REMOVE - ui->forumName->setText(groupId().isNull () ? "" : tr("Loading")); -#endif + ui->forumName->setText(groupId().isNull () ? "" : tr("Loading...")); + mNewCount = 0; mUnreadCount = 0; @@ -860,7 +861,7 @@ bool GxsForumThreadWidget::eventFilter(QObject *obj, QEvent *event) // pass the event on to the parent class return RsGxsUpdateBroadcastWidget::eventFilter(obj, event); #endif - return true; + return RsGxsUpdateBroadcastWidget::eventFilter(obj, event); } void GxsForumThreadWidget::togglethreadview() @@ -2674,6 +2675,10 @@ bool GxsForumThreadWidget::filterItem(QTreeWidgetItem *item, const QString &text /** Request / Response of Data ********************************/ /*********************** **** **** **** ***********************/ +void GxsForumThreadWidget::updateGroupName() +{ + ui->forumName->setText(QString::fromUtf8(mForumGroup.mMeta.mGroupName.c_str())); +} void GxsForumThreadWidget::updateGroupData() { mSubscribeFlags = 0; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index fc085e4d1..48df15759 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -103,6 +103,7 @@ private slots: void changedThread(QModelIndex index); void changedVersion(); void clickedThread (QModelIndex index); + void updateGroupName(); void reply_with_private_message(); void replytoforummessage(); From 561db00255d528ef266918ca3e64c21ce03f0d95 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 27 Nov 2018 15:15:54 +0100 Subject: [PATCH 30/79] resurrected sorting for pinned posts using a proxy model --- .../src/gui/gxsforums/GxsForumModel.cpp | 15 +++- .../src/gui/gxsforums/GxsForumModel.h | 1 + .../gui/gxsforums/GxsForumThreadWidget.cpp | 78 +++++++++++++++---- .../src/gui/gxsforums/GxsForumThreadWidget.h | 2 + 4 files changed, 76 insertions(+), 20 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 0546ca43b..04fbcb67e 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -276,9 +276,7 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const if(role == Qt::FontRole) { QFont font ; - - font.setBold(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN); - + font.setBold( (fmpe.mPostFlags & (ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN | ForumModelPostEntry::FLAG_POST_IS_PINNED))); return QVariant(font); } @@ -296,6 +294,7 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const case Qt::ToolTipRole: return toolTipRole (fmpe,index.column()) ; case Qt::UserRole: return userRole (fmpe,index.column()) ; case Qt::TextColorRole: return textColorRole (fmpe,index.column()) ; + case Qt::BackgroundRole: return backgroundRole(fmpe,index.column()) ; case ThreadPinnedRole: return pinnedRole (fmpe,index.column()) ; case MissingRole: return missingRole (fmpe,index.column()) ; @@ -310,7 +309,7 @@ QVariant RsGxsForumModel::textColorRole(const ForumModelPostEntry& fmpe,int colu if( (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING)) return QVariant(mTextColorMissing); - if(IS_MSG_UNREAD(fmpe.mMsgStatus)) + if(IS_MSG_UNREAD(fmpe.mMsgStatus) || (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED)) return QVariant(mTextColorUnread); else return QVariant(mTextColorRead); @@ -382,6 +381,13 @@ QVariant RsGxsForumModel::pinnedRole(const ForumModelPostEntry& fmpe,int column) return QVariant(false); } +QVariant RsGxsForumModel::backgroundRole(const ForumModelPostEntry& fmpe,int column) const +{ + if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) + return QVariant(QBrush(QColor(255,200,180))); + + return QVariant(); +} QVariant RsGxsForumModel::sizeHintRole(int col) const { @@ -393,6 +399,7 @@ QVariant RsGxsForumModel::sizeHintRole(int col) const case COLUMN_THREAD_TITLE: return QVariant( QSize(factor * 170, factor*14 )); case COLUMN_THREAD_DATE: return QVariant( QSize(factor * 75 , factor*14 )); case COLUMN_THREAD_AUTHOR: return QVariant( QSize(factor * 75 , factor*14 )); + case COLUMN_THREAD_DISTRIBUTION: return QVariant( QSize(factor * 15 , factor*14 )); } } diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index 83d81aca5..c5ada2d88 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -141,6 +141,7 @@ public: QVariant sortRole (const ForumModelPostEntry& fmpe, int col) const; QVariant fontRole (const ForumModelPostEntry& fmpe, int col) const; QVariant textColorRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant backgroundRole(const ForumModelPostEntry& fmpe, int col) const; /*! * \brief debug_dump diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 18511383d..b7df1cd07 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -270,6 +270,41 @@ public: } }; +class ForumPostSortFilterProxyModel: public QSortFilterProxyModel +{ +public: + ForumPostSortFilterProxyModel(const QHeaderView *header,QObject *parent = NULL): QSortFilterProxyModel(parent),m_header(header) {} + + bool lessThan(const QModelIndex& left, const QModelIndex& right) const override + { + bool left_is_not_pinned = ! left.data(ROLE_THREAD_PINNED).toBool(); + bool right_is_not_pinned = !right.data(ROLE_THREAD_PINNED).toBool(); +#ifdef DEBUG_PINNED_POST_SORTING + std::cerr << "Comparing item date \"" << data(RsGxsForumModel::COLUMN_THREAD_DATE,Qt::DisplayRole).toString().toStdString() << "\" (" + << data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toUInt() << ", \"" << data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toString().toStdString() << "\" --> " << left_is_not_pinned << ") to \"" + << other.data(RsGxsForumModel::COLUMN_THREAD_DATE,Qt::DisplayRole).toString().toStdString() << "\" (" + << other.data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toUInt() << ", \"" << other.data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toString().toStdString() << "\" --> " << right_is_not_pinned << ") "; +#endif + + if(left_is_not_pinned ^ right_is_not_pinned) + { +#ifdef DEBUG_PINNED_POST_SORTING + std::cerr << "Local: " << ((m_header->sortIndicatorOrder()==Qt::AscendingOrder)?right_is_not_pinned:left_is_not_pinned) << std::endl; +#endif + return (m_header->sortIndicatorOrder()==Qt::AscendingOrder)?right_is_not_pinned:left_is_not_pinned ; // always put pinned posts on top + } + +#ifdef DEBUG_PINNED_POST_SORTING + std::cerr << "Remote: " << GxsIdRSTreeWidgetItem::operator<(other) << std::endl; +#endif + return left.data(RsGxsForumModel::SortRole) < right.data(RsGxsForumModel::SortRole) ; + } + +private: + const QHeaderView *m_header ; +}; + + void GxsForumThreadWidget::setTextColorRead (QColor color) { mTextColorRead = color; mThreadModel->setTextColorRead (color);} void GxsForumThreadWidget::setTextColorUnread (QColor color) { mTextColorUnread = color; mThreadModel->setTextColorUnread (color);} void GxsForumThreadWidget::setTextColorUnreadChildren(QColor color) { mTextColorUnreadChildren = color; mThreadModel->setTextColorUnreadChildren(color);} @@ -329,11 +364,17 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mInMsgAsReadUnread = false; - mThreadCompareRole = new RSTreeWidgetItemCompareRole; - mThreadCompareRole->setRole(RsGxsForumModel::COLUMN_THREAD_DATE, ROLE_THREAD_SORT); + //mThreadCompareRole = new RSTreeWidgetItemCompareRole; + //mThreadCompareRole->setRole(RsGxsForumModel::COLUMN_THREAD_DATE, ROLE_THREAD_SORT); + + ui->threadTreeWidget->setSortingEnabled(true); mThreadModel = new RsGxsForumModel(this); - ui->threadTreeWidget->setModel(mThreadModel); + mThreadProxyModel = new ForumPostSortFilterProxyModel(ui->threadTreeWidget->header(),this); + mThreadProxyModel->setSourceModel(mThreadModel); + ui->threadTreeWidget->setModel(mThreadProxyModel); + + ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,new DistributionItemDelegate()) ; ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_AUTHOR,new AuthorItemDelegate()) ; ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_READ,new ReadStatusItemDelegate()) ; @@ -442,8 +483,8 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget #ifdef SUSPENDED_CODE ui->threadTreeWidget->enableColumnCustomize(true); - ui->threadTreeWidget->sortItems(RsGxsForumModel::COLUMN_THREAD_DATE, Qt::DescendingOrder); #endif + ui->threadTreeWidget->sortByColumn(RsGxsForumModel::COLUMN_THREAD_DATE, Qt::DescendingOrder); } void GxsForumThreadWidget::blank() @@ -671,7 +712,7 @@ bool GxsForumThreadWidget::getCurrentPost(ForumModelPostEntry& fmpe) const if(!index.isValid()) return false ; - return mThreadModel->getPostData(index,fmpe); + return mThreadModel->getPostData(mThreadProxyModel->mapToSource(index),fmpe); } void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) @@ -905,14 +946,16 @@ void GxsForumThreadWidget::changedThread(QModelIndex index) return; } - mThreadId = mOrigThreadId = RsGxsMessageId(mThreadModel->data(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_MSGID),Qt::UserRole).toString().toStdString()); + mThreadId = mOrigThreadId = RsGxsMessageId(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_MSGID).data(Qt::UserRole).toString().toStdString()); std::cerr << "Switched to new thread ID " << mThreadId << std::endl; //ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages()) ; insertMessage(); - mThreadModel->setMsgReadStatus(index, true,false); + + QModelIndex src_index = mThreadProxyModel->mapToSource(index); + mThreadModel->setMsgReadStatus(src_index, true,false); } void GxsForumThreadWidget::clickedThread(QModelIndex index) @@ -932,8 +975,11 @@ void GxsForumThreadWidget::clickedThread(QModelIndex index) if (index.column() == RsGxsForumModel::COLUMN_THREAD_READ) { ForumModelPostEntry fmpe; - mThreadModel->getPostData(index,fmpe); - mThreadModel->setMsgReadStatus(index, IS_MSG_UNREAD(fmpe.mMsgStatus),false); + + QModelIndex src_index = mThreadProxyModel->mapToSource(index); + + mThreadModel->getPostData(src_index,fmpe); + mThreadModel->setMsgReadStatus(src_index, IS_MSG_UNREAD(fmpe.mMsgStatus),false); } else changedThread(index); @@ -1837,7 +1883,7 @@ void GxsForumThreadWidget::insertMessage() if (index.isValid()) { - QModelIndex parentIndex = index.parent(); + QModelIndex parentIndex = mThreadProxyModel->mapToSource(index).parent(); int curr_index = index.row(); int count = mThreadModel->rowCount(parentIndex); @@ -1950,15 +1996,15 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) if (IS_MSG_NEW(status)) { if (setToReadOnActive) { /* set to read */ - mThreadModel->setMsgReadStatus(index,true,false); + mThreadModel->setMsgReadStatus(mThreadProxyModel->mapToSource(index),true,false); } else { /* set to unread by user */ - mThreadModel->setMsgReadStatus(index,false,false); + mThreadModel->setMsgReadStatus(mThreadProxyModel->mapToSource(index),false,false); } } else { if (setToReadOnActive && IS_MSG_UNREAD(status)) { /* set to read */ - mThreadModel->setMsgReadStatus(index, true,false); + mThreadModel->setMsgReadStatus(mThreadProxyModel->mapToSource(index), true,false); } } @@ -2004,7 +2050,7 @@ void GxsForumThreadWidget::previousMessage() if (index > 0) { - QModelIndex prevItem = mThreadModel->index(index - 1,0,parentIndex) ; + QModelIndex prevItem = mThreadProxyModel->index(index - 1,0,parentIndex) ; if (prevItem.isValid()) { ui->threadTreeWidget->setCurrentIndex(prevItem); @@ -2027,11 +2073,11 @@ void GxsForumThreadWidget::nextMessage() QModelIndex parentIndex = current_index.parent(); int index = current_index.row(); - int count = mThreadModel->rowCount(parentIndex) ; + int count = mThreadProxyModel->rowCount(parentIndex); if (index < count - 1) { - QModelIndex nextItem = mThreadModel->index(index + 1,0,parentIndex) ; + QModelIndex nextItem = mThreadProxyModel->index(index + 1,0,parentIndex) ; if (nextItem.isValid()) { ui->threadTreeWidget->setCurrentIndex(nextItem); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 48df15759..426b56456 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -27,6 +27,7 @@ #include #include "gui/gxs/GxsIdDetails.h" +class QSortFilterProxyModel; class QTreeWidgetItem; class RSTreeWidgetItemCompareRole; class RsGxsForumMsg; @@ -239,6 +240,7 @@ private: QMap > > mPostVersions ; // holds older versions of posts RsGxsForumModel *mThreadModel; + QSortFilterProxyModel *mThreadProxyModel; Ui::GxsForumThreadWidget *ui; }; From 23302ea469d1ca8f728408243047bbf8d9aad1cb Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 27 Nov 2018 19:21:49 +0100 Subject: [PATCH 31/79] partly resurrected post versions --- .../src/gui/gxsforums/GxsForumModel.cpp | 64 ++++++++++++------- .../src/gui/gxsforums/GxsForumModel.h | 7 +- .../gui/gxsforums/GxsForumThreadWidget.cpp | 35 +++++----- .../src/gui/gxsforums/GxsForumThreadWidget.h | 2 - 4 files changed, 65 insertions(+), 43 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 04fbcb67e..2e960df90 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -48,11 +48,22 @@ int RsGxsForumModel::rowCount(const QModelIndex& parent) const else return getChildrenCount(parent.internalPointer()); } + int RsGxsForumModel::columnCount(const QModelIndex &parent) const { return COLUMN_THREAD_NB_COLUMNS ; } +std::vector > RsGxsForumModel::getPostVersions(const RsGxsMessageId& mid) const +{ + auto it = mPostVersions.find(mid); + + if(it != mPostVersions.end()) + return it->second; + else + return std::vector >(); +} + bool RsGxsForumModel::getPostData(const QModelIndex& i,ForumModelPostEntry& fmpe) const { if(!i.isValid()) @@ -488,12 +499,13 @@ void RsGxsForumModel::setForum(const RsGxsGroupId& forum_group_id) update_posts(forum_group_id); } -void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector& posts) +void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector& posts,const std::map > >& post_versions) { emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); mForumGroup = group; mPosts = posts; + mPostVersions = post_versions; // now update prow for all posts @@ -539,14 +551,15 @@ void RsGxsForumModel::update_posts(const RsGxsGroupId& group_id) // 2 - sort the messages into a proper hierarchy + auto post_versions = new std::map > >() ; std::vector *vect = new std::vector(); RsGxsForumGroup group = groups[0]; - computeMessagesHierarchy(group,messages,*vect); + computeMessagesHierarchy(group,messages,*vect,*post_versions); // 3 - update the model in the UI thread. - RsQThreadUtils::postToObject( [group,vect,this]() + RsQThreadUtils::postToObject( [group,vect,post_versions,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 @@ -554,8 +567,10 @@ void RsGxsForumModel::update_posts(const RsGxsGroupId& group_id) * Qt::QueuedConnection is important! */ - setPosts(group,*vect) ; + setPosts(group,*vect,*post_versions) ; + delete vect; + delete post_versions; }, this ); @@ -651,11 +666,13 @@ void RsGxsForumModel::convertMsgToPostEntry(const RsGxsForumGroup& mForumGroup,c #endif } -static bool decreasing_time_comp(const QPair& e1,const QPair& e2) { return e2.first < e1.first ; } +static bool decreasing_time_comp(const std::pair& e1,const std::pair& e2) { return e2.first < e1.first ; } void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_group, const std::vector& msgs_array, - std::vector& posts) + std::vector& posts, + std::map > >& mPostVersions + ) { std::cerr << "updating messages data with " << msgs_array.size() << " messages" << std::endl; @@ -687,7 +704,6 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou int step = 0; initEmptyHierarchy(posts); - QMap > > mPostVersions ; // ThreadList contains the list of parent threads. The algorithm below iterates through all messages // and tries to establish parenthood relationships between them, given that we only know the @@ -740,31 +756,31 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou // always add the post a self version if(mPostVersions[msgIt->second.mMeta.mOrigMsgId].empty()) - mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(QPair(msgIt2->second.mMeta.mPublishTs,msgIt2->second.mMeta.mMsgId)) ; + mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(std::make_pair(msgIt2->second.mMeta.mPublishTs,msgIt2->second.mMeta.mMsgId)) ; - mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(QPair(msgIt->second.mMeta.mPublishTs,msgIt->second.mMeta.mMsgId)) ; + mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(std::make_pair(msgIt->second.mMeta.mPublishTs,msgIt->second.mMeta.mMsgId)) ; } } // The following code assembles all new versions of a given post into the same array, indexed by the oldest version of the post. - for(QMap > >::iterator it(mPostVersions.begin());it!=mPostVersions.end();++it) + for(auto it(mPostVersions.begin());it!=mPostVersions.end();++it) { - QVector >& v(*it) ; + auto& v(it->second) ; for(int32_t i=0;ifirst) { RsGxsMessageId sub_msg_id = v[i].second ; - QMap > >::iterator it2 = mPostVersions.find(sub_msg_id); + auto it2 = mPostVersions.find(sub_msg_id); if(it2 != mPostVersions.end()) { - for(int32_t j=0;j<(*it2).size();++j) - if((*it2)[j].second != sub_msg_id) // dont copy it, since it is already present at slot i - v.append((*it2)[j]) ; + for(int32_t j=0;jsecond.size();++j) + if(it2->second[j].second != sub_msg_id) // dont copy it, since it is already present at slot i + v.push_back(it2->second[j]) ; mPostVersions.erase(it2) ; // it2 is never equal to it } @@ -779,37 +795,37 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou #ifdef DEBUG_FORUMS std::cerr << "Final post versions: " << std::endl; #endif - QMap > > mTmp; + std::map > > mTmp; std::map most_recent_versions ; - for(QMap > >::iterator it(mPostVersions.begin());it!=mPostVersions.end();++it) + for(auto it(mPostVersions.begin());it!=mPostVersions.end();++it) { #ifdef DEBUG_FORUMS std::cerr << "Original post: " << it.key() << std::endl; #endif // Finally, sort the posts from newer to older - qSort((*it).begin(),(*it).end(),decreasing_time_comp) ; + std::sort(it->second.begin(),it->second.end(),decreasing_time_comp) ; #ifdef DEBUG_FORUMS std::cerr << " most recent version " << (*it)[0].first << " " << (*it)[0].second << std::endl; #endif - for(int32_t i=1;i<(*it).size();++i) + for(int32_t i=1;isecond.size();++i) { - msgs.erase((*it)[i].second) ; + msgs.erase(it->second[i].second) ; #ifdef DEBUG_FORUMS std::cerr << " older version " << (*it)[i].first << " " << (*it)[i].second << std::endl; #endif } - mTmp[(*it)[0].second] = *it ; // index the versions map by the ID of the most recent post. + mTmp[it->second[0].second] = it->second ; // index the versions map by the ID of the most recent post. // Now make sure that message parents are consistent. Indeed, an old post may have the old version of a post as parent. So we need to change that parent // to the newest version. So we create a map of which is the most recent version of each message, so that parent messages can be searched in it. - for(int i=1;i<(*it).size();++i) - most_recent_versions[(*it)[i].second] = (*it)[0].second ; + for(int i=1;isecond.size();++i) + most_recent_versions[it->second[i].second] = it->second[0].second ; } mPostVersions = mTmp ; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index c5ada2d88..78fd9f6e3 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -83,6 +83,8 @@ public: QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const; + std::vector > getPostVersions(const RsGxsMessageId& mid) const; + #ifdef TO_REMOVE QModelIndex getNextIndex(const QModelIndex& i,bool unread_only) const; @@ -176,11 +178,12 @@ private: static ForumModelIndex addEntry(std::vector& posts,const ForumModelPostEntry& entry,ForumModelIndex parent); static void convertMsgToPostEntry(const RsGxsForumGroup &mForumGroup, const RsGxsForumMsg& msg, bool useChildTS, uint32_t filterColumn, ForumModelPostEntry& fentry); - void computeMessagesHierarchy(const RsGxsForumGroup& forum_group,const std::vector& msgs_array,std::vector& posts); - void setPosts(const RsGxsForumGroup &group, const std::vector& posts); // this method *must* be called from UI thread. + void computeMessagesHierarchy(const RsGxsForumGroup& forum_group, const std::vector& msgs_array, std::vector& posts, std::map > > &mPostVersions); + void setPosts(const RsGxsForumGroup& group, const std::vector& posts,const std::map > >& post_versions); void initEmptyHierarchy(std::vector& posts); std::vector mPosts ; // store the list of posts updated from rsForums. + std::map > > mPostVersions; QColor mTextColorRead ; QColor mTextColorUnread ; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index b7df1cd07..a5c5c4ce7 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -484,7 +484,6 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->threadTreeWidget->enableColumnCustomize(true); #endif - ui->threadTreeWidget->sortByColumn(RsGxsForumModel::COLUMN_THREAD_DATE, Qt::DescendingOrder); } void GxsForumThreadWidget::blank() @@ -1883,9 +1882,9 @@ void GxsForumThreadWidget::insertMessage() if (index.isValid()) { - QModelIndex parentIndex = mThreadProxyModel->mapToSource(index).parent(); + QModelIndex parentIndex = index.parent(); int curr_index = index.row(); - int count = mThreadModel->rowCount(parentIndex); + int count = mThreadProxyModel->rowCount(parentIndex); ui->previousButton->setEnabled(curr_index > 0); ui->nextButton->setEnabled(curr_index < count - 1); @@ -1911,32 +1910,31 @@ void GxsForumThreadWidget::insertMessage() // add/show combobox for versions, if applicable, and enable it. If no older versions of the post available, hide the combobox. - std::cerr << "Looking into existing versions for post " << mThreadId << ", thread history: " << mPostVersions.size() << std::endl; -#ifdef TODO - QMap > >::const_iterator it = mPostVersions.find(mOrigThreadId) ; + std::vector > post_versions = mThreadModel->getPostVersions(mThreadId); + std::cerr << "Looking into existing versions for post " << mThreadId << ", thread history: " << post_versions.size() << std::endl; ui->versions_CB->blockSignals(true) ; while(ui->versions_CB->count() > 0) ui->versions_CB->removeItem(0); - if(it != mPostVersions.end()) + if(!post_versions.empty()) { - std::cerr << (*it).size() << " versions found " << std::endl; + std::cerr << post_versions.size() << " versions found " << std::endl; ui->versions_CB->setVisible(true) ; ui->time_label->hide(); int current_index = 0 ; - for(int i=0;i<(*it).size();++i) + for(int i=0;iversions_CB->insertItem(i, ((i==0)?tr("(Latest) "):tr("(Old) "))+" "+DateTime::formatLongDateTime( (*it)[i].first)); - ui->versions_CB->setItemData(i,QString::fromStdString((*it)[i].second.toStdString())); + ui->versions_CB->insertItem(i, ((i==0)?tr("(Latest) "):tr("(Old) "))+" "+DateTime::formatLongDateTime( post_versions[i].first)); + ui->versions_CB->setItemData(i,QString::fromStdString(post_versions[i].second.toStdString())); - std::cerr << " added new post version " << (*it)[i].first << " " << (*it)[i].second << std::endl; + std::cerr << " added new post version " << post_versions[i].first << " " << post_versions[i].second << std::endl; - if(mThreadId == (*it)[i].second) + if(mThreadId == post_versions[i].second) current_index = i ; } @@ -1947,7 +1945,6 @@ void GxsForumThreadWidget::insertMessage() ui->versions_CB->hide(); ui->time_label->show(); } -#endif ui->versions_CB->blockSignals(false) ; @@ -2238,7 +2235,7 @@ void GxsForumThreadWidget::markMsgAsReadUnread (bool read, bool children, bool f QModelIndex index = *selectedIndexes.begin(); - mThreadModel->setMsgReadStatus(index,read,children); + mThreadModel->setMsgReadStatus(mThreadProxyModel->mapToSource(index),read,children); } #ifdef TODO @@ -2723,13 +2720,21 @@ bool GxsForumThreadWidget::filterItem(QTreeWidgetItem *item, const QString &text void GxsForumThreadWidget::updateGroupName() { + ui->threadTreeWidget->selectionModel()->clear(); + ui->threadTreeWidget->selectionModel()->reset(); + mThreadId.clear(); ui->forumName->setText(QString::fromUtf8(mForumGroup.mMeta.mGroupName.c_str())); + ui->threadTreeWidget->sortByColumn(RsGxsForumModel::COLUMN_THREAD_DATE, Qt::DescendingOrder); + ui->threadTreeWidget->update(); } void GxsForumThreadWidget::updateGroupData() { mSubscribeFlags = 0; mSignFlags = 0; + mThreadId.clear(); mForumDescription.clear(); + ui->threadTreeWidget->selectionModel()->clear(); + ui->threadTreeWidget->selectionModel()->reset(); emit groupChanged(this); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 426b56456..44ef20f75 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -237,8 +237,6 @@ private: RsGxsMessageId mNavigatePendingMsgId; QList mIgnoredMsgId; - QMap > > mPostVersions ; // holds older versions of posts - RsGxsForumModel *mThreadModel; QSortFilterProxyModel *mThreadProxyModel; From ed68d720aa3724637e0656ed2b59d3a6d071ed71 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 27 Nov 2018 20:43:09 +0100 Subject: [PATCH 32/79] fixed post versionning --- retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index a5c5c4ce7..9d8fa6824 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -968,6 +968,7 @@ void GxsForumThreadWidget::clickedThread(QModelIndex index) return; mThreadId = tmp; + mOrigThreadId = tmp; std::cerr << "Clicked on message ID " << mThreadId << std::endl; @@ -1910,7 +1911,7 @@ void GxsForumThreadWidget::insertMessage() // add/show combobox for versions, if applicable, and enable it. If no older versions of the post available, hide the combobox. - std::vector > post_versions = mThreadModel->getPostVersions(mThreadId); + std::vector > post_versions = mThreadModel->getPostVersions(mOrigThreadId); std::cerr << "Looking into existing versions for post " << mThreadId << ", thread history: " << post_versions.size() << std::endl; ui->versions_CB->blockSignals(true) ; From ccdfc3cbf3998b2d4ee29f2231147efc61b7f647 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 27 Nov 2018 22:24:18 +0100 Subject: [PATCH 33/79] cleaned up removed code in Forum Model --- .../src/gui/gxsforums/GxsForumModel.cpp | 4 +- .../gui/gxsforums/GxsForumThreadWidget.cpp | 59 ++++++++++--------- .../src/gui/gxsforums/GxsForumThreadWidget.h | 11 ++-- .../src/gui/gxsforums/GxsForumsFillThread.cpp | 2 + .../src/gui/gxsforums/GxsForumsFillThread.h | 2 + 5 files changed, 43 insertions(+), 35 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 2e960df90..b819e1970 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -491,8 +491,8 @@ QVariant RsGxsForumModel::decorationRole(const ForumModelPostEntry& fmpe,int col void RsGxsForumModel::setForum(const RsGxsGroupId& forum_group_id) { - if(mForumGroup.mMeta.mGroupId == forum_group_id) - return ; + //if(mForumGroup.mMeta.mGroupId == forum_group_id) + // return ; // we do not set mForumGroupId yet. We'll do it when the forum data is updated. diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 9d8fa6824..d9162ce56 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -367,18 +367,19 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget //mThreadCompareRole = new RSTreeWidgetItemCompareRole; //mThreadCompareRole->setRole(RsGxsForumModel::COLUMN_THREAD_DATE, ROLE_THREAD_SORT); - ui->threadTreeWidget->setSortingEnabled(true); - mThreadModel = new RsGxsForumModel(this); mThreadProxyModel = new ForumPostSortFilterProxyModel(ui->threadTreeWidget->header(),this); mThreadProxyModel->setSourceModel(mThreadModel); ui->threadTreeWidget->setModel(mThreadProxyModel); + ui->threadTreeWidget->setSortingEnabled(true); ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,new DistributionItemDelegate()) ; ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_AUTHOR,new AuthorItemDelegate()) ; ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_READ,new ReadStatusItemDelegate()) ; + connect(ui->threadTreeWidget->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),this,SLOT(sortColumn(int,Qt::SortOrder))); + connect(ui->versions_CB, SIGNAL(currentIndexChanged(int)), this, SLOT(changedVersion())); connect(ui->threadTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(threadListCustomPopupMenu(QPoint))); connect(ui->postText, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuTextBrowser(QPoint))); @@ -486,6 +487,11 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget #endif } +void GxsForumThreadWidget::sortColumn(int col,Qt::SortOrder o) +{ + ui->threadTreeWidget->sortByColumn(col,o); +} + void GxsForumThreadWidget::blank() { ui->progressBar->hide(); @@ -514,18 +520,19 @@ void GxsForumThreadWidget::blank() GxsForumThreadWidget::~GxsForumThreadWidget() { +#ifdef TO_REMOVE if (mFillThread) { mFillThread->stop(); delete(mFillThread); mFillThread = NULL; } + delete(mThreadCompareRole); +#endif // save settings processSettings(false); delete ui; - - delete(mThreadCompareRole); } void GxsForumThreadWidget::processSettings(bool load) @@ -609,7 +616,7 @@ void GxsForumThreadWidget::changeEvent(QEvent *e) RsGxsUpdateBroadcastWidget::changeEvent(e); switch (e->type()) { case QEvent::StyleChange: - calculateIconsAndFonts(); + //calculateIconsAndFonts(); break; default: // remove compiler warnings @@ -929,9 +936,11 @@ void GxsForumThreadWidget::changedVersion() { mThreadId = RsGxsMessageId(ui->versions_CB->itemData(ui->versions_CB->currentIndex()).toString().toStdString()) ; +#ifdef TO_REMOVE if (mFillThread) { return; } +#endif ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages()) ; insertMessage(); } @@ -985,9 +994,9 @@ void GxsForumThreadWidget::clickedThread(QModelIndex index) changedThread(index); } +#ifdef TO_REMOVE void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item, bool &hasReadChilddren, bool &hasUnreadChilddren) { -#ifdef TODO uint32_t status = item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); bool isNew = IS_MSG_NEW(status); @@ -1062,12 +1071,10 @@ void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item, bool &h hasReadChilddren = hasReadChilddren || myReadChilddren || !unread; hasUnreadChilddren = hasUnreadChilddren || myUnreadChilddren || unread; -#endif } void GxsForumThreadWidget::calculateUnreadCount() { -#ifdef TODO unsigned int unreadCount = 0; unsigned int newCount = 0; @@ -1098,12 +1105,10 @@ void GxsForumThreadWidget::calculateUnreadCount() if (changed) { emit groupChanged(this); } -#endif } void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item /*= NULL*/) { -#ifdef TODO bool dummy1 = false; bool dummy2 = false; @@ -1120,8 +1125,8 @@ void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item /*= NULL dummy2 = false; calculateIconsAndFonts(ui->threadTreeWidget->topLevelItem(index), dummy1, dummy2); } -#endif } +#endif static void cleanupItems (QList &items) { @@ -1134,6 +1139,7 @@ static void cleanupItems (QList &items) items.clear(); } +#ifdef TO_REMOVE void GxsForumThreadWidget::insertGroupData() { #ifdef DEBUG_FORUMS @@ -1142,6 +1148,7 @@ void GxsForumThreadWidget::insertGroupData() //GxsIdDetails::process(mForumGroup.mMeta.mAuthorId, &loadAuthorIdCallback, this); calculateIconsAndFonts(); } +#endif static QString getDurationString(uint32_t days) { @@ -1159,6 +1166,7 @@ static QString getDurationString(uint32_t days) } } +#ifdef TO_REMOVE /*static*/ void GxsForumThreadWidget::loadAuthorIdCallback(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &) { GxsForumThreadWidget *tw = dynamic_cast(object); @@ -1274,7 +1282,6 @@ static QString getDurationString(uint32_t days) void GxsForumThreadWidget::fillThreadFinished() { -#ifdef TODO #ifdef DEBUG_FORUMS std::cerr << "GxsForumThreadWidget::fillThreadFinished" << std::endl; #endif @@ -1393,7 +1400,6 @@ void GxsForumThreadWidget::fillThreadFinished() #ifdef DEBUG_FORUMS std::cerr << "GxsForumThreadWidget::fillThreadFinished done" << std::endl; #endif -#endif } void GxsForumThreadWidget::fillThreadProgress(int current, int count) @@ -1598,7 +1604,6 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum return item; } -#ifdef TO_REMOVE void GxsForumThreadWidget::insertThreads() { #ifdef DEBUG_FORUMS @@ -1913,7 +1918,7 @@ void GxsForumThreadWidget::insertMessage() std::vector > post_versions = mThreadModel->getPostVersions(mOrigThreadId); - std::cerr << "Looking into existing versions for post " << mThreadId << ", thread history: " << post_versions.size() << std::endl; + std::cerr << "Looking into existing versions for post " << mOrigThreadId << ", thread history: " << post_versions.size() << std::endl; ui->versions_CB->blockSignals(true) ; while(ui->versions_CB->count() > 0) @@ -1950,7 +1955,6 @@ void GxsForumThreadWidget::insertMessage() ui->versions_CB->blockSignals(false) ; /* request Post */ - //RsGxsGrpMsgIdPair msgId = std::make_pair(groupId(), mThreadId); updateMessageData(mThreadId); markMsgAsRead(); @@ -1971,9 +1975,10 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) std::cerr << "\t or CurrThdId: " << mThreadId << " != msg.MsgId: " << msg.mMeta.mMsgId; std::cerr << std::endl; std::cerr << std::endl; - +#ifdef TO_REMOVE mStateHelper->setActive(mTokenTypeMessageData, false); mStateHelper->clear(mTokenTypeMessageData); +#endif return; } @@ -1981,10 +1986,12 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) uint32_t overall_reputation = rsReputations->overallReputationLevel(msg.mMeta.mAuthorId) ; bool redacted = (overall_reputation == RsReputations::REPUTATION_LOCALLY_NEGATIVE) ; +#ifdef TO_REMOVE mStateHelper->setActive(mTokenTypeMessageData, true); //mThreadId = mOrigThreadId = RsGxsMessageId(mThreadModel->data(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_MSGID),Qt::DisplayRole).toString().toStdString()); //QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); +#endif bool setToReadOnActive = Settings->getForumMsgSetToReadOnActivate(); uint32_t status = msg.mMeta.mMsgStatus ;//item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); @@ -2360,7 +2367,6 @@ void GxsForumThreadWidget::subscribeGroup(bool subscribe) uint32_t token; rsGxsForums->subscribeToGroup(token, groupId(), subscribe); -// mTokenQueue->queueRequest(token, 0, RS_TOKREQ_ANSTYPE_ACK, TOKEN_TYPE_SUBSCRIBE_CHANGE); } void GxsForumThreadWidget::createmessage() @@ -2377,21 +2383,20 @@ void GxsForumThreadWidget::createmessage() void GxsForumThreadWidget::togglePinUpPost() { -#ifdef TODO - if (groupId().isNull() || mThreadId.isNull()) + if (groupId().isNull() || mOrigThreadId.isNull()) return; - QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); + QModelIndex index = getCurrentIndex(); // normally this method is only called on top level items. We still check it just in case... - if(item->parent() != NULL) + if(mThreadProxyModel->mapToSource(index).parent() != mThreadModel->root()) { std::cerr << "(EE) togglePinUpPost() called on non top level post. This is inconsistent." << std::endl; return ; } - QString thread_title = (item != NULL)?item->text(RsGxsForumModel::COLUMN_THREAD_TITLE):QString() ; + QString thread_title = index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_TITLE).data(Qt::DisplayRole).toString(); std::cerr << "Toggling Pin-up state of post " << mThreadId.toStdString() << ": \"" << thread_title.toStdString() << "\"" << std::endl; @@ -2403,9 +2408,8 @@ void GxsForumThreadWidget::togglePinUpPost() uint32_t token; rsGxsForums->updateGroup(token,mForumGroup); - ui->threadTreeWidget->takeTopLevelItem(ui->threadTreeWidget->indexOfTopLevelItem(item)); // forces the re-creation of all posts widgets. A bit extreme. We should rather only delete item above + groupIdChanged(); // reloads all posts. We could also update the model directly, but the cost is so small now ;-) updateDisplay(true) ; -#endif } void GxsForumThreadWidget::createthread() @@ -2736,6 +2740,7 @@ void GxsForumThreadWidget::updateGroupData() mForumDescription.clear(); ui->threadTreeWidget->selectionModel()->clear(); ui->threadTreeWidget->selectionModel()->reset(); + mThreadProxyModel->clear(); emit groupChanged(this); @@ -3164,7 +3169,6 @@ void GxsForumThreadWidget::loadMsgData_SetAuthorOpinion(const uint32_t &token,Rs std::cerr << __PRETTY_FUNCTION__ << ": need to implement the update of GxsTreeWidgetItems icons too." << std::endl; } -#endif /*********************** **** **** **** ***********************/ /*********************** **** **** **** ***********************/ @@ -3177,7 +3181,6 @@ void GxsForumThreadWidget::loadRequest(const TokenQueue *queue, const TokenReque if (queue == mTokenQueue) { -#ifdef TO_REMOVE /* now switch on req */ if (req.mUserType == mTokenTypeGroupData) { loadGroupData(req.mToken); @@ -3221,7 +3224,6 @@ void GxsForumThreadWidget::loadRequest(const TokenQueue *queue, const TokenReque loadMsgData_SetAuthorOpinion(req.mToken,RsReputations::OPINION_NEUTRAL); return; } -#endif } GxsMessageFrameWidget::loadRequest(queue, req); @@ -3231,3 +3233,4 @@ QTreeWidgetItem *GxsForumThreadWidget::generateMissingItem(const RsGxsMessageId& { return NULL; } +#endif diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 44ef20f75..547be9435 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -79,11 +79,10 @@ public: unsigned int newCount() { return mNewCount; } unsigned int unreadCount() { return mUnreadCount; } - QTreeWidgetItem *convertMsgToThreadWidget(const RsGxsForumMsg &msg, bool useChildTS, uint32_t filterColumn, QTreeWidgetItem *parent); QTreeWidgetItem *generateMissingItem(const RsGxsMessageId &msgId); // Callback for all Loads. - virtual void loadRequest(const TokenQueue *queue, const TokenRequest &req); + //virtual void loadRequest(const TokenQueue *queue, const TokenRequest &req); virtual void blank(); protected: @@ -100,6 +99,7 @@ private slots: /** Create the context popup menu and it's submenus */ void threadListCustomPopupMenu(QPoint point); void contextMenuTextBrowser(QPoint point); + void sortColumn(int col,Qt::SortOrder o); void changedThread(QModelIndex index); void changedVersion(); @@ -151,10 +151,11 @@ private slots: void filterColumnChanged(int column); void filterItems(const QString &text); - +#ifdef TO_REMOVE void fillThreadFinished(); void fillThreadProgress(int current, int count); void fillThreadStatus(QString text); +#endif private: void insertMessageData(const RsGxsForumMsg &msg); @@ -171,8 +172,8 @@ private: int getSelectedMsgCount(QList *pRows, QList *pRowsRead, QList *pRowsUnread); void setMsgReadStatus(QList &rows, bool read); void markMsgAsReadUnread(bool read, bool children, bool forum); - void calculateIconsAndFonts(QTreeWidgetItem *item = NULL); - void calculateIconsAndFonts(QTreeWidgetItem *item, bool &hasReadChilddren, bool &hasUnreadChilddren); + //void calculateIconsAndFonts(QTreeWidgetItem *item = NULL); + //void calculateIconsAndFonts(QTreeWidgetItem *item, bool &hasReadChilddren, bool &hasUnreadChilddren); void calculateUnreadCount(); void togglethreadview_internal(); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp index faff45f74..abaad4848 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp @@ -33,6 +33,7 @@ //#define DEBUG_FORUMS +#ifdef TO_REMOVE #define PROGRESSBAR_MAX 100 GxsForumsFillThread::GxsForumsFillThread(GxsForumThreadWidget *parent) @@ -553,4 +554,5 @@ void GxsForumsFillThread::run() if(wasStopped()) deleteLater(); } +#endif diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h index 76428f382..cf4f17ea2 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h @@ -31,6 +31,7 @@ class RsGxsForumMsg; class RSTreeWidgetItemCompareRole; class QTreeWidgetItem; +#ifdef TO_REMOVE class GxsForumsFillThread : public QThread { Q_OBJECT @@ -70,3 +71,4 @@ private: }; #endif // GXSFORUMSFILLTHREAD_H +#endif // GXSFORUMSFILLTHREAD_H From 9c840baf2ed7fdc27ac811b9133ebfa81d5e03ed Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 28 Nov 2018 23:50:38 +0100 Subject: [PATCH 34/79] added missing signal causing crach in new model when changing forums --- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index b819e1970..e38ae759d 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -501,7 +501,7 @@ void RsGxsForumModel::setForum(const RsGxsGroupId& forum_group_id) void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector& posts,const std::map > >& post_versions) { - emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); + emit layoutAboutToBeChanged(); mForumGroup = group; mPosts = posts; @@ -523,6 +523,7 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector Date: Thu, 29 Nov 2018 00:01:35 +0100 Subject: [PATCH 35/79] removed some more old code from forum thread widget --- .../src/gui/gxsforums/GxsForumThreadWidget.cpp | 15 ++++++++++++++- .../src/gui/gxsforums/GxsForumThreadWidget.h | 4 +++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index d9162ce56..7e28d7480 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -317,6 +317,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget { ui->setupUi(this); +#ifdef TO_REMOVE mTokenTypeGroupData = nextTokenType(); mTokenTypeInsertThreads = nextTokenType(); mTokenTypeMessageData = nextTokenType(); @@ -327,10 +328,11 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mTokenTypeNeutralAuthor = nextTokenType(); mTokenTypePositiveAuthor = nextTokenType(); mTokenTypeEditForumMessage = nextTokenType(); +#endif setUpdateWhenInvisible(true); -#ifdef TODO +#ifdef TO_REMOVE /* Setup UI helper */ mStateHelper->addWidget(mTokenTypeGroupData, ui->subscribeToolButton); mStateHelper->addWidget(mTokenTypeGroupData, ui->newthreadButton); @@ -373,6 +375,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->threadTreeWidget->setModel(mThreadProxyModel); ui->threadTreeWidget->setSortingEnabled(true); + ui->threadTreeWidget->setDynamicSortFilter(true); ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,new DistributionItemDelegate()) ; ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_AUTHOR,new AuthorItemDelegate()) ; @@ -600,9 +603,11 @@ QString GxsForumThreadWidget::groupName(bool withUnreadCount) QIcon GxsForumThreadWidget::groupIcon() { +#ifdef TO_REMOVE if (mStateHelper->isLoading(mTokenTypeGroupData) || mFillThread) { return QIcon(":/images/kalarm.png"); } +#endif if (mNewCount) { return QIcon(":/images/message-state-new.png"); @@ -2330,6 +2335,7 @@ bool GxsForumThreadWidget::navigate(const RsGxsMessageId &msgId) return true; } +#ifdef TO_REMOVE bool GxsForumThreadWidget::isLoading() { if (mStateHelper->isLoading(mTokenTypeGroupData) || mFillThread) { @@ -2338,6 +2344,7 @@ bool GxsForumThreadWidget::isLoading() return GxsMessageFrameWidget::isLoading(); } +#endif void GxsForumThreadWidget::copyMessageLink() { @@ -2761,8 +2768,11 @@ void GxsForumThreadWidget::updateGroupData() if(groups.size() != 1) { + std::cerr << __PRETTY_FUNCTION__ << " obtained more than one group info for forum " << groupId() << std::endl; +#ifdef TO_REMOVE mStateHelper->setActive(mTokenTypeGroupData, false); mStateHelper->clear(mTokenTypeGroupData); +#endif return; } @@ -2813,8 +2823,11 @@ void GxsForumThreadWidget::updateMessageData(const RsGxsMessageId& msgId) if(msgs.size() != 1) { + std::cerr << __PRETTY_FUNCTION__ << " obtained more than one msg info for msgId " << msgId << std::endl; +#ifdef TO_REMOVE mStateHelper->setActive(mTokenTypeGroupData, false); mStateHelper->clear(mTokenTypeGroupData); +#endif return; } diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 547be9435..b387a7d70 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -74,7 +74,7 @@ public: virtual QString groupName(bool withUnreadCount); virtual QIcon groupIcon(); virtual bool navigate(const RsGxsMessageId& msgId); - virtual bool isLoading(); + //virtual bool isLoading(); unsigned int newCount() { return mNewCount; } unsigned int unreadCount() { return mUnreadCount; } @@ -217,6 +217,7 @@ private: unsigned int mUnreadCount; unsigned int mNewCount; +#ifdef TO_REMOVE uint32_t mTokenTypeGroupData; uint32_t mTokenTypeInsertThreads; uint32_t mTokenTypeMessageData; @@ -227,6 +228,7 @@ private: uint32_t mTokenTypeNegativeAuthor; uint32_t mTokenTypePositiveAuthor; uint32_t mTokenTypeNeutralAuthor; +#endif /* Color definitions (for standard see qss.default) */ QColor mTextColorRead; From 66ad7b650bb9c50beeae66d04fa365ab64732f6e Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 29 Nov 2018 18:33:25 +0100 Subject: [PATCH 36/79] added missing virtual destructor in RsGrpMetaData and RsMsgMetaData --- libretroshare/src/retroshare/rsgxsifacetypes.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libretroshare/src/retroshare/rsgxsifacetypes.h b/libretroshare/src/retroshare/rsgxsifacetypes.h index 72f290c2f..c80ce3afa 100644 --- a/libretroshare/src/retroshare/rsgxsifacetypes.h +++ b/libretroshare/src/retroshare/rsgxsifacetypes.h @@ -61,6 +61,8 @@ struct RsGroupMetaData : RsSerializable mCircleType(0x0001), mAuthenFlags(0), mSubscribeFlags(0), mPop(0), mVisibleMsgCount(0), mLastPost(0), mGroupStatus(0) {} + virtual ~RsGroupMetaData() {} + void operator =(const RsGxsGrpMetaData& rGxsMeta); RsGxsGroupId mGroupId; @@ -124,9 +126,9 @@ struct RsMsgMetaData : RsSerializable { RsMsgMetaData() : mPublishTs(0), mMsgFlags(0), mMsgStatus(0), mChildTs(0) {} + virtual ~RsMsgMetaData() {} void operator =(const RsGxsMsgMetaData& rGxsMeta); - RsGxsGroupId mGroupId; RsGxsMessageId mMsgId; From c078510909031e0805a3886937d9fd890d7ed89a Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 29 Nov 2018 18:34:47 +0100 Subject: [PATCH 37/79] removed line that breaks compilation --- retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 7e28d7480..0f53abf47 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -375,7 +375,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->threadTreeWidget->setModel(mThreadProxyModel); ui->threadTreeWidget->setSortingEnabled(true); - ui->threadTreeWidget->setDynamicSortFilter(true); + //ui->threadTreeWidget->setDynamicSortFilter(true);// is that useful?? ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,new DistributionItemDelegate()) ; ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_AUTHOR,new AuthorItemDelegate()) ; From dce660357aceab527c289b432f3add5480450ec1 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 29 Nov 2018 22:15:12 +0100 Subject: [PATCH 38/79] fixed Travis compilation --- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index e38ae759d..6f9b0fa75 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -1165,10 +1165,13 @@ static void recursPrintModel(const std::vector& entries,For { const ForumModelPostEntry& e(entries[index]); + QDateTime qtime; + qtime.setTime_t(e.mPublishTs); + std::cerr << std::string(depth*2,' ') << index << " : " << e.mAuthorId.toStdString() << " " << QString("%1").arg((uint32_t)e.mPostFlags,8,16,QChar('0')).toStdString() << " " << QString("%1").arg((uint32_t)e.mMsgStatus,8,16,QChar('0')).toStdString() << " " - << QDateTime::fromSecsSinceEpoch(e.mPublishTs).toString().toStdString() << " \"" << e.mTitle << "\"" << std::endl; + << qtime.toString().toStdString() << " \"" << e.mTitle << "\"" << std::endl; for(uint32_t i=0;i Date: Fri, 30 Nov 2018 17:24:43 +0100 Subject: [PATCH 39/79] fixed sorting problem in new model due to missing call to sortRole() --- retroshare-gui/src/gui/gxs/GxsIdDetails.h | 1 + .../src/gui/gxsforums/GxsForumModel.cpp | 19 ++++++++++++++++--- .../gui/gxsforums/GxsForumThreadWidget.cpp | 2 ++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.h b/retroshare-gui/src/gui/gxs/GxsIdDetails.h index 30edffd7e..8c6c8edac 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.h +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.h @@ -63,6 +63,7 @@ class GxsIdDetails : public QObject Q_OBJECT public: + static const int ICON_TYPE_NONE = 0x0000 ; static const int ICON_TYPE_AVATAR = 0x0001 ; static const int ICON_TYPE_PGP = 0x0002 ; static const int ICON_TYPE_RECOGN = 0x0004 ; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 6f9b0fa75..825cc02d4 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -310,6 +310,7 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const case ThreadPinnedRole: return pinnedRole (fmpe,index.column()) ; case MissingRole: return missingRole (fmpe,index.column()) ; case StatusRole: return statusRole (fmpe,index.column()) ; + case SortRole: return sortRole (fmpe,index.column()) ; default: return QVariant(); } @@ -424,10 +425,22 @@ QVariant RsGxsForumModel::authorRole(const ForumModelPostEntry& fmpe,int column) QVariant RsGxsForumModel::sortRole(const ForumModelPostEntry& fmpe,int column) const { - if(column == COLUMN_THREAD_DATA) - return QVariant(QString::number(fmpe.mPublishTs)); // we should probably have leading zeroes here + switch(column) + { + case COLUMN_THREAD_DATE: return QVariant(QString::number(fmpe.mPublishTs)); // we should probably have leading zeroes here + case COLUMN_THREAD_READ: return QVariant((bool)IS_MSG_UNREAD(fmpe.mMsgStatus)); + case COLUMN_THREAD_DISTRIBUTION: return decorationRole(fmpe,column); + case COLUMN_THREAD_AUTHOR: + { + QString str,comment ; + QList icons; + GxsIdDetails::MakeIdDesc(fmpe.mAuthorId, false, str, icons, comment,GxsIdDetails::ICON_TYPE_NONE); - return QVariant(); + return QVariant(str); + } + default: + return displayRole(fmpe,column); + } } QVariant RsGxsForumModel::displayRole(const ForumModelPostEntry& fmpe,int col) const diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 0f53abf47..a5a16caed 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -372,6 +372,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mThreadModel = new RsGxsForumModel(this); mThreadProxyModel = new ForumPostSortFilterProxyModel(ui->threadTreeWidget->header(),this); mThreadProxyModel->setSourceModel(mThreadModel); + mThreadProxyModel->setSortRole(RsGxsForumModel::SortRole); ui->threadTreeWidget->setModel(mThreadProxyModel); ui->threadTreeWidget->setSortingEnabled(true); @@ -381,6 +382,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_AUTHOR,new AuthorItemDelegate()) ; ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_READ,new ReadStatusItemDelegate()) ; + ui->threadTreeWidget->header()->setSortIndicatorShown(true); connect(ui->threadTreeWidget->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),this,SLOT(sortColumn(int,Qt::SortOrder))); connect(ui->versions_CB, SIGNAL(currentIndexChanged(int)), this, SLOT(changedVersion())); From b7b9f335f95b782843497aaaa51d49970cf07c1d Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 30 Nov 2018 18:01:51 +0100 Subject: [PATCH 40/79] fixed fonts for unread msgs in Forum Model --- .../src/gui/gxsforums/GxsForumModel.cpp | 2 +- .../src/gui/gxsforums/GxsForumThreadWidget.cpp | 6 ------ .../src/gui/gxsforums/GxsForumThreadWidget.h | 15 --------------- 3 files changed, 1 insertion(+), 22 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 825cc02d4..d3609c197 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -287,7 +287,7 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const if(role == Qt::FontRole) { QFont font ; - font.setBold( (fmpe.mPostFlags & (ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN | ForumModelPostEntry::FLAG_POST_IS_PINNED))); + font.setBold( (fmpe.mPostFlags & (ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN | ForumModelPostEntry::FLAG_POST_IS_PINNED)) || IS_MSG_UNREAD(fmpe.mMsgStatus)); return QVariant(font); } diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index a5a16caed..c2a12b426 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -383,7 +383,6 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_READ,new ReadStatusItemDelegate()) ; ui->threadTreeWidget->header()->setSortIndicatorShown(true); - connect(ui->threadTreeWidget->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),this,SLOT(sortColumn(int,Qt::SortOrder))); connect(ui->versions_CB, SIGNAL(currentIndexChanged(int)), this, SLOT(changedVersion())); connect(ui->threadTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(threadListCustomPopupMenu(QPoint))); @@ -492,11 +491,6 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget #endif } -void GxsForumThreadWidget::sortColumn(int col,Qt::SortOrder o) -{ - ui->threadTreeWidget->sortByColumn(col,o); -} - void GxsForumThreadWidget::blank() { ui->progressBar->hide(); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index b387a7d70..29c59099d 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -74,15 +74,12 @@ public: virtual QString groupName(bool withUnreadCount); virtual QIcon groupIcon(); virtual bool navigate(const RsGxsMessageId& msgId); - //virtual bool isLoading(); unsigned int newCount() { return mNewCount; } unsigned int unreadCount() { return mUnreadCount; } QTreeWidgetItem *generateMissingItem(const RsGxsMessageId &msgId); - // Callback for all Loads. - //virtual void loadRequest(const TokenQueue *queue, const TokenRequest &req); virtual void blank(); protected: @@ -99,7 +96,6 @@ private slots: /** Create the context popup menu and it's submenus */ void threadListCustomPopupMenu(QPoint point); void contextMenuTextBrowser(QPoint point); - void sortColumn(int col,Qt::SortOrder o); void changedThread(QModelIndex index); void changedVersion(); @@ -120,11 +116,6 @@ private slots: void saveImage(); - - //void print(); - //void printpreview(); - - //void removemessage(); void markMsgAsRead(); void markMsgAsReadChildren(); void markMsgAsUnread(); @@ -165,15 +156,9 @@ private: void insertMessage(); void insertGroupData(); - //void insertThreads(); - //void fillThreads(QList &threadList, bool expandNewMessages, QList &itemToExpand); - //void fillChildren(QTreeWidgetItem *parentItem, QTreeWidgetItem *newParentItem, bool expandNewMessages, QList &itemToExpand); - int getSelectedMsgCount(QList *pRows, QList *pRowsRead, QList *pRowsUnread); void setMsgReadStatus(QList &rows, bool read); void markMsgAsReadUnread(bool read, bool children, bool forum); - //void calculateIconsAndFonts(QTreeWidgetItem *item = NULL); - //void calculateIconsAndFonts(QTreeWidgetItem *item, bool &hasReadChilddren, bool &hasUnreadChilddren); void calculateUnreadCount(); void togglethreadview_internal(); From a51eba1db2be0e77728ee5d1375b4b79472460c4 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 1 Dec 2018 16:09:35 +0100 Subject: [PATCH 41/79] added filtering mechanism in ForumModel --- .../src/gui/gxsforums/GxsForumModel.cpp | 44 ++++++++++- .../src/gui/gxsforums/GxsForumModel.h | 6 ++ .../gui/gxsforums/GxsForumThreadWidget.cpp | 75 +++++++++++-------- 3 files changed, 91 insertions(+), 34 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index d3609c197..37d7ead53 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -10,6 +10,7 @@ #include "GxsForumModel.h" #include "retroshare/rsgxsflags.h" #include "retroshare/rsgxsforums.h" +#include "retroshare/rsexpr.h" //#define DEBUG_FORUMMODEL @@ -17,6 +18,8 @@ Q_DECLARE_METATYPE(RsMsgMetaData); std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere +const QString RsGxsForumModel::FilterString("filtered"); + RsGxsForumModel::RsGxsForumModel(QObject *parent) : QAbstractItemModel(parent) { @@ -307,6 +310,7 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const case Qt::TextColorRole: return textColorRole (fmpe,index.column()) ; case Qt::BackgroundRole: return backgroundRole(fmpe,index.column()) ; + case FilterRole: return filterRole (fmpe,index.column()) ; case ThreadPinnedRole: return pinnedRole (fmpe,index.column()) ; case MissingRole: return missingRole (fmpe,index.column()) ; case StatusRole: return statusRole (fmpe,index.column()) ; @@ -337,10 +341,41 @@ QVariant RsGxsForumModel::statusRole(const ForumModelPostEntry& fmpe,int column) return QVariant(fmpe.mMsgStatus); } +QVariant RsGxsForumModel::filterRole(const ForumModelPostEntry& fmpe,int column) const +{ + if(mFilterColumn < 0) + return QVariant(QString()); + + switch(mFilterColumn) + { + case COLUMN_THREAD_TITLE: + { + for(auto iter(mFilterStrings.begin()); iter != mFilterStrings.end(); ++iter) + if(fmpe.mTitle.end() != std::search( fmpe.mTitle.begin(), fmpe.mTitle.end(), (*iter).begin(), (*iter).end(), RsRegularExpression::CompareCharIC() )) + return QVariant(FilterString); + + return QVariant(QString()); + } + + default: + return QVariant(FilterString); + } +} + +void RsGxsForumModel::setFilter(int column,const std::list& strings) +{ + mFilterColumn = column; + mFilterStrings = strings; + + emit layoutAboutToBeChanged(); + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); + emit layoutChanged(); +} + QVariant RsGxsForumModel::missingRole(const ForumModelPostEntry& fmpe,int column) const { - if(column != COLUMN_THREAD_DATA) - return QVariant(); +// if(column != COLUMN_THREAD_DATA) +// return QVariant(); if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) return QVariant(true); @@ -455,7 +490,10 @@ QVariant RsGxsForumModel::displayRole(const ForumModelPostEntry& fmpe,int col) c return QVariant(QString::fromUtf8(fmpe.mTitle.c_str())); case COLUMN_THREAD_READ:return QVariant(); - case COLUMN_THREAD_DATE: { + case COLUMN_THREAD_DATE:{ + if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) + return QVariant(QString()); + QDateTime qtime; qtime.setTime_t(fmpe.mPublishTs); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index 78fd9f6e3..4637b1be1 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -78,11 +78,14 @@ public: MissingRole = Qt::UserRole+3, StatusRole = Qt::UserRole+4, UnreadChildrenRole = Qt::UserRole+5, + FilterRole = Qt::UserRole+6, }; QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const; + static const QString FilterString ; + std::vector > getPostVersions(const RsGxsMessageId& mid) const; #ifdef TO_REMOVE @@ -117,6 +120,7 @@ public: void setTextColorMissing (QColor color) { mTextColorMissing = color;} void setMsgReadStatus(const QModelIndex &i, bool read_status, bool with_children); + void setFilter(int column,const std::list& strings) ; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; @@ -142,6 +146,7 @@ public: QVariant authorRole (const ForumModelPostEntry& fmpe, int col) const; QVariant sortRole (const ForumModelPostEntry& fmpe, int col) const; QVariant fontRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant filterRole (const ForumModelPostEntry& fmpe, int col) const; QVariant textColorRole (const ForumModelPostEntry& fmpe, int col) const; QVariant backgroundRole(const ForumModelPostEntry& fmpe, int col) const; @@ -160,6 +165,7 @@ private: bool mUseChildTS; bool mFlatView; int mFilterColumn; + std::list mFilterStrings; void *getParentRef(void *ref,int& row) const; void *getChildRef(void *ref,int row) const; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index c2a12b426..329839131 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -100,12 +100,6 @@ class DistributionItemDelegate: public QStyledItemDelegate public: DistributionItemDelegate() {} - QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override - { - const QRect r = option.rect; - return QSize(r.height(),r.height()); - } - virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if(!index.isValid()) @@ -130,11 +124,11 @@ public: switch(warning_level) { + default: + case 3: case 0: icon = QIcon(IMAGE_VOID); break; case 1: icon = QIcon(IMAGE_WARNING_YELLOW); break; case 2: icon = QIcon(IMAGE_WARNING_RED); break; - default: - case 3: icon = QIcon(IMAGE_WARNING_UNKNOWN); break; } QPixmap pix = icon.pixmap(r.size()); @@ -225,7 +219,7 @@ public: QPixmap pix = icon.pixmap(r.size()); - return QSize(pix.width() + fm.width(str),std::max(1.1*pix.height(),1.4*fm.height())); + return QSize(1.2*(pix.width() + fm.width(str)),std::max(1.1*pix.height(),1.4*fm.height())); } virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const override @@ -261,12 +255,17 @@ public: else icon = *icons.begin(); - QPixmap pix = icon.pixmap(r.size()); + if(index.data(RsGxsForumModel::MissingRole).toBool()) + painter->drawText(r.topLeft() + QPoint(f/2.0,f*1.0), tr("[None]")); + else + { + QPixmap pix = icon.pixmap(r.size()); + const QPoint p = QPoint(pix.width()/2.0, (r.height() - pix.height())/2); - // draw pixmap at center of item - const QPoint p = QPoint(pix.width()/2.0, (r.height() - pix.height())/2); - painter->drawPixmap(r.topLeft() + p, pix); - painter->drawText(r.topLeft() + p + QPoint(pix.width()+f/2.0,f*0.8), str); + // draw pixmap at center of item + painter->drawPixmap(r.topLeft() + p, pix); + painter->drawText(r.topLeft() + p + QPoint(pix.width()+f/2.0,f*1.0), str); + } } }; @@ -375,6 +374,9 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mThreadProxyModel->setSortRole(RsGxsForumModel::SortRole); ui->threadTreeWidget->setModel(mThreadProxyModel); + mThreadProxyModel->setFilterRole(RsGxsForumModel::FilterRole); + mThreadProxyModel->setFilterRegExp(QRegExp(QString(RsGxsForumModel::FilterString))) ; + ui->threadTreeWidget->setSortingEnabled(true); //ui->threadTreeWidget->setDynamicSortFilter(true);// is that useful?? @@ -419,14 +421,6 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget itemDelegate->setOnlyPlainText(true); ui->threadTreeWidget->setItemDelegate(itemDelegate); - float f = QFontMetricsF(font()).height()/14.0f ; - - QHeaderView * ttheader = ui->threadTreeWidget->header () ; - ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_DATE, 140*f); - ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_TITLE, 440*f); - ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, 24*f); - ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_AUTHOR, 150*f); - #ifdef SUSPENDED_CODE /* Set text of column "Read" to empty - without this the column has a number as header text */ QTreeWidgetItem *headerItem = ui->threadTreeWidget->headerItem(); @@ -449,16 +443,25 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget // load settings processSettings(true); + float f = QFontMetricsF(font()).height()/14.0f ; + /* Set header resize modes and initial section sizes */ + + QHeaderView * ttheader = ui->threadTreeWidget->header () ; + ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_DATE, 140*f); + ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_TITLE, 440*f); + ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, 24*f); + ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_AUTHOR, 150*f); + ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_READ, 24*f); + QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_TITLE, QHeaderView::Interactive); - QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_READ, QHeaderView::Fixed); QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_DATE, QHeaderView::Interactive); - QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, QHeaderView::ResizeToContents); QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_AUTHOR, QHeaderView::Interactive); + QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_READ, QHeaderView::Fixed); + QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, QHeaderView::Fixed); ui->threadTreeWidget->header()->setCascadingSectionResizes(true); /* Set header sizes for the fixed columns and resize modes, must be set after processSettings */ - ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_READ, 24*f); ttheader->hideSection (RsGxsForumModel::COLUMN_THREAD_CONTENT); ttheader->hideSection (RsGxsForumModel::COLUMN_THREAD_MSGID); ttheader->hideSection (RsGxsForumModel::COLUMN_THREAD_DATA); @@ -2685,14 +2688,24 @@ void GxsForumThreadWidget::filterColumnChanged(int column) void GxsForumThreadWidget::filterItems(const QString& text) { -#ifdef TODO + //FileSearchFlags flags = isRemote()?RS_FILE_HINTS_REMOTE:RS_FILE_HINTS_LOCAL; + QStringList lst = text.split(" ",QString::SkipEmptyParts) ; + std::list keywords ; + + for(auto it(lst.begin());it!=lst.end();++it) + keywords.push_back((*it).toStdString()); + int filterColumn = ui->filterLineEdit->currentFilter(); - int count = ui->threadTreeWidget->topLevelItemCount(); - for (int index = 0; index < count; ++index) { - filterItem(ui->threadTreeWidget->topLevelItem(index), text, filterColumn); - } -#endif + mThreadModel->setFilter(filterColumn,keywords) ; + + //if(found > 0) + // expandAll(); + + //if(found == 0) + // ui.filterLineEdit->setToolTip(tr("No result.")) ; + //else + // ui.filterLineEdit->setToolTip(tr("Found %1 results.").arg(found)) ; } bool GxsForumThreadWidget::filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn) From 917695e83268872b93ebd987d8dcd89e8837a53c Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 1 Dec 2018 23:14:08 +0100 Subject: [PATCH 42/79] fixed filtering of messages in new forum Model --- .../src/gui/gxsforums/GxsForumModel.cpp | 105 +++++++++++++----- .../src/gui/gxsforums/GxsForumModel.h | 20 ++-- .../gui/gxsforums/GxsForumThreadWidget.cpp | 38 +++---- 3 files changed, 103 insertions(+), 60 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 37d7ead53..3e72f3659 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -25,10 +25,9 @@ RsGxsForumModel::RsGxsForumModel(QObject *parent) { initEmptyHierarchy(mPosts); - - mFilterColumn=0; mUseChildTS=false; mFlatView=false; + mFilteringEnabled=false; } void RsGxsForumModel::initEmptyHierarchy(std::vector& posts) @@ -343,38 +342,84 @@ QVariant RsGxsForumModel::statusRole(const ForumModelPostEntry& fmpe,int column) QVariant RsGxsForumModel::filterRole(const ForumModelPostEntry& fmpe,int column) const { - if(mFilterColumn < 0) - return QVariant(QString()); - - switch(mFilterColumn) - { - case COLUMN_THREAD_TITLE: - { - for(auto iter(mFilterStrings.begin()); iter != mFilterStrings.end(); ++iter) - if(fmpe.mTitle.end() != std::search( fmpe.mTitle.begin(), fmpe.mTitle.end(), (*iter).begin(), (*iter).end(), RsRegularExpression::CompareCharIC() )) - return QVariant(FilterString); - - return QVariant(QString()); - } - - default: + if(!mFilteringEnabled || (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER)) return QVariant(FilterString); - } + + return QVariant(QString()); } -void RsGxsForumModel::setFilter(int column,const std::list& strings) +uint32_t RsGxsForumModel::recursUpdateFilterStatus(ForumModelIndex i,int column,const QStringList& strings) { - mFilterColumn = column; - mFilterStrings = strings; + QString s ; + uint32_t count = 0; - emit layoutAboutToBeChanged(); - emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); - emit layoutChanged(); + switch(column) + { + default: + case COLUMN_THREAD_DATE: + case COLUMN_THREAD_TITLE: s = displayRole(mPosts[i],column).toString(); + break; + case COLUMN_THREAD_AUTHOR: + { + QString comment ; + QList icons; + + GxsIdDetails::MakeIdDesc(mPosts[i].mAuthorId, false,s, icons, comment,GxsIdDetails::ICON_TYPE_NONE); + } + break; + } + + if(!strings.empty()) + { + mPosts[i].mPostFlags &= ~(ForumModelPostEntry::FLAG_POST_PASSES_FILTER | ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER); + + for(auto iter(strings.begin()); iter != strings.end(); ++iter) + if(s.contains(*iter,Qt::CaseInsensitive)) + { + mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_PASSES_FILTER | ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; + + count++; + break; + } + } + else + { + mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_PASSES_FILTER |ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; + count++; + } + + for(uint32_t j=0;j 0) + mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; + } + + return count; +} + + +void RsGxsForumModel::setFilter(int column,const QStringList& strings,uint32_t& count) +{ + emit layoutAboutToBeChanged(); + + if(!strings.empty()) + { + count = recursUpdateFilterStatus(ForumModelIndex(0),column,strings); + mFilteringEnabled = true; + } + else + mFilteringEnabled = false; + + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); + emit layoutChanged(); } QVariant RsGxsForumModel::missingRole(const ForumModelPostEntry& fmpe,int column) const { -// if(column != COLUMN_THREAD_DATA) + // if(column != COLUMN_THREAD_DATA) // return QVariant(); if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) @@ -433,6 +478,9 @@ QVariant RsGxsForumModel::backgroundRole(const ForumModelPostEntry& fmpe,int col if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) return QVariant(QBrush(QColor(255,200,180))); + if(mFilteringEnabled && (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_PASSES_FILTER)) + return QVariant(QBrush(QColor(255,240,210))); + return QVariant(); } @@ -568,6 +616,7 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector& strings) ; + void setFilter(int column, const QStringList &strings, uint32_t &count) ; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; @@ -164,8 +166,7 @@ private: bool mUseChildTS; bool mFlatView; - int mFilterColumn; - std::list mFilterStrings; + bool mFilteringEnabled; void *getParentRef(void *ref,int& row) const; void *getChildRef(void *ref,int row) const; @@ -179,10 +180,11 @@ private: void setForumMessageSummary(const std::vector& messages); void recursUpdateReadStatus(ForumModelIndex i,bool& has_unread_below,bool& has_read_below); void recursSetMsgReadStatus(ForumModelIndex i,bool read_status,bool with_children); + uint32_t recursUpdateFilterStatus(ForumModelIndex i,int column,const QStringList& strings); static void generateMissingItem(const RsGxsMessageId &msgId,ForumModelPostEntry& entry); static ForumModelIndex addEntry(std::vector& posts,const ForumModelPostEntry& entry,ForumModelIndex parent); - static void convertMsgToPostEntry(const RsGxsForumGroup &mForumGroup, const RsGxsForumMsg& msg, bool useChildTS, uint32_t filterColumn, ForumModelPostEntry& fentry); + static void convertMsgToPostEntry(const RsGxsForumGroup &mForumGroup, const RsGxsForumMsg& msg, bool useChildTS, ForumModelPostEntry& fentry); void computeMessagesHierarchy(const RsGxsForumGroup& forum_group, const std::vector& msgs_array, std::vector& posts, std::map > > &mPostVersions); void setPosts(const RsGxsForumGroup& group, const std::vector& posts,const std::map > >& post_versions); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 329839131..60d0e7c15 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -25,6 +25,7 @@ #include #include "util/qtthreadsutils.h" +#include "util/misc.h" #include "GxsForumThreadWidget.h" #include "ui_GxsForumThreadWidget.h" #include "GxsForumsFillThread.h" @@ -359,7 +360,6 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mSubscribeFlags = 0; mSignFlags = 0; - mInProcessSettings = false; mUnreadCount = 0; mNewCount = 0; @@ -434,7 +434,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->filterLineEdit->addFilter(QIcon(), tr("Title"), RsGxsForumModel::COLUMN_THREAD_TITLE, tr("Search Title")); ui->filterLineEdit->addFilter(QIcon(), tr("Date"), RsGxsForumModel::COLUMN_THREAD_DATE, tr("Search Date")); ui->filterLineEdit->addFilter(QIcon(), tr("Author"), RsGxsForumModel::COLUMN_THREAD_AUTHOR, tr("Search Author")); - ui->filterLineEdit->addFilter(QIcon(), tr("Content"), RsGxsForumModel::COLUMN_THREAD_CONTENT, tr("Search Content")); + //ui->filterLineEdit->addFilter(QIcon(), tr("Content"), RsGxsForumModel::COLUMN_THREAD_CONTENT, tr("Search Content")); // see processSettings //ui->filterLineEdit->setCurrentFilter(COLUMN_THREAD_TITLE); @@ -539,8 +539,6 @@ GxsForumThreadWidget::~GxsForumThreadWidget() void GxsForumThreadWidget::processSettings(bool load) { - mInProcessSettings = true; - QHeaderView *header = ui->threadTreeWidget->header(); Settings->beginGroup(QString("ForumThreadWidget")); @@ -575,7 +573,6 @@ void GxsForumThreadWidget::processSettings(bool load) } Settings->endGroup(); - mInProcessSettings = false; } void GxsForumThreadWidget::groupIdChanged() @@ -2671,16 +2668,13 @@ void GxsForumThreadWidget::changedViewBox() void GxsForumThreadWidget::filterColumnChanged(int column) { - if (mInProcessSettings) { - return; - } - +#ifdef TO_REMOVE if (column == RsGxsForumModel::COLUMN_THREAD_CONTENT) { // need content ... refill //insertThreads(); } else { - filterItems(ui->filterLineEdit->text()); - } +#endif + filterItems(ui->filterLineEdit->text()); // save index Settings->setValueToGroup("ForumThreadWidget", "filterColumn", column); @@ -2688,24 +2682,22 @@ void GxsForumThreadWidget::filterColumnChanged(int column) void GxsForumThreadWidget::filterItems(const QString& text) { - //FileSearchFlags flags = isRemote()?RS_FILE_HINTS_REMOTE:RS_FILE_HINTS_LOCAL; QStringList lst = text.split(" ",QString::SkipEmptyParts) ; - std::list keywords ; - - for(auto it(lst.begin());it!=lst.end();++it) - keywords.push_back((*it).toStdString()); int filterColumn = ui->filterLineEdit->currentFilter(); - mThreadModel->setFilter(filterColumn,keywords) ; + uint32_t count; + mThreadModel->setFilter(filterColumn,lst,count) ; - //if(found > 0) - // expandAll(); + if(!lst.empty()) + ui->threadTreeWidget->expandAll(); + else + ui->threadTreeWidget->collapseAll(); - //if(found == 0) - // ui.filterLineEdit->setToolTip(tr("No result.")) ; - //else - // ui.filterLineEdit->setToolTip(tr("Found %1 results.").arg(found)) ; + if(count > 0) + ui->filterLineEdit->setToolTip(tr("No result.")) ; + else + ui->filterLineEdit->setToolTip(tr("Found %1 results.").arg(count)) ; } bool GxsForumThreadWidget::filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn) From 1fced4a1c3450bfb021a366ba20a520dcae756a0 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Dec 2018 12:02:25 +0100 Subject: [PATCH 43/79] added flat mode to ForumModel --- .../src/gui/gxsforums/GxsForumModel.cpp | 50 +++++++++++++++++-- .../src/gui/gxsforums/GxsForumModel.h | 7 ++- .../gui/gxsforums/GxsForumThreadWidget.cpp | 21 ++++---- 3 files changed, 61 insertions(+), 17 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 3e72f3659..abf2a15f2 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -26,15 +26,32 @@ RsGxsForumModel::RsGxsForumModel(QObject *parent) initEmptyHierarchy(mPosts); mUseChildTS=false; - mFlatView=false; mFilteringEnabled=false; } +void RsGxsForumModel::setTreeMode(TreeMode mode) +{ + if(mode == mTreeMode) + return; + + emit layoutAboutToBeChanged(); + + mTreeMode = mode; + + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); + emit layoutChanged(); +} + void RsGxsForumModel::initEmptyHierarchy(std::vector& posts) { + emit layoutAboutToBeChanged(); + posts.resize(1); // adds a sentinel item posts[0].mTitle = "Root sentinel post" ; posts[0].mParent = 0; + + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); + emit layoutChanged(); } int RsGxsForumModel::rowCount(const QModelIndex& parent) const @@ -88,6 +105,9 @@ bool RsGxsForumModel::hasChildren(const QModelIndex &parent) const if(!parent.isValid()) return true; + if(mTreeMode == TREE_MODE_FLAT) + return false; + void *ref = parent.internalPointer(); uint32_t entry = 0; @@ -151,6 +171,9 @@ QModelIndex RsGxsForumModel::parent(const QModelIndex& index) const if(!index.isValid()) return QModelIndex(); + if(mTreeMode == TREE_MODE_FLAT) + return QModelIndex(); + void *child_ref = index.internalPointer(); int row=0; @@ -178,6 +201,16 @@ void *RsGxsForumModel::getChildRef(void *ref,int row) const return NULL ; void *new_ref; + + if(mTreeMode == TREE_MODE_FLAT) + if(entry == 0) + { + convertTabEntryToRefPointer(row+1,new_ref); + return new_ref; + } + else + return NULL ; + if(row >= mPosts[entry].mChildren.size()) return NULL; @@ -190,6 +223,9 @@ void *RsGxsForumModel::getParentRef(void *ref,int& row) const { ForumModelIndex ref_entry; + if(mTreeMode == TREE_MODE_FLAT) + return NULL; + if(!convertRefPointerToTabEntry(ref,ref_entry) || ref_entry >= mPosts.size()) return NULL ; @@ -217,7 +253,13 @@ int RsGxsForumModel::getChildrenCount(void *ref) const if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) return 0 ; - return mPosts[entry].mChildren.size(); + if(mTreeMode == TREE_MODE_FLAT) + if(entry == 0) + return ((int)mPosts.size())-1; + else + return 0; + else + return mPosts[entry].mChildren.size(); } QVariant RsGxsForumModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -941,7 +983,7 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou for ( std::map::iterator msgIt = msgs.begin(); msgIt != msgs.end();++msgIt) { - if(mFlatView || msgIt->second.mMeta.mParentId.isNull()) + if(msgIt->second.mMeta.mParentId.isNull()) { /* add all threads */ @@ -956,7 +998,7 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou ForumModelIndex entry_index = addEntry(posts,entry,0); - if (!mFlatView) + //if (!mFlatView) threadStack.push_back(std::make_pair(msg.mMeta.mMsgId,entry_index)) ; //calculateExpand(msg, item); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index 539f1a400..60e38fa9b 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -83,6 +83,10 @@ public: FilterRole = Qt::UserRole+6, }; + enum TreeMode{ TREE_MODE_FLAT = 0x00, + TREE_MODE_TREE = 0x01, + }; + QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const; @@ -114,6 +118,7 @@ public: // This method will asynchroneously update the data void setForum(const RsGxsGroupId& forumGroup); + void setTreeMode(TreeMode mode) ; void setTextColorRead (QColor color) { mTextColorRead = color;} void setTextColorUnread (QColor color) { mTextColorUnread = color;} @@ -165,8 +170,8 @@ private: RsGxsForumGroup mForumGroup; bool mUseChildTS; - bool mFlatView; bool mFilteringEnabled; + TreeMode mTreeMode; void *getParentRef(void *ref,int& row) const; void *getChildRef(void *ref,int row) const; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 60d0e7c15..0258cf29b 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -365,9 +365,6 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mInMsgAsReadUnread = false; - //mThreadCompareRole = new RSTreeWidgetItemCompareRole; - //mThreadCompareRole->setRole(RsGxsForumModel::COLUMN_THREAD_DATE, ROLE_THREAD_SORT); - mThreadModel = new RsGxsForumModel(this); mThreadProxyModel = new ForumPostSortFilterProxyModel(ui->threadTreeWidget->header(),this); mThreadProxyModel->setSourceModel(mThreadModel); @@ -400,7 +397,6 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->newmessageButton->setText(tr("Reply")); ui->newthreadButton->setText(tr("New thread")); - //connect(ui->threadTreeWidget, SIGNAL(clicked(QModelIndex)), this, SLOT(changedThread(QModelIndex))); connect(ui->threadTreeWidget, SIGNAL(clicked(QModelIndex)), this, SLOT(clickedThread(QModelIndex))); connect(ui->viewBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changedViewBox())); @@ -2652,18 +2648,19 @@ void GxsForumThreadWidget::saveImage() void GxsForumThreadWidget::changedViewBox() { -#ifdef TODO - if (mInProcessSettings) { - return; - } - // save index Settings->setValueToGroup("ForumThreadWidget", "viewBox", ui->viewBox->currentIndex()); - ui->threadTreeWidget->clear(); + switch(ui->viewBox->currentIndex()) + { + default: + case VIEW_THREADED: + case VIEW_LAST_POST: mThreadModel->setTreeMode(RsGxsForumModel::TREE_MODE_TREE); + break; - insertThreads(); -#endif + case VIEW_FLAT: mThreadModel->setTreeMode(RsGxsForumModel::TREE_MODE_FLAT); + break; + } } void GxsForumThreadWidget::filterColumnChanged(int column) From 37f721f305ffe1356ddf0497c08e785729f8be10 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Dec 2018 16:07:28 +0100 Subject: [PATCH 44/79] added reset to avoid crash when switching from flat to tree views --- retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 0258cf29b..817dccdf7 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -2648,6 +2648,10 @@ void GxsForumThreadWidget::saveImage() void GxsForumThreadWidget::changedViewBox() { + ui->threadTreeWidget->selectionModel()->clear(); + ui->threadTreeWidget->selectionModel()->reset(); + mThreadId.clear(); + // save index Settings->setValueToGroup("ForumThreadWidget", "viewBox", ui->viewBox->currentIndex()); From 91321725e666d2bb4cbb4fc6e631713cda6b0550 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Dec 2018 16:34:43 +0100 Subject: [PATCH 45/79] added sorting based on most recent TS from children --- .../src/gui/gxsforums/GxsForumModel.cpp | 31 ++++++++++++++++--- .../src/gui/gxsforums/GxsForumModel.h | 13 ++++++-- .../gui/gxsforums/GxsForumThreadWidget.cpp | 17 +++++----- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index abf2a15f2..adadbf5bf 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -42,6 +42,16 @@ void RsGxsForumModel::setTreeMode(TreeMode mode) emit layoutChanged(); } +void RsGxsForumModel::setSortMode(SortMode mode) +{ + emit layoutAboutToBeChanged(); + + mSortMode = mode; + + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); + emit layoutChanged(); +} + void RsGxsForumModel::initEmptyHierarchy(std::vector& posts) { emit layoutAboutToBeChanged(); @@ -552,7 +562,11 @@ QVariant RsGxsForumModel::sortRole(const ForumModelPostEntry& fmpe,int column) c { switch(column) { - case COLUMN_THREAD_DATE: return QVariant(QString::number(fmpe.mPublishTs)); // we should probably have leading zeroes here + case COLUMN_THREAD_DATE: if(mSortMode == SORT_MODE_PUBLISH_TS) + return QVariant(QString::number(fmpe.mPublishTs)); // we should probably have leading zeroes here + else + return QVariant(QString::number(fmpe.mMostRecentTsInThread)); // we should probably have leading zeroes here + case COLUMN_THREAD_READ: return QVariant((bool)IS_MSG_UNREAD(fmpe.mMsgStatus)); case COLUMN_THREAD_DISTRIBUTION: return decorationRole(fmpe,column); case COLUMN_THREAD_AUTHOR: @@ -657,8 +671,10 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector& messages); - void recursUpdateReadStatus(ForumModelIndex i,bool& has_unread_below,bool& has_read_below); - void recursSetMsgReadStatus(ForumModelIndex i,bool read_status,bool with_children); + void recursUpdateReadStatusAndTimes(ForumModelIndex i,bool& has_unread_below,bool& has_read_below); uint32_t recursUpdateFilterStatus(ForumModelIndex i,int column,const QStringList& strings); + void recursSetMsgReadStatus(ForumModelIndex i,bool read_status,bool with_children); static void generateMissingItem(const RsGxsMessageId &msgId,ForumModelPostEntry& entry); static ForumModelIndex addEntry(std::vector& posts,const ForumModelPostEntry& entry,ForumModelIndex parent); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 817dccdf7..dae56098f 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -2655,16 +2655,15 @@ void GxsForumThreadWidget::changedViewBox() // save index Settings->setValueToGroup("ForumThreadWidget", "viewBox", ui->viewBox->currentIndex()); - switch(ui->viewBox->currentIndex()) - { - default: - case VIEW_THREADED: - case VIEW_LAST_POST: mThreadModel->setTreeMode(RsGxsForumModel::TREE_MODE_TREE); - break; + if(ui->viewBox->currentIndex() == VIEW_FLAT) + mThreadModel->setTreeMode(RsGxsForumModel::TREE_MODE_FLAT); + else + mThreadModel->setTreeMode(RsGxsForumModel::TREE_MODE_TREE); - case VIEW_FLAT: mThreadModel->setTreeMode(RsGxsForumModel::TREE_MODE_FLAT); - break; - } + if(ui->viewBox->currentIndex() == VIEW_LAST_POST) + mThreadModel->setSortMode(RsGxsForumModel::SORT_MODE_CHILDREN_PUBLISH_TS); + else + mThreadModel->setSortMode(RsGxsForumModel::SORT_MODE_PUBLISH_TS); } void GxsForumThreadWidget::filterColumnChanged(int column) From 73c06006dae4979f74ef2a66b43a5c0eed8df348 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Dec 2018 16:39:33 +0100 Subject: [PATCH 46/79] removed old code --- .../gui/gxsforums/GxsForumThreadWidget.cpp | 1477 ----------------- .../src/gui/gxsforums/GxsForumThreadWidget.h | 33 - .../src/gui/gxsforums/GxsForumsFillThread.cpp | 558 ------- .../src/gui/gxsforums/GxsForumsFillThread.h | 74 - retroshare-gui/src/retroshare-gui.pro | 2 - 5 files changed, 2144 deletions(-) delete mode 100644 retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp delete mode 100644 retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index dae56098f..a83d3d590 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -317,47 +317,8 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget { ui->setupUi(this); -#ifdef TO_REMOVE - mTokenTypeGroupData = nextTokenType(); - mTokenTypeInsertThreads = nextTokenType(); - mTokenTypeMessageData = nextTokenType(); - mTokenTypeReplyMessage = nextTokenType(); - mTokenTypeReplyForumMessage = nextTokenType(); - mTokenTypeShowAuthorInPeople = nextTokenType(); - mTokenTypeNegativeAuthor = nextTokenType(); - mTokenTypeNeutralAuthor = nextTokenType(); - mTokenTypePositiveAuthor = nextTokenType(); - mTokenTypeEditForumMessage = nextTokenType(); -#endif - setUpdateWhenInvisible(true); -#ifdef TO_REMOVE - /* Setup UI helper */ - mStateHelper->addWidget(mTokenTypeGroupData, ui->subscribeToolButton); - mStateHelper->addWidget(mTokenTypeGroupData, ui->newthreadButton); - - mStateHelper->addClear(mTokenTypeGroupData, ui->forumName); - - mStateHelper->addWidget(mTokenTypeInsertThreads, ui->progressBar, UISTATE_LOADING_VISIBLE); - mStateHelper->addWidget(mTokenTypeInsertThreads, ui->progressText, UISTATE_LOADING_VISIBLE); - mStateHelper->addWidget(mTokenTypeInsertThreads, ui->threadTreeWidget, UISTATE_ACTIVE_ENABLED); - mStateHelper->addLoadPlaceholder(mTokenTypeInsertThreads, ui->progressText); - mStateHelper->addWidget(mTokenTypeInsertThreads, ui->nextUnreadButton); - mStateHelper->addWidget(mTokenTypeInsertThreads, ui->previousButton); - mStateHelper->addWidget(mTokenTypeInsertThreads, ui->nextButton); -#ifdef SUSPENDED_CODE - mStateHelper->addClear(mTokenTypeInsertThreads, ui->threadTreeWidget); -#endif - - mStateHelper->addWidget(mTokenTypeMessageData, ui->newmessageButton); -// mStateHelper->addWidget(mTokenTypeMessageData, ui->postText); - mStateHelper->addWidget(mTokenTypeMessageData, ui->downloadButton); - - mStateHelper->addLoadPlaceholder(mTokenTypeMessageData, ui->postText); - //mStateHelper->addLoadPlaceholder(mTokenTypeMessageData, ui->threadTitle); -#endif - mSubscribeFlags = 0; mSignFlags = 0; mUnreadCount = 0; @@ -518,15 +479,6 @@ void GxsForumThreadWidget::blank() GxsForumThreadWidget::~GxsForumThreadWidget() { -#ifdef TO_REMOVE - if (mFillThread) { - mFillThread->stop(); - delete(mFillThread); - mFillThread = NULL; - } - delete(mThreadCompareRole); -#endif - // save settings processSettings(false); @@ -595,12 +547,6 @@ QString GxsForumThreadWidget::groupName(bool withUnreadCount) QIcon GxsForumThreadWidget::groupIcon() { -#ifdef TO_REMOVE - if (mStateHelper->isLoading(mTokenTypeGroupData) || mFillThread) { - return QIcon(":/images/kalarm.png"); - } -#endif - if (mNewCount) { return QIcon(":/images/message-state-new.png"); } @@ -933,11 +879,6 @@ void GxsForumThreadWidget::changedVersion() { mThreadId = RsGxsMessageId(ui->versions_CB->itemData(ui->versions_CB->currentIndex()).toString().toStdString()) ; -#ifdef TO_REMOVE - if (mFillThread) { - return; - } -#endif ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages()) ; insertMessage(); } @@ -991,140 +932,6 @@ void GxsForumThreadWidget::clickedThread(QModelIndex index) changedThread(index); } -#ifdef TO_REMOVE -void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item, bool &hasReadChilddren, bool &hasUnreadChilddren) -{ - uint32_t status = item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); - - bool isNew = IS_MSG_NEW(status); - bool unread = IS_MSG_UNREAD(status); - bool missing = item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_MISSING).toBool(); - RsGxsMessageId msgId(item->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::UserRole).toString().toStdString()); - - // set icon - if (missing) { - item->setIcon(RsGxsForumModel::COLUMN_THREAD_READ, QIcon()); - item->setIcon(RsGxsForumModel::COLUMN_THREAD_TITLE, QIcon()); - } else { - if (unread) { - item->setIcon(RsGxsForumModel::COLUMN_THREAD_READ, QIcon(":/images/message-state-unread.png")); - } else { - item->setIcon(RsGxsForumModel::COLUMN_THREAD_READ, QIcon(":/images/message-state-read.png")); - } - if (isNew) { - item->setIcon(RsGxsForumModel::COLUMN_THREAD_TITLE, QIcon(":/images/message-state-new.png")); - } else { - item->setIcon(RsGxsForumModel::COLUMN_THREAD_TITLE, QIcon()); - } - } - - int index; - int itemCount = item->childCount(); - - bool myReadChilddren = false; - bool myUnreadChilddren = false; - - for (index = 0; index < itemCount; ++index) { - calculateIconsAndFonts(item->child(index), myReadChilddren, myUnreadChilddren); - } - - bool is_pinned = mForumGroup.mPinnedPosts.ids.find(msgId) != mForumGroup.mPinnedPosts.ids.end(); - - // set font - for (int i = 0; i < RsGxsForumModel::COLUMN_THREAD_NB_COLUMNS; ++i) { - QFont qf = item->font(i); - - if (!IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { - qf.setBold(false); - item->setForeground(i, textColorNotSubscribed()); - } else if (unread || isNew) { - qf.setBold(true); - item->setForeground(i, textColorUnread()); - } else if (myUnreadChilddren) { - qf.setBold(true); - item->setForeground(i, textColorUnreadChildren()); - } else { - qf.setBold(false); - item->setForeground(i, textColorRead()); - } - if (missing) { - /* Missing message */ - item->setForeground(i, textColorMissing()); - } - if(is_pinned) - { - qf.setBold(true); - item->setForeground(i, textColorUnread()); - item->setData(i,Qt::BackgroundRole, QBrush(QColor(255,200,180))) ; - } - else - item->setData(i,Qt::BackgroundRole, QBrush()); - - item->setFont(i, qf); - } - - item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_READCHILDREN, hasReadChilddren || myReadChilddren); - item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_UNREADCHILDREN, hasUnreadChilddren || myUnreadChilddren); - - hasReadChilddren = hasReadChilddren || myReadChilddren || !unread; - hasUnreadChilddren = hasUnreadChilddren || myUnreadChilddren || unread; -} - -void GxsForumThreadWidget::calculateUnreadCount() -{ - unsigned int unreadCount = 0; - unsigned int newCount = 0; - - QTreeWidgetItemIterator itemIterator(ui->threadTreeWidget); - QTreeWidgetItem *item = NULL; - while ((item = *itemIterator) != NULL) { - ++itemIterator; - - uint32_t status = item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); - if (IS_MSG_UNREAD(status)) { - ++unreadCount; - } - if (IS_MSG_NEW(status)) { - ++newCount; - } - } - - bool changed = false; - if (mUnreadCount != unreadCount) { - mUnreadCount = unreadCount; - changed = true; - } - if (mNewCount != newCount) { - mNewCount = newCount; - changed = true; - } - - if (changed) { - emit groupChanged(this); - } -} - -void GxsForumThreadWidget::calculateIconsAndFonts(QTreeWidgetItem *item /*= NULL*/) -{ - bool dummy1 = false; - bool dummy2 = false; - - if (item) { - calculateIconsAndFonts(item, dummy1, dummy2); - return; - } - - int index; - int itemCount = ui->threadTreeWidget->topLevelItemCount(); - - for (index = 0; index < itemCount; ++index) { - dummy1 = false; - dummy2 = false; - calculateIconsAndFonts(ui->threadTreeWidget->topLevelItem(index), dummy1, dummy2); - } -} -#endif - static void cleanupItems (QList &items) { QList::iterator item; @@ -1136,17 +943,6 @@ static void cleanupItems (QList &items) items.clear(); } -#ifdef TO_REMOVE -void GxsForumThreadWidget::insertGroupData() -{ -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::insertGroupData" << std::endl; -#endif - //GxsIdDetails::process(mForumGroup.mMeta.mAuthorId, &loadAuthorIdCallback, this); - calculateIconsAndFonts(); -} -#endif - static QString getDurationString(uint32_t days) { switch(days) @@ -1163,699 +959,10 @@ static QString getDurationString(uint32_t days) } } -#ifdef TO_REMOVE -/*static*/ void GxsForumThreadWidget::loadAuthorIdCallback(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &) -{ - GxsForumThreadWidget *tw = dynamic_cast(object); - if(!tw) - return; - - QString author; - switch (type) { - case GXS_ID_DETAILS_TYPE_EMPTY: - author = GxsIdDetails::getEmptyIdText(); - break; - case GXS_ID_DETAILS_TYPE_FAILED: - author = GxsIdDetails::getFailedText(details.mId); - break; - case GXS_ID_DETAILS_TYPE_LOADING: - author = GxsIdDetails::getLoadingText(details.mId); - break; - case GXS_ID_DETAILS_TYPE_BANNED: - author = tr("[Banned]") ; - break ; - case GXS_ID_DETAILS_TYPE_DONE: - author = GxsIdDetails::getName(details); - break; - } - - const RsGxsForumGroup& group = tw->mForumGroup; - - tw->mSubscribeFlags = group.mMeta.mSubscribeFlags; - tw->mSignFlags = group.mMeta.mSignFlags; - tw->ui->forumName->setText(QString::fromUtf8(group.mMeta.mGroupName.c_str())); - - QString anti_spam_features1 ; - if(IS_GROUP_PGP_KNOWN_AUTHED(tw->mSignFlags)) anti_spam_features1 = tr("Anonymous/unknown posts forwarded if reputation is positive"); - else if(IS_GROUP_PGP_AUTHED(tw->mSignFlags)) anti_spam_features1 = tr("Anonymous posts forwarded if reputation is positive"); - - tw->mForumDescription = QString("%1: \t%2
").arg(tr("Forum name"), QString::fromUtf8( group.mMeta.mGroupName.c_str())); - tw->mForumDescription += QString("%1: %2
").arg(tr("Description"), - group.mDescription.empty()? - tr("[None]
") - :(QString::fromUtf8(group.mDescription.c_str())+"
")); - tw->mForumDescription += QString("%1: \t%2
").arg(tr("Subscribers")).arg(group.mMeta.mPop); - tw->mForumDescription += QString("%1: \t%2
").arg(tr("Posts (at neighbor nodes)")).arg(group.mMeta.mVisibleMsgCount); - if(group.mMeta.mLastPost==0) - tw->mForumDescription += QString("%1: \t%2
").arg(tr("Last post")).arg(tr("Never")); - else - tw->mForumDescription += QString("%1: \t%2
").arg(tr("Last post")).arg(DateTime::formatLongDateTime(group.mMeta.mLastPost)); - tw->mForumDescription += QString("%1: \t%2
").arg(tr("Synchronization")).arg(getDurationString( rsGxsForums->getSyncPeriod(group.mMeta.mGroupId)/86400 )) ; - tw->mForumDescription += QString("%1: \t%2
").arg(tr("Storage")).arg(getDurationString( rsGxsForums->getStoragePeriod(group.mMeta.mGroupId)/86400)); - - QString distrib_string = tr("[unknown]"); - switch(group.mMeta.mCircleType) - { - case GXS_CIRCLE_TYPE_PUBLIC: distrib_string = tr("Public") ; - break ; - case GXS_CIRCLE_TYPE_EXTERNAL: - { - RsGxsCircleDetails det ; - - // !! What we need here is some sort of CircleLabel, which loads the circle and updates the label when done. - - if(rsGxsCircles->getCircleDetails(group.mMeta.mCircleId,det)) - distrib_string = tr("Restricted to members of circle \"")+QString::fromUtf8(det.mCircleName.c_str()) +"\""; - else - distrib_string = tr("Restricted to members of circle ")+QString::fromStdString(group.mMeta.mCircleId.toStdString()) ; - } - break ; - case GXS_CIRCLE_TYPE_YOUR_FRIENDS_ONLY: - { - distrib_string = tr("Only friends nodes in group ") ; - - RsGroupInfo ginfo ; - rsPeers->getGroupInfo(RsNodeGroupId(group.mMeta.mInternalCircle),ginfo) ; - - QString desc; - GroupChooser::makeNodeGroupDesc(ginfo, desc); - distrib_string += desc ; - } - break ; - - case GXS_CIRCLE_TYPE_LOCAL: distrib_string = tr("Your eyes only"); // this is not yet supported. If you see this, it is a bug! - break ; - default: - std::cerr << "(EE) badly initialised group distribution ID = " << group.mMeta.mCircleType << std::endl; - } - - tw->mForumDescription += QString("%1: \t%2
").arg(tr("Distribution"), distrib_string); - tw->mForumDescription += QString("%1: \t%2
").arg(tr("Contact"), author); - - if(!anti_spam_features1.isNull()) - tw->mForumDescription += QString("%1: \t%2
").arg(tr("Anti-spam")).arg(anti_spam_features1); - - tw->ui->subscribeToolButton->setSubscribed(IS_GROUP_SUBSCRIBED(tw->mSubscribeFlags)); - tw->mStateHelper->setWidgetEnabled(tw->ui->newthreadButton, (IS_GROUP_SUBSCRIBED(tw->mSubscribeFlags))); - - if(!group.mAdminList.ids.empty()) - { - QString admin_list_str ; - - for(auto it(group.mAdminList.ids.begin());it!=group.mAdminList.ids.end();++it) - { - RsIdentityDetails det ; - - rsIdentity->getIdDetails(*it,det); - admin_list_str += (admin_list_str.isNull()?"":", ") + QString::fromUtf8(det.mNickname.c_str()) ; - } - - tw->mForumDescription += QString("%1: %2").arg(tr("Moderators"), admin_list_str); - } - - if (tw->mThreadId.isNull() && !tw->mStateHelper->isLoading(tw->mTokenTypeMessageData)) - tw->ui->postText->setText(tw->mForumDescription); -} - -void GxsForumThreadWidget::fillThreadFinished() -{ -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::fillThreadFinished" << std::endl; -#endif - - // thread has finished - GxsForumsFillThread *thread = dynamic_cast(sender()); - if (thread) { - if (thread == mFillThread) { - // current thread has finished, hide progressbar and release thread - mFillThread = NULL; - - mStateHelper->setLoading(mTokenTypeInsertThreads, false); - emit groupChanged(this); - } - - if (thread->wasStopped()) { - // thread was stopped -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::fillThreadFinished Thread was stopped" << std::endl; -#endif - } else { -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::fillThreadFinished Add messages" << std::endl; -#endif - - mStateHelper->setActive(mTokenTypeInsertThreads, true); - ui->threadTreeWidget->setSortingEnabled(false); - - GxsIdDetails::enableProcess(false); - - /* add all messages in! */ - if (mLastViewType != thread->mViewType || mLastForumID != groupId()) { - ui->threadTreeWidget->clear(); - mLastViewType = thread->mViewType; - mLastForumID = groupId(); - ui->threadTreeWidget->insertTopLevelItems(0, thread->mItems); - mPostVersions = thread->mPostVersions; - - // clear list - thread->mItems.clear(); - } else { - mPostVersions = thread->mPostVersions; - fillThreads(thread->mItems, thread->mExpandNewMessages, thread->mItemToExpand); - - // cleanup list - cleanupItems(thread->mItems); - } - - /* Move value from ROLE_THREAD_AUTHOR to GxsIdRSTreeWidgetItem::setId */ - QTreeWidgetItemIterator itemIterator(ui->threadTreeWidget); - QTreeWidgetItem *item = NULL; - while ((item = *itemIterator) != NULL) { - ++itemIterator; - - QString gxsId = item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_AUTHOR).toString(); - if (gxsId.isEmpty()) { - continue; - } - - item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_AUTHOR, QVariant()); - - GxsIdRSTreeWidgetItem *gxsIdItem = dynamic_cast(item); - if (gxsIdItem) { - gxsIdItem->setId(RsGxsId(gxsId.toStdString()), RsGxsForumModel::COLUMN_THREAD_AUTHOR, false); - } - } - - GxsIdDetails::enableProcess(true); - - ui->threadTreeWidget->setSortingEnabled(true); - - if (thread->mFocusMsgId.empty() == false) { - /* Search exisiting item */ - QTreeWidgetItemIterator itemIterator(ui->threadTreeWidget); - QTreeWidgetItem *item = NULL; - while ((item = *itemIterator) != NULL) { - ++itemIterator; - - if (item->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString().toStdString() == thread->mFocusMsgId) { - ui->threadTreeWidget->setCurrentItem(item); - ui->threadTreeWidget->setFocus(); - break; - } - } - } - - QList::iterator itemIt; - for (itemIt = thread->mItemToExpand.begin(); itemIt != thread->mItemToExpand.end(); ++itemIt) { - if ((*itemIt)->isHidden() == false) { - (*itemIt)->setExpanded(true); - } - } - thread->mItemToExpand.clear(); - - if (ui->filterLineEdit->text().isEmpty() == false) { - filterItems(ui->filterLineEdit->text()); - } - calculateIconsAndFonts(); - calculateUnreadCount(); - emit groupChanged(this); - - if (!mNavigatePendingMsgId.isNull()) { - navigate(mNavigatePendingMsgId); - mNavigatePendingMsgId.clear(); - } - } - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::fillThreadFinished Delete thread" << std::endl; -#endif - - thread->deleteLater(); - thread = NULL; - } - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::fillThreadFinished done" << std::endl; -#endif -} - -void GxsForumThreadWidget::fillThreadProgress(int current, int count) -{ - // show fill progress - if (count) { - int max = ui->progressBar->maximum(); - ui->progressBar->setValue(current * max / count); - } -} - -void GxsForumThreadWidget::fillThreadStatus(QString text) -{ - ui->progressText->setText(text); -} - -//#define DEBUG_PINNED_POST_SORTING 1 - -class ForumThreadItem: public GxsIdRSTreeWidgetItem -{ -public: - ForumThreadItem(QHeaderView *header,const RSTreeWidgetItemCompareRole *compareRole, uint32_t icon_mask,QTreeWidget *parent = NULL) - : GxsIdRSTreeWidgetItem(compareRole,icon_mask,parent), m_header(header) {} - - bool operator<(const QTreeWidgetItem& other) const - { - bool left_is_not_pinned = ! data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_PINNED).toBool(); - bool right_is_not_pinned = !other.data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_PINNED).toBool(); -#ifdef DEBUG_PINNED_POST_SORTING - std::cerr << "Comparing item date \"" << data(RsGxsForumModel::COLUMN_THREAD_DATE,Qt::DisplayRole).toString().toStdString() << "\" (" - << data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toUInt() << ", \"" << data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toString().toStdString() << "\" --> " << left_is_not_pinned << ") to \"" - << other.data(RsGxsForumModel::COLUMN_THREAD_DATE,Qt::DisplayRole).toString().toStdString() << "\" (" - << other.data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toUInt() << ", \"" << other.data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toString().toStdString() << "\" --> " << right_is_not_pinned << ") "; -#endif - - if(left_is_not_pinned ^ right_is_not_pinned) - { -#ifdef DEBUG_PINNED_POST_SORTING - std::cerr << "Local: " << ((m_header->sortIndicatorOrder()==Qt::AscendingOrder)?right_is_not_pinned:left_is_not_pinned) << std::endl; -#endif - return (m_header->sortIndicatorOrder()==Qt::AscendingOrder)?right_is_not_pinned:left_is_not_pinned ; // always put pinned posts on top - } - -#ifdef DEBUG_PINNED_POST_SORTING - std::cerr << "Remote: " << GxsIdRSTreeWidgetItem::operator<(other) << std::endl; -#endif - return GxsIdRSTreeWidgetItem::operator<(other); - } - -private: - QHeaderView *m_header ; -}; - -QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForumMsg &msg, bool useChildTS, uint32_t filterColumn, QTreeWidgetItem *parent) -{ - // Early check for a message that should be hidden because its author - // is flagged with a bad reputation - - bool is_pinned = mForumGroup.mPinnedPosts.ids.find(msg.mMeta.mMsgId) != mForumGroup.mPinnedPosts.ids.end(); - - uint32_t idflags =0; - RsReputations::ReputationLevel reputation_level = rsReputations->overallReputationLevel(msg.mMeta.mAuthorId,&idflags) ; - bool redacted = false; - - redacted = (reputation_level == RsReputations::REPUTATION_LOCALLY_NEGATIVE); - - // We use a specific item model for forums in order to handle the post pinning. - - GxsIdRSTreeWidgetItem *item = new ForumThreadItem(ui->threadTreeWidget->header(),mThreadCompareRole,GxsIdDetails::ICON_TYPE_AVATAR ); - item->moveToThread(ui->threadTreeWidget->thread()); - - if(redacted) - item->setText(RsGxsForumModel::COLUMN_THREAD_TITLE, tr("[ ... Redacted message ... ]")); - else if(is_pinned) - item->setText(RsGxsForumModel::COLUMN_THREAD_TITLE, tr("[PINNED] ") + QString::fromUtf8(msg.mMeta.mMsgName.c_str())); - else - item->setText(RsGxsForumModel::COLUMN_THREAD_TITLE, QString::fromUtf8(msg.mMeta.mMsgName.c_str())); - - QString rep_tooltip_str ; - uint32_t rep_warning_level ; - - if(reputation_level == RsReputations::REPUTATION_UNKNOWN) - { - rep_warning_level = 3 ; - rep_tooltip_str = tr("Information for this identity is currently missing.") ; - } - else if(reputation_level == RsReputations::REPUTATION_LOCALLY_NEGATIVE) - { - rep_warning_level = 2 ; - rep_tooltip_str = tr("You have banned this ID. The message will not be\ndisplayed nor forwarded to your friends.") ; - } - else if(reputation_level < rsGxsForums->minReputationForForwardingMessages(mForumGroup.mMeta.mSignFlags,idflags)) - { - rep_warning_level = 1 ; - rep_tooltip_str = tr("You have not set an opinion for this person,\n and your friends do not vote positively: Spam regulation \nprevents the message to be forwarded to your friends.") ; - } - else - { - rep_warning_level = 0 ; - rep_tooltip_str = tr("Message will be forwarded to your friends.") ; - } - - item->setData(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,Qt::ToolTipRole,rep_tooltip_str) ; - item->setData(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,Qt::DecorationRole,rep_warning_level) ; - - //msg.mMeta.mChildTs Was not updated when received new child - // so do it here. - QDateTime qtime; - qtime.setTime_t(msg.mMeta.mPublishTs); - - QString itemText = DateTime::formatDateTime(qtime); - // This is an attempt to put pinned posts on the top. We should rather use a QSortFilterProxyModel here. - QString itemSort = QString::number(msg.mMeta.mPublishTs);//Don't need to format it as for sort. - -//#define SHOW_COMBINED_DATES 1 - - if (useChildTS) - { - for(QTreeWidgetItem *grandParent = parent; grandParent!=NULL; grandParent = grandParent->parent()) - { - //Update Parent Child TimeStamp - QString oldTSSort = grandParent->data(RsGxsForumModel::COLUMN_THREAD_DATE, ROLE_THREAD_SORT).toString(); - - QString oldCTSSort = oldTSSort.split("|").at(0); - QString oldPTSSort = oldTSSort.contains("|") ? oldTSSort.split(" | ").at(1) : oldCTSSort; -#ifdef SHOW_COMBINED_DATES - QString oldTSText = grandParent->text(RsGxsForumModel::COLUMN_THREAD_DATE); - QString oldCTSText = oldTSText.split("|").at(0); - QString oldPTSText = oldTSText.contains("|") ? oldTSText.split(" | ").at(1) : oldCTSText;//If first time parent get only its mPublishTs - #endif - if (oldCTSSort.toDouble() < itemSort.toDouble()) - { -#ifdef SHOW_COMBINED_DATES - grandParent->setText(RsGxsForumModel::COLUMN_THREAD_DATE, DateTime::formatDateTime(qtime) + " | " + oldPTSText); -#endif - grandParent->setData(RsGxsForumModel::COLUMN_THREAD_DATE, ROLE_THREAD_SORT, itemSort + " | " + oldPTSSort); - } - } - } - - item->setText(RsGxsForumModel::COLUMN_THREAD_DATE, itemText); - item->setData(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT, itemSort); - - if(is_pinned) - item->setData(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_PINNED, QVariant(true)); // this is used by the sorting model to put all posts on top - else - item->setData(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_PINNED, QVariant(false)); - - // Set later with GxsIdRSTreeWidgetItem::setId -#ifdef TODO - item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_AUTHOR, QString::fromStdString(msg.mMeta.mAuthorId.toStdString())); -#endif - -//#TODO -#if 0 - text = QString::fromUtf8(authorName.c_str()); - - if (text.isEmpty()) - { - item->setText(RsGxsForumModel::COLUMN_THREAD_AUTHOR, tr("Anonymous")); - } - else - { - item->setText(RsGxsForumModel::COLUMN_THREAD_AUTHOR, text); - } -#endif -//#TODO -#ifdef TOGXS - if (msgInfo.mMeta.mMsgFlags & RS_DISTRIB_AUTHEN_REQ) - { - item->setText(RsGxsForumModel::COLUMN_THREAD_SIGNED, tr("signed")); - item->setIcon(RsGxsForumModel::COLUMN_THREAD_SIGNED, QIcon(":/images/mail-signed.png")); - } - else - { - item->setText(RsGxsForumModel::COLUMN_THREAD_SIGNED, tr("none")); - item->setIcon(RsGxsForumModel::COLUMN_THREAD_SIGNED, QIcon(":/images/mail-signature-unknown.png")); - } -#endif - - if (filterColumn == RsGxsForumModel::COLUMN_THREAD_CONTENT) { - // need content for filter - QTextDocument doc; - doc.setHtml(QString::fromUtf8(msg.mMsg.c_str())); - item->setText(RsGxsForumModel::COLUMN_THREAD_CONTENT, doc.toPlainText().replace(QString("\n"), QString(" "))); - } - - item->setData(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::UserRole, QString::fromStdString(msg.mMeta.mMsgId.toStdString())); -//#TODO -#if 0 - if (IS_GROUP_SUBSCRIBED(subscribeFlags) && !(msginfo.mMsgFlags & RS_DISTRIB_MISSING_MSG)) { - rsGxsForums->getMessageStatus(msginfo.forumId, msginfo.msgId, status); - } else { - // show message as read - status = RSGXS_MSG_STATUS_READ; - } - item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS, msg.mMeta.mMsgStatus); - item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_MISSING, false); -#endif - - if (parent) parent->addChild(item); - return item; -} - -void GxsForumThreadWidget::insertThreads() -{ -#ifdef DEBUG_FORUMS - /* get the current Forum */ - std::cerr << "GxsForumThreadWidget::insertThreads()" << std::endl; -#endif - - mNavigatePendingMsgId.clear(); - ui->progressBar->reset(); - - if (mFillThread) { -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::insertThreads() stop current fill thread" << std::endl; -#endif - // stop current fill thread - GxsForumsFillThread *thread = mFillThread; - mFillThread = NULL; - thread->stop(); - - mStateHelper->setLoading(mTokenTypeInsertThreads, false); - } - - if (groupId().isNull()) - { - /* not an actual forum - clear */ - mStateHelper->setActive(mTokenTypeInsertThreads, false); - mStateHelper->clear(mTokenTypeInsertThreads); - - /* clear last stored forumID */ - mLastForumID.clear(); - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::insertThreads() Current Thread Invalid" << std::endl; -#endif - - return; - } - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::insertThreads() Start filling Forum threads" << std::endl; -#endif - - mStateHelper->setLoading(mTokenTypeInsertThreads, true); - - // create fill thread - mFillThread = new GxsForumsFillThread(this); - - // set data - mFillThread->mCompareRole = mThreadCompareRole; - mFillThread->mForumId = groupId(); - mFillThread->mFilterColumn = ui->filterLineEdit->currentFilter(); - mFillThread->mExpandNewMessages = Settings->getForumExpandNewMessages(); - mFillThread->mViewType = ui->viewBox->currentIndex(); - if (mLastViewType != mFillThread->mViewType || mLastForumID != groupId()) { - mFillThread->mFillComplete = true; - } - - mFillThread->mFlatView = false; - mFillThread->mUseChildTS = false; - - switch (mFillThread->mViewType) { - case VIEW_LAST_POST: - mFillThread->mUseChildTS = true; - break; - case VIEW_FLAT: - mFillThread->mFlatView = true; - break; - case VIEW_THREADED: - break; - } - - ui->threadTreeWidget->setRootIsDecorated(!mFillThread->mFlatView); - - // connect thread - // connect(mFillThread, SIGNAL(finished()), this, SLOT(fillThreadFinished()), Qt::BlockingQueuedConnection); - // connect(mFillThread, SIGNAL(status(QString)), this, SLOT(fillThreadStatus(QString))); - // connect(mFillThread, SIGNAL(progress(int,int)), this, SLOT(fillThreadProgress(int,int))); - -#ifdef DEBUG_FORUMS - std::cerr << "ForumsDialog::insertThreads() Start fill thread" << std::endl; -#endif - - // start thread - mFillThread->start(); - emit groupChanged(this); -} - -static void copyItem(QTreeWidgetItem *item, const QTreeWidgetItem *newItem) -{ - int i; - for (i = 0; i < RsGxsForumModel::COLUMN_THREAD_COUNT; ++i) { - if (i != RsGxsForumModel::COLUMN_THREAD_AUTHOR) { - /* Copy text */ - item->setText(i, newItem->text(i)); - } - } - for (i = 0; i < ROLE_THREAD_COUNT; ++i) { - item->setData(RsGxsForumModel::COLUMN_THREAD_DATA, Qt::UserRole + i, newItem->data(RsGxsForumModel::COLUMN_THREAD_DATA, Qt::UserRole + i)); - } - - item->setData(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,Qt::DecorationRole,newItem->data(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,Qt::DecorationRole)); - item->setData(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,Qt::ToolTipRole, newItem->data(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,Qt::ToolTipRole )); - item->setData(RsGxsForumModel::COLUMN_THREAD_MSGID, Qt::DisplayRole, newItem->data(RsGxsForumModel::COLUMN_THREAD_MSGID, Qt::DisplayRole )); -} - -void GxsForumThreadWidget::fillThreads(QList &threadList, bool expandNewMessages, QList &itemToExpand) -{ -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::fillThreads()" << std::endl; -#endif - - int index = 0; - QTreeWidgetItem *threadItem; - - // store new items in a map, so as to allow a fast search - - std::map newThreadMap ; - - for(QList::iterator newThread = threadList.begin (); newThread != threadList.end (); ++newThread) - newThreadMap[(*newThread)->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()] = *newThread ; - - // delete not existing - while (index < ui->threadTreeWidget->topLevelItemCount()) - { - threadItem = ui->threadTreeWidget->topLevelItem(index); - - if(newThreadMap.find(threadItem->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()) == newThreadMap.end()) - delete(ui->threadTreeWidget->takeTopLevelItem(index)); - else - ++index; - } - - //(csoler) QTreeWidget::findItems apparently does not always work so I need to make the search manually, which I do using a map for efficiency reasons. - std::map oldThreadMap; - for(int i=0; ithreadTreeWidget->topLevelItemCount(); ++i) - oldThreadMap[ui->threadTreeWidget->topLevelItem(i)->data(RsGxsForumModel::COLUMN_THREAD_MSGID, Qt::DisplayRole).toString()] = ui->threadTreeWidget->topLevelItem(i); - - // iterate all new threads - for (QList::iterator newThread = threadList.begin (); newThread != threadList.end (); ++newThread) { - // search existing thread -#ifdef DEBUG_FORUMS - std::cerr << "Makign a search for string \"" << (*newThread)->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString().toStdString() << "\"" << std::endl; -#endif - - std::map::const_iterator it = oldThreadMap.find((*newThread)->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()) ; - - if(it != oldThreadMap.end()) - { - threadItem = it->second ; - - // set child data - copyItem(threadItem, *newThread); - - // fill recursive - fillChildren(threadItem, *newThread, expandNewMessages, itemToExpand); - } - else - { - // add new thread - ui->threadTreeWidget->addTopLevelItem (*newThread); - threadItem = *newThread; - *newThread = NULL; - } - - uint32_t status = threadItem->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); - if (expandNewMessages && IS_MSG_UNREAD(status)) { - QTreeWidgetItem *parentItem = threadItem; - while ((parentItem = parentItem->parent()) != NULL) { - if (std::find(itemToExpand.begin(), itemToExpand.end(), parentItem) == itemToExpand.end()) { - itemToExpand.push_back(parentItem); - } - } - } - } - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::fillThreads() done" << std::endl; -#endif -} -#endif - -#ifdef TO_REMOVE -void GxsForumThreadWidget::fillChildren(QTreeWidgetItem *parentItem, QTreeWidgetItem *newParentItem, bool expandNewMessages, QList &itemToExpand) -{ - int index = 0; - int newIndex; - int newCount = newParentItem->childCount(); - - QTreeWidgetItem *childItem; - QTreeWidgetItem *newChildItem; - - std::map newParentItemMap, parentItemMap ; - - for(index = 0; index < newParentItem->childCount(); ++index) newParentItemMap[newParentItem->child(index)->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()] = newParentItem->child(index); - for(index = 0; index < parentItem->childCount(); ++index) parentItemMap[ parentItem->child(index)->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()] = parentItem->child(index); - - // delete not existing - while (index < parentItem->childCount()) - { - childItem = parentItem->child(index); - - if(newParentItemMap.find(childItem->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()) == newParentItemMap.end()) - delete(parentItem->takeChild (index)); - else - ++index; - } - - // iterate all new children - for (newIndex = 0; newIndex < newParentItem->childCount(); ++newIndex) - { - newChildItem = newParentItem->child(newIndex); - - // search existing child - - std::map::const_iterator it = parentItemMap.find(newChildItem->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString()) ; - - if(it != parentItemMap.end()) - { - // set child data - copyItem(it->second, newChildItem); - - // fill recursive - fillChildren(it->second, newChildItem, expandNewMessages, itemToExpand); - childItem = it->second; - } - else - { - // add new child - childItem = newParentItem->takeChild(newIndex); - parentItem->addChild(childItem); - newIndex--; - newCount--; - } - - uint32_t status = childItem->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); - if (expandNewMessages && IS_MSG_UNREAD(status)) { - QTreeWidgetItem *parentItem = childItem; - while ((parentItem = parentItem->parent()) != NULL) { - if (std::find(itemToExpand.begin(), itemToExpand.end(), parentItem) == itemToExpand.end()) { - itemToExpand.push_back(parentItem); - } - } - } - } -} -#endif - void GxsForumThreadWidget::insertMessage() { if (groupId().isNull()) { -#ifdef SUSPENDED_CODE - mStateHelper->setActive(mTokenTypeMessageData, false); - mStateHelper->clear(mTokenTypeMessageData); -#endif ui->versions_CB->hide(); ui->time_label->show(); @@ -1865,11 +972,6 @@ void GxsForumThreadWidget::insertMessage() if (mThreadId.isNull()) { -#ifdef SUSPENDED_CODE - mStateHelper->setActive(mTokenTypeMessageData, false); - mStateHelper->clear(mTokenTypeMessageData); -#endif - ui->versions_CB->hide(); ui->time_label->show(); @@ -1877,10 +979,6 @@ void GxsForumThreadWidget::insertMessage() return; } -#ifdef SUSPENDED_CODE - mStateHelper->setActive(mTokenTypeMessageData, true); -#endif - QModelIndex index = getCurrentIndex(); if (index.isValid()) @@ -1972,10 +1070,6 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) std::cerr << "\t or CurrThdId: " << mThreadId << " != msg.MsgId: " << msg.mMeta.mMsgId; std::cerr << std::endl; std::cerr << std::endl; -#ifdef TO_REMOVE - mStateHelper->setActive(mTokenTypeMessageData, false); - mStateHelper->clear(mTokenTypeMessageData); -#endif return; } @@ -1983,13 +1077,6 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) uint32_t overall_reputation = rsReputations->overallReputationLevel(msg.mMeta.mAuthorId) ; bool redacted = (overall_reputation == RsReputations::REPUTATION_LOCALLY_NEGATIVE) ; -#ifdef TO_REMOVE - mStateHelper->setActive(mTokenTypeMessageData, true); - - //mThreadId = mOrigThreadId = RsGxsMessageId(mThreadModel->data(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_MSGID),Qt::DisplayRole).toString().toStdString()); - //QTreeWidgetItem *item = ui->threadTreeWidget->currentItem(); -#endif - bool setToReadOnActive = Settings->getForumMsgSetToReadOnActivate(); uint32_t status = msg.mMeta.mMsgStatus ;//item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); @@ -2123,106 +1210,6 @@ void GxsForumThreadWidget::nextUnreadMessage() changedThread(index); } -#ifdef TO_REMOVE -/* get selected messages - the messages tree is single selected, but who knows ... */ -int GxsForumThreadWidget::getSelectedMsgCount(QList *rows, QList *rowsRead, QList *rowsUnread) -{ - if (rowsRead) rowsRead->clear(); - if (rowsUnread) rowsUnread->clear(); - - QList selectedItems = ui->threadTreeWidget->selectedItems(); - for(QList::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it) { - if (rows) rows->append(*it); - if (rowsRead || rowsUnread) { - uint32_t status = (*it)->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); - if (IS_MSG_UNREAD(status)) { - if (rowsUnread) rowsUnread->append(*it); - } else { - if (rowsRead) rowsRead->append(*it); - } - } - } - - return selectedItems.size(); - return 0; -} - -void GxsForumThreadWidget::setMsgReadStatus(QList &rows, bool read) -{ - QList::iterator row; - std::list changedItems; - - mInMsgAsReadUnread = true; - - for (row = rows.begin(); row != rows.end(); ++row) { - if ((*row)->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_MISSING).toBool()) { - /* Missing message */ - continue; - } - - uint32_t status = (*row)->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); - - uint32_t statusNew = (status & ~(GXS_SERV::GXS_MSG_STATUS_GUI_NEW | GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD)); // orig status, without NEW AND UNREAD - if (!read) { - statusNew |= GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD; - } - - if (status != statusNew) // is it different? - { - std::string msgId = (*row)->data(RsGxsForumModel::COLUMN_THREAD_MSGID,Qt::DisplayRole).toString().toStdString(); - - // NB: MUST BE PART OF ACTIVE THREAD--- OR ELSE WE MUST STORE GROUPID SOMEWHERE!. - // LIKE THIS BELOW... - //std::string grpId = (*Row)->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_GROUPID).toString().toStdString(); - - RsGxsGrpMsgIdPair msgPair = std::make_pair( groupId(), RsGxsMessageId(msgId) ); - - uint32_t token; - rsGxsForums->setMessageReadStatus(token, msgPair, read); - - // Look if older version exist to mark them too - QMap > >::const_iterator it = mPostVersions.find(RsGxsMessageId(msgId)) ; - if(it != mPostVersions.end()) - { - std::cerr << (*it).size() << " versions found " << std::endl; - for(int i=0;i<(*it).size();++i) - { - RsGxsMessageId found = (*it)[i].second; - if(found != RsGxsMessageId(msgId)) - { - msgPair = std::make_pair( groupId(), found ); - rsGxsForums->setMessageReadStatus(token, msgPair, read); - } - } - } - - /* Add message id to ignore list for the next updateDisplay */ - mIgnoredMsgId.push_back(RsGxsMessageId(msgId)); - - (*row)->setData(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS, statusNew); - - QTreeWidgetItem *parentItem = *row; - while (parentItem->parent()) { - parentItem = parentItem->parent(); - } - if (std::find(changedItems.begin(), changedItems.end(), parentItem) == changedItems.end()) { - changedItems.push_back(parentItem); - } - } - } - - mInMsgAsReadUnread = false; - - if (changedItems.size()) { - for (std::list::iterator it = changedItems.begin(); it != changedItems.end(); ++it) { - calculateIconsAndFonts(*it); - } - calculateUnreadCount(); - } -} -#endif - void GxsForumThreadWidget::markMsgAsReadUnread (bool read, bool children, bool forum) { if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { @@ -2242,51 +1229,6 @@ void GxsForumThreadWidget::markMsgAsReadUnread (bool read, bool children, bool f mThreadModel->setMsgReadStatus(mThreadProxyModel->mapToSource(index),read,children); } - -#ifdef TODO - /* get selected messages */ - QList rows; - if (forum) { - int itemCount = ui->threadTreeWidget->topLevelItemCount(); - for (int item = 0; item < itemCount; ++item) { - rows.push_back(ui->threadTreeWidget->topLevelItem(item)); - } - } else { - getSelectedMsgCount (&rows, NULL, NULL); - } - - if (children) { - /* add children */ - QList allRows; - - while (rows.isEmpty() == false) { - QTreeWidgetItem *row = rows.takeFirst(); - - /* add only items with the right state or with not RSGXS_MSG_STATUS_READ */ - uint32_t status = row->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); - bool isUnread = IS_MSG_UNREAD(status); - if (isUnread == read || IS_MSG_NEW(status)) { - allRows.append(row); - } - - for (int i = 0; i < row->childCount(); ++i) { - /* add child to main list and let the main loop do the work */ - rows.append(row->child(i)); - } - } - - if (allRows.isEmpty()) { - /* nothing to do */ - return; - } - - setMsgReadStatus(allRows, read); - - return; - } - - setMsgReadStatus(rows, read); -#endif } void GxsForumThreadWidget::markMsgAsRead() @@ -2327,17 +1269,6 @@ bool GxsForumThreadWidget::navigate(const RsGxsMessageId &msgId) return true; } -#ifdef TO_REMOVE -bool GxsForumThreadWidget::isLoading() -{ - if (mStateHelper->isLoading(mTokenTypeGroupData) || mFillThread) { - return true; - } - - return GxsMessageFrameWidget::isLoading(); -} -#endif - void GxsForumThreadWidget::copyMessageLink() { if (groupId().isNull() || mThreadId.isNull()) { @@ -2459,26 +1390,6 @@ void GxsForumThreadWidget::flagperson() std::cerr << "Setting own opinion for author " << fmpe.mAuthorId << " to " << opinion << std::endl; rsReputations->setOwnOpinion(fmpe.mAuthorId,opinion) ; - -#ifdef TO_REMOVE - // Get Message ... then complete replyMessageData(). - RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId); - - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::requestMsgData_BanAuthor(" << postId.first << "," << postId.second << ")"; - std::cerr << std::endl; -#endif - - GxsMsgReq msgIds; - std::set &vect = msgIds[postId.first]; - vect.insert(postId.second); - - uint32_t token; - mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, token_type); -#endif } void GxsForumThreadWidget::replytoforummessage() { async_msg_action( &GxsForumThreadWidget::replyForumMessageData ); } @@ -2668,12 +1579,6 @@ void GxsForumThreadWidget::changedViewBox() void GxsForumThreadWidget::filterColumnChanged(int column) { -#ifdef TO_REMOVE - if (column == RsGxsForumModel::COLUMN_THREAD_CONTENT) { - // need content ... refill - //insertThreads(); - } else { -#endif filterItems(ui->filterLineEdit->text()); // save index @@ -2770,10 +1675,6 @@ void GxsForumThreadWidget::updateGroupData() if(groups.size() != 1) { std::cerr << __PRETTY_FUNCTION__ << " obtained more than one group info for forum " << groupId() << std::endl; -#ifdef TO_REMOVE - mStateHelper->setActive(mTokenTypeGroupData, false); - mStateHelper->clear(mTokenTypeGroupData); -#endif return; } @@ -2825,10 +1726,6 @@ void GxsForumThreadWidget::updateMessageData(const RsGxsMessageId& msgId) if(msgs.size() != 1) { std::cerr << __PRETTY_FUNCTION__ << " obtained more than one msg info for msgId " << msgId << std::endl; -#ifdef TO_REMOVE - mStateHelper->setActive(mTokenTypeGroupData, false); - mStateHelper->clear(mTokenTypeGroupData); -#endif return; } @@ -2857,281 +1754,6 @@ void GxsForumThreadWidget::updateMessageData(const RsGxsMessageId& msgId) } -#ifdef TO_REMOVE -void GxsForumThreadWidget::requestGroupData() -{ - mSubscribeFlags = 0; - mSignFlags = 0; - mForumDescription.clear(); - - mTokenQueue->cancelActiveRequestTokens(mTokenTypeGroupData); - emit groupChanged(this); - - if (groupId().isNull()) { - mStateHelper->setActive(mTokenTypeGroupData, false); - mStateHelper->setLoading(mTokenTypeGroupData, false); - mStateHelper->clear(mTokenTypeGroupData); - - return; - } - - mStateHelper->setLoading(mTokenTypeGroupData, true); - - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; - - std::list grpIds; - grpIds.push_back(groupId()); - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::requestGroupData(" << groupId() << ")"; - std::cerr << std::endl; -#endif - - uint32_t token; - mTokenQueue->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, grpIds, mTokenTypeGroupData); -} - -void GxsForumThreadWidget::loadGroupData(const uint32_t &token) -{ -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::loadGroup_CurrentForum()"; - std::cerr << std::endl; -#endif - - std::vector groups; - rsGxsForums->getGroupData(token, groups); - - mStateHelper->setLoading(mTokenTypeGroupData, false); - - if (groups.size() == 1) - { - mForumGroup = groups[0]; - insertGroupData(); - - mStateHelper->setActive(mTokenTypeGroupData, true); - - // Don't show the distribution column if the forum has no anti-spam - ui->threadTreeWidget->setColumnHidden(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); - ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mSubscribeFlags)) ; - } - else - { - std::cerr << "GxsForumThreadWidget::loadGroupSummary_CurrentForum() ERROR Invalid Number of Groups..."; - std::cerr << std::endl; - - mStateHelper->setActive(mTokenTypeGroupData, false); - mStateHelper->clear(mTokenTypeGroupData); - } - - emit groupChanged(this); -} - -/*********************** **** **** **** ***********************/ -/*********************** **** **** **** ***********************/ - -void GxsForumThreadWidget::requestMessageData(const RsGxsGrpMsgIdPair &msgId) -{ - mStateHelper->setLoading(mTokenTypeMessageData, true); - - mTokenQueue->cancelActiveRequestTokens(mTokenTypeMessageData); - - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::requestMessage(" << msgId.first << "," << msgId.second << ")"; - std::cerr << std::endl; -#endif - - GxsMsgReq msgIds; - std::set &vect = msgIds[msgId.first]; - vect.insert(msgId.second); - - uint32_t token; - mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, mTokenTypeMessageData); -} - -void GxsForumThreadWidget::loadMessageData(const uint32_t &token) -{ - mStateHelper->setLoading(mTokenTypeMessageData, false); - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::loadMessage()"; - std::cerr << std::endl; -#endif - - std::vector msgs; - if (rsGxsForums->getMsgData(token, msgs)) { - if (msgs.size() != 1) { - std::cerr << "GxsForumThreadWidget::loadMessage() ERROR Wrong number of answers"; - std::cerr << std::endl; - - mStateHelper->setActive(mTokenTypeMessageData, false); - mStateHelper->clear(mTokenTypeMessageData); - return; - } - insertMessageData(msgs[0]); - } else { - std::cerr << "GxsForumThreadWidget::loadMessage() ERROR Missing Message Data..."; - std::cerr << std::endl; - - mStateHelper->setActive(mTokenTypeMessageData, false); - mStateHelper->clear(mTokenTypeMessageData); - } -} - -/*********************** **** **** **** ***********************/ -/*********************** **** **** **** ***********************/ - - -void GxsForumThreadWidget::requestMsgData_ReplyWithPrivateMessage(const RsGxsGrpMsgIdPair &msgId) -{ - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::requestMsgData_ReplyMessage(" << msgId.first << "," << msgId.second << ")"; - std::cerr << std::endl; -#endif - - GxsMsgReq msgIds; - std::set &vect = msgIds[msgId.first]; - vect.insert(msgId.second); - - uint32_t token; - mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, mTokenTypeReplyMessage); -} - -void GxsForumThreadWidget::requestMsgData_ShowAuthorInPeople(const RsGxsGrpMsgIdPair& msgId) -{ - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::requestMsgData_ReplyMessage(" << msgId.first << "," << msgId.second << ")"; - std::cerr << std::endl; -#endif - - GxsMsgReq msgIds; - std::set &vect = msgIds[msgId.first]; - vect.insert(msgId.second); - - uint32_t token; - mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, mTokenTypeShowAuthorInPeople); -} -void GxsForumThreadWidget::requestMsgData_EditForumMessage(const RsGxsGrpMsgIdPair &msgId) -{ - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::requestMsgData_ReplyMessage(" << msgId.first << "," << msgId.second << ")"; - std::cerr << std::endl; -#endif - - GxsMsgReq msgIds; - std::set &vect = msgIds[msgId.first]; - vect.insert(msgId.second); - - uint32_t token; - mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, mTokenTypeEditForumMessage); -} -void GxsForumThreadWidget::requestMsgData_ReplyForumMessage(const RsGxsGrpMsgIdPair &msgId) -{ - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::requestMsgData_ReplyMessage(" << msgId.first << "," << msgId.second << ")"; - std::cerr << std::endl; -#endif - - GxsMsgReq msgIds; - std::set &vect = msgIds[msgId.first]; - vect.insert(msgId.second); - - uint32_t token; - mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, mTokenTypeReplyForumMessage); -} - -void GxsForumThreadWidget::loadMsgData_ReplyMessage(const uint32_t &token) -{ -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage()"; - std::cerr << std::endl; -#endif - - std::vector msgs; - if (rsGxsForums->getMsgData(token, msgs)) - { - if (msgs.size() != 1) - { - std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage() ERROR Wrong number of answers"; - std::cerr << std::endl; - return; - } - replyMessageData(msgs[0]); - } - else - { - std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage() ERROR Missing Message Data..."; - std::cerr << std::endl; - } -} - -void GxsForumThreadWidget::loadMsgData_EditForumMessage(const uint32_t &token) -{ -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::loadMsgData_EditMessage()"; - std::cerr << std::endl; -#endif - - std::vector msgs; - if (rsGxsForums->getMsgData(token, msgs)) - { - if (msgs.size() != 1) - { - std::cerr << "GxsForumThreadWidget::loadMsgData_EditMessage() ERROR Wrong number of answers"; - std::cerr << std::endl; - return; - } - - editForumMessageData(msgs[0]); - } - else - { - std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage() ERROR Missing Message Data..."; - std::cerr << std::endl; - } -} -void GxsForumThreadWidget::loadMsgData_ReplyForumMessage(const uint32_t &token) -{ -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage()"; - std::cerr << std::endl; -#endif - - std::vector msgs; - if (rsGxsForums->getMsgData(token, msgs)) - { - if (msgs.size() != 1) - { - std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage() ERROR Wrong number of answers"; - std::cerr << std::endl; - return; - } - - replyForumMessageData(msgs[0]); - } - else - { - std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage() ERROR Missing Message Data..."; - std::cerr << std::endl; - } -} -#endif - void GxsForumThreadWidget::showAuthorInPeople(const RsGxsForumMsg& msg) { if(msg.mMeta.mAuthorId.isNull()) @@ -3149,102 +1771,3 @@ void GxsForumThreadWidget::showAuthorInPeople(const RsGxsForumMsg& msg) MainWindow::showWindow(MainWindow::People); idDialog->navigate(RsGxsId(msg.mMeta.mAuthorId)); } - -#ifdef TO_REMOVE -void GxsForumThreadWidget::loadMsgData_SetAuthorOpinion(const uint32_t &token,RsReputations::Opinion opinion) -{ -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::loadMsgData_BanAuthor()"; - std::cerr << std::endl; -#endif - - std::vector msgs; - if (rsGxsForums->getMsgData(token, msgs)) - { - if (msgs.size() != 1) - { - std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage() ERROR Wrong number of answers"; - std::cerr << std::endl; - return; - } - - std::cerr << " banning author id " << msgs[0].mMeta.mAuthorId << std::endl; - - rsReputations->setOwnOpinion(msgs[0].mMeta.mAuthorId,opinion) ; - } - else - { - std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage() ERROR Missing Message Data..."; - std::cerr << std::endl; - } - updateDisplay(true) ; - - // we should also update the icons so that they changed to the icon for banned peers. - - std::cerr << __PRETTY_FUNCTION__ << ": need to implement the update of GxsTreeWidgetItems icons too." << std::endl; -} -/*********************** **** **** **** ***********************/ -/*********************** **** **** **** ***********************/ - -void GxsForumThreadWidget::loadRequest(const TokenQueue *queue, const TokenRequest &req) -{ -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumThreadWidget::loadRequest() UserType: " << req.mUserType; - std::cerr << std::endl; -#endif - - if (queue == mTokenQueue) - { - /* now switch on req */ - if (req.mUserType == mTokenTypeGroupData) { - loadGroupData(req.mToken); - return; - } - - if (req.mUserType == mTokenTypeMessageData) { - loadMessageData(req.mToken); - return; - } - - if (req.mUserType == mTokenTypeReplyMessage) { - loadMsgData_ReplyMessage(req.mToken); - return; - } - - if (req.mUserType == mTokenTypeReplyForumMessage) { - loadMsgData_ReplyForumMessage(req.mToken); - return; - } - - if (req.mUserType == mTokenTypeEditForumMessage) { - loadMsgData_EditForumMessage(req.mToken); - return; - } - if (req.mUserType == mTokenTypeShowAuthorInPeople) { - loadMsgData_ShowAuthorInPeople(req.mToken); - return; - } - if (req.mUserType == mTokenTypePositiveAuthor) { - loadMsgData_SetAuthorOpinion(req.mToken,RsReputations::OPINION_POSITIVE); - return; - } - - if (req.mUserType == mTokenTypeNegativeAuthor) { - loadMsgData_SetAuthorOpinion(req.mToken,RsReputations::OPINION_NEGATIVE); - return; - } - - if (req.mUserType == mTokenTypeNeutralAuthor) { - loadMsgData_SetAuthorOpinion(req.mToken,RsReputations::OPINION_NEUTRAL); - return; - } - } - - GxsMessageFrameWidget::loadRequest(queue, req); -} - -QTreeWidgetItem *GxsForumThreadWidget::generateMissingItem(const RsGxsMessageId& mid) -{ -return NULL; -} -#endif diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 29c59099d..07c62e76d 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -142,12 +142,6 @@ private slots: void filterColumnChanged(int column); void filterItems(const QString &text); -#ifdef TO_REMOVE - void fillThreadFinished(); - void fillThreadProgress(int current, int count); - void fillThreadStatus(QString text); -#endif - private: void insertMessageData(const RsGxsForumMsg &msg); bool getCurrentPost(ForumModelPostEntry& fmpe) const ; @@ -172,20 +166,6 @@ private: void updateMessageData(const RsGxsMessageId& msgId); -#ifdef TO_REMOVE - void requestMsgData_ReplyWithPrivateMessage(const RsGxsGrpMsgIdPair &msgId); - void requestMsgData_ShowAuthorInPeople(const RsGxsGrpMsgIdPair &msgId); - void requestMsgData_ReplyForumMessage(const RsGxsGrpMsgIdPair &msgId); - void requestMsgData_EditForumMessage(const RsGxsGrpMsgIdPair &msgId); - - void loadMessageData(const uint32_t &token); - void loadMsgData_ReplyMessage(const uint32_t &token); - void loadMsgData_ReplyForumMessage(const uint32_t &token); - void loadMsgData_EditForumMessage(const uint32_t &token); - void loadMsgData_ShowAuthorInPeople(const uint32_t &token); - void loadMsgData_SetAuthorOpinion(const uint32_t &token, RsReputations::Opinion opinion); -#endif - private: RsGxsGroupId mLastForumID; RsGxsMessageId mThreadId; @@ -202,19 +182,6 @@ private: unsigned int mUnreadCount; unsigned int mNewCount; -#ifdef TO_REMOVE - uint32_t mTokenTypeGroupData; - uint32_t mTokenTypeInsertThreads; - uint32_t mTokenTypeMessageData; - uint32_t mTokenTypeReplyMessage; - uint32_t mTokenTypeReplyForumMessage; - uint32_t mTokenTypeEditForumMessage; - uint32_t mTokenTypeShowAuthorInPeople; - uint32_t mTokenTypeNegativeAuthor; - uint32_t mTokenTypePositiveAuthor; - uint32_t mTokenTypeNeutralAuthor; -#endif - /* Color definitions (for standard see qss.default) */ QColor mTextColorRead; QColor mTextColorUnread; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp deleted file mode 100644 index abaad4848..000000000 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp +++ /dev/null @@ -1,558 +0,0 @@ -/******************************************************************************* - * retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp * - * * - * Copyright 2012 Retroshare Team * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Affero General Public License as * - * published by the Free Software Foundation, either version 3 of the * - * License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Affero General Public License for more details. * - * * - * You should have received a copy of the GNU Affero General Public License * - * along with this program. If not, see . * - * * - *******************************************************************************/ - -#include -#include - -#include "GxsForumsFillThread.h" -#include "GxsForumThreadWidget.h" -#include "GxsForumModel.h" - -#include "retroshare/rsgxsflags.h" -#include "retroshare/rsgxsforums.h" - -#include -#include - -//#define DEBUG_FORUMS - -#ifdef TO_REMOVE -#define PROGRESSBAR_MAX 100 - -GxsForumsFillThread::GxsForumsFillThread(GxsForumThreadWidget *parent) - : QThread(parent), mParent(parent) -{ - mStopped = false; - mCompareRole = NULL; - - mExpandNewMessages = true; - mFillComplete = false; - - mFilterColumn = 0; - - mViewType = 0; - mFlatView = false; - mUseChildTS = false; -} - -GxsForumsFillThread::~GxsForumsFillThread() -{ -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::~GxsForumsFillThread" << std::endl; -#endif - - // remove all items (when items are available, the thread was terminated) - QList::iterator item; - for (item = mItems.begin (); item != mItems.end (); ++item) { - if (*item) { - delete (*item); - } - } - mItems.clear(); - - mItemToExpand.clear(); -} - -void GxsForumsFillThread::stop() -{ - disconnect(); - mStopped = true; - QApplication::processEvents(); -} - -void GxsForumsFillThread::calculateExpand(const RsGxsForumMsg &msg, QTreeWidgetItem *item) -{ - if (mFillComplete && mExpandNewMessages && IS_MSG_UNREAD(msg.mMeta.mMsgStatus)) { - QTreeWidgetItem *parentItem = item; - while ((parentItem = parentItem->parent()) != NULL) { - if (std::find(mItemToExpand.begin(), mItemToExpand.end(), parentItem) == mItemToExpand.end()) { - mItemToExpand.push_back(parentItem); - } - } - } -} - -static bool decreasing_time_comp(const QPair& e1,const QPair& e2) { return e2.first < e1.first ; } - -void GxsForumsFillThread::run() -{ - RsTokenService *service = rsGxsForums->getTokenService(); - uint32_t msg_token; - uint32_t grp_token; - - emit status(tr("Waiting")); - - { - /* get all messages of the forum */ - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; - - std::list grpIds; - grpIds.push_back(mForumId); - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::run() forum id " << mForumId << std::endl; -#endif - - service->requestMsgInfo(msg_token, RS_TOKREQ_ANSTYPE_DATA, opts, grpIds); - - /* wait for the answer */ - uint32_t requestStatus = RsTokenService::PENDING; - while (!wasStopped()) { - requestStatus = service->requestStatus(msg_token); - if (requestStatus == RsTokenService::FAILED || - requestStatus == RsTokenService::COMPLETE) { - break; - } - msleep(200); - } - - if (requestStatus == RsTokenService::FAILED) - { - deleteLater(); - return; - } - } - - // also get the forum meta data. - { - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; - - std::list grpIds; - grpIds.push_back(mForumId); - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::run() forum id " << mForumId << std::endl; -#endif - - service->requestGroupInfo(grp_token, RS_TOKREQ_ANSTYPE_DATA, opts, grpIds); - - /* wait for the answer */ - uint32_t requestStatus = RsTokenService::PENDING; - while (!wasStopped()) { - requestStatus = service->requestStatus(grp_token); - if (requestStatus == RsTokenService::FAILED || - requestStatus == RsTokenService::COMPLETE) { - break; - } - msleep(200); - } - - if (requestStatus == RsTokenService::FAILED) - { - deleteLater(); - return; - } - } - - if (wasStopped()) - { -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::run() thread stopped, cancel request" << std::endl; -#endif - - /* cancel request */ - service->cancelRequest(msg_token); - service->cancelRequest(grp_token); - deleteLater(); - return; - } - - emit status(tr("Retrieving")); - - std::vector forum_groups; - - if (!rsGxsForums->getGroupData(grp_token, forum_groups) || forum_groups.size() != 1) - { - deleteLater(); - return; - } - - RsGxsForumGroup forum_group = *forum_groups.begin(); - -//#ifdef DEBUG_FORUMS - std::cerr << "Retrieved group data: " << std::endl; - std::cerr << " Group ID: " << forum_group.mMeta.mGroupId << std::endl; - std::cerr << " Admin lst: " << forum_group.mAdminList.ids.size() << " elements." << std::endl; - for(auto it(forum_group.mAdminList.ids.begin());it!=forum_group.mAdminList.ids.end();++it) - std::cerr << " " << *it << std::endl; - std::cerr << " Pinned Post: " << forum_group.mPinnedPosts.ids.size() << " messages." << std::endl; - for(auto it(forum_group.mPinnedPosts.ids.begin());it!=forum_group.mPinnedPosts.ids.end();++it) - std::cerr << " " << *it << std::endl; -//#endif - - /* get messages */ - std::map msgs; - - { // This forces to delete msgs_array after the conversion to std::map. - - std::vector msgs_array; - - if (!rsGxsForums->getMsgData(msg_token, msgs_array)) - { - deleteLater(); - return; - } - - // now put everything into a map in order to make search log(n) - - for(uint32_t i=0;i > threadStack; - std::map > kids_array ; - std::set missing_parents; - - // First of all, remove all older versions of posts. This is done by first adding all posts into a hierarchy structure - // and then removing all posts which have a new versions available. The older versions are kept appart. - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::run() Collecting post versions" << std::endl; -#endif - mPostVersions.clear(); - std::list msg_stack ; - - for ( std::map::iterator msgIt = msgs.begin(); msgIt != msgs.end();++msgIt) - { - if(wasStopped()) - { - deleteLater(); - return; - } - if(!msgIt->second.mMeta.mOrigMsgId.isNull() && msgIt->second.mMeta.mOrigMsgId != msgIt->second.mMeta.mMsgId) - { -#ifdef DEBUG_FORUMS - std::cerr << " Post " << msgIt->second.mMeta.mMsgId << " is a new version of " << msgIt->second.mMeta.mOrigMsgId << std::endl; -#endif - std::map::iterator msgIt2 = msgs.find(msgIt->second.mMeta.mOrigMsgId); - - // Ensuring that the post exists allows to only collect the existing data. - - if(msgIt2 == msgs.end()) - continue ; - - // Make sure that the author is the same than the original message, or is a moderator. This should always happen when messages are constructed using - // the UI but nothing can prevent a nasty user to craft a new version of a message with his own signature. - - if(msgIt2->second.mMeta.mAuthorId != msgIt->second.mMeta.mAuthorId) - { - if( !IS_FORUM_MSG_MODERATION(msgIt->second.mMeta.mMsgFlags) ) // if authors are different the moderation flag needs to be set on the editing msg - continue ; - - if( forum_group.mAdminList.ids.find(msgIt->second.mMeta.mAuthorId)==forum_group.mAdminList.ids.end()) // if author is not a moderator, continue - continue ; - } - - // always add the post a self version - - if(mPostVersions[msgIt->second.mMeta.mOrigMsgId].empty()) - mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(QPair(msgIt2->second.mMeta.mPublishTs,msgIt2->second.mMeta.mMsgId)) ; - - mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(QPair(msgIt->second.mMeta.mPublishTs,msgIt->second.mMeta.mMsgId)) ; - } - } - - // The following code assembles all new versions of a given post into the same array, indexed by the oldest version of the post. - - for(QMap > >::iterator it(mPostVersions.begin());it!=mPostVersions.end();++it) - { - if(wasStopped()) - { - deleteLater(); - return; - } - QVector >& v(*it) ; - - for(int32_t i=0;i > >::iterator it2 = mPostVersions.find(sub_msg_id); - - if(it2 != mPostVersions.end()) - { - for(int32_t j=0;j<(*it2).size();++j) - if((*it2)[j].second != sub_msg_id) // dont copy it, since it is already present at slot i - v.append((*it2)[j]) ; - - mPostVersions.erase(it2) ; // it2 is never equal to it - } - } - } - } - - - // Now remove from msg ids, all posts except the most recent one. And make the mPostVersion be indexed by the most recent version of the post, - // which corresponds to the item in the tree widget. - -#ifdef DEBUG_FORUMS - std::cerr << "Final post versions: " << std::endl; -#endif - QMap > > mTmp; - std::map most_recent_versions ; - - for(QMap > >::iterator it(mPostVersions.begin());it!=mPostVersions.end();++it) - { -#ifdef DEBUG_FORUMS - std::cerr << "Original post: " << it.key() << std::endl; -#endif - if(wasStopped()) - { - deleteLater(); - return; - } - // Finally, sort the posts from newer to older - - qSort((*it).begin(),(*it).end(),decreasing_time_comp) ; - -#ifdef DEBUG_FORUMS - std::cerr << " most recent version " << (*it)[0].first << " " << (*it)[0].second << std::endl; -#endif - for(int32_t i=1;i<(*it).size();++i) - { - if(wasStopped()) - { - deleteLater(); - return; - } - msgs.erase((*it)[i].second) ; - -#ifdef DEBUG_FORUMS - std::cerr << " older version " << (*it)[i].first << " " << (*it)[i].second << std::endl; -#endif - } - - mTmp[(*it)[0].second] = *it ; // index the versions map by the ID of the most recent post. - - // Now make sure that message parents are consistent. Indeed, an old post may have the old version of a post as parent. So we need to change that parent - // to the newest version. So we create a map of which is the most recent version of each message, so that parent messages can be searched in it. - - for(int i=1;i<(*it).size();++i) - { - if(wasStopped()) - { - deleteLater(); - return; - } - most_recent_versions[(*it)[i].second] = (*it)[0].second ; - } - } - mPostVersions = mTmp ; - - // The next step is to find the top level thread messages. These are defined as the messages without - // any parent message ID. - - // this trick is needed because while we remove messages, the parents a given msg may already have been removed - // and wrongly understand as a missing parent. - - std::map kept_msgs; - - for ( std::map::iterator msgIt = msgs.begin(); msgIt != msgs.end();++msgIt) - { - - if (wasStopped()) - { - deleteLater(); - return; - } - if(mFlatView || msgIt->second.mMeta.mParentId.isNull()) - { - - /* add all threads */ - if (wasStopped()) - { - deleteLater(); - return; - } - - const RsGxsForumMsg& msg = msgIt->second; - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::run() Adding TopLevel Thread: mId: " << msg.mMeta.mMsgId << std::endl; -#endif - - QTreeWidgetItem *item = mParent->convertMsgToThreadWidget(msg, mUseChildTS, mFilterColumn,NULL); - - if (!mFlatView) - threadStack.push_back(std::make_pair(msg.mMeta.mMsgId,item)) ; - - calculateExpand(msg, item); - - mItems.append(item); - - if (++step >= steps) { - step = 0; - emit progress(++pos, PROGRESSBAR_MAX); - } - } - else - { -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::run() Storing kid " << msgIt->first << " of message " << msgIt->second.mMeta.mParentId << std::endl; -#endif - // The same missing parent may appear multiple times, so we first store them into a unique container. - - RsGxsMessageId parent_msg = msgIt->second.mMeta.mParentId; - - if(msgs.find(parent_msg) == msgs.end()) - { - // also check that the message is not versionned - - std::map::const_iterator mrit = most_recent_versions.find(parent_msg) ; - - if(mrit != most_recent_versions.end()) - parent_msg = mrit->second ; - else - missing_parents.insert(parent_msg); - } - - kids_array[parent_msg].push_back(msgIt->first) ; - kept_msgs.insert(*msgIt) ; - } - } - - msgs = kept_msgs; - - // Also create a list of posts by time, when they are new versions of existing posts. Only the last one will have an item created. - - // Add a fake toplevel item for the parent IDs that we dont actually have. - - for(std::set::const_iterator it(missing_parents.begin());it!=missing_parents.end();++it) - { - // add dummy parent item - QTreeWidgetItem *parent = mParent->generateMissingItem(*it); - mItems.append( parent ); - - threadStack.push_back(std::make_pair(*it,parent)) ; - } -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::run() Processing stack:" << std::endl; -#endif - // Now use a stack to go down the hierarchy - - while (!threadStack.empty()) - { - if (wasStopped()) - { - deleteLater(); - return; - } - - std::pair threadPair = threadStack.front(); - threadStack.pop_front(); - - std::map >::iterator it = kids_array.find(threadPair.first) ; - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::run() Node: " << threadPair.first << std::endl; -#endif - if(it == kids_array.end()) - continue ; - - - for(std::list::const_iterator it2(it->second.begin());it2!=it->second.end();++it2) - { - if(wasStopped()) - { - deleteLater(); - return; - } - // We iterate through the top level thread items, and look for which message has the current item as parent. - // When found, the item is put in the thread list itself, as a potential new parent. - - std::map::iterator mit = msgs.find(*it2) ; - - if(mit == msgs.end()) - { - std::cerr << "GxsForumsFillThread::run() Cannot find submessage " << *it2 << " !!!" << std::endl; - continue ; - } - - const RsGxsForumMsg& msg(mit->second) ; -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::run() adding sub_item " << msg.mMeta.mMsgId << std::endl; -#endif - - QTreeWidgetItem *item = mParent->convertMsgToThreadWidget(msg, mUseChildTS, mFilterColumn, threadPair.second); - calculateExpand(msg, item); - - /* add item to process list */ - threadStack.push_back(std::make_pair(msg.mMeta.mMsgId, item)); - - if (++step >= steps) { - step = 0; - emit progress(++pos, PROGRESSBAR_MAX); - } - - msgs.erase(mit); - } - -#ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::run() Erasing entry " << it->first << " from kids tab." << std::endl; -#endif - kids_array.erase(it) ; // This is not strictly needed, but it improves performance by reducing the search space. - } - -#ifdef DEBUG_FORUMS - std::cerr << "Kids array now has " << kids_array.size() << " elements" << std::endl; - for(std::map >::const_iterator it(kids_array.begin());it!=kids_array.end();++it) - { - std::cerr << "Node " << it->first << std::endl; - for(std::list::const_iterator it2(it->second.begin());it2!=it->second.end();++it2) - std::cerr << " " << *it2 << std::endl; - } - - std::cerr << "GxsForumsFillThread::run() stopped: " << (wasStopped() ? "yes" : "no") << std::endl; -#endif - if(wasStopped()) - deleteLater(); -} -#endif - diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h deleted file mode 100644 index cf4f17ea2..000000000 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h +++ /dev/null @@ -1,74 +0,0 @@ -/******************************************************************************* - * retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h * - * * - * Copyright 2012 Retroshare Team * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Affero General Public License as * - * published by the Free Software Foundation, either version 3 of the * - * License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Affero General Public License for more details. * - * * - * You should have received a copy of the GNU Affero General Public License * - * along with this program. If not, see . * - * * - *******************************************************************************/ - -#ifndef GXSFORUMSFILLTHREAD_H -#define GXSFORUMSFILLTHREAD_H - -#include -#include -#include -#include "retroshare/rsgxsifacetypes.h" - -class GxsForumThreadWidget; -class RsGxsForumMsg; -class RSTreeWidgetItemCompareRole; -class QTreeWidgetItem; - -#ifdef TO_REMOVE -class GxsForumsFillThread : public QThread -{ - Q_OBJECT - -public: - GxsForumsFillThread(GxsForumThreadWidget *parent); - ~GxsForumsFillThread(); - - void run(); - void stop(); - bool wasStopped() { return mStopped; } - -signals: - void progress(int current, int count); - void status(QString text); - -public: - RsGxsGroupId mForumId; - int mFilterColumn; - bool mFillComplete; - int mViewType; - bool mFlatView; - bool mUseChildTS; - bool mExpandNewMessages; - std::string mFocusMsgId; - RSTreeWidgetItemCompareRole *mCompareRole; - - QList mItems; - QList mItemToExpand; - - QMap > > mPostVersions ; -private: - void calculateExpand(const RsGxsForumMsg &msg, QTreeWidgetItem *item); - - GxsForumThreadWidget *mParent; - volatile bool mStopped; -}; - -#endif // GXSFORUMSFILLTHREAD_H -#endif // GXSFORUMSFILLTHREAD_H diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 8a9ae04ce..86171a916 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -1230,7 +1230,6 @@ gxsforums { gui/gxsforums/GxsForumGroupDialog.h \ gui/gxsforums/CreateGxsForumMsg.h \ gui/gxsforums/GxsForumThreadWidget.h \ - gui/gxsforums/GxsForumsFillThread.h \ gui/gxsforums/GxsForumModel.h \ gui/gxsforums/GxsForumUserNotify.h \ gui/feeds/GxsForumGroupItem.h \ @@ -1246,7 +1245,6 @@ gxsforums { gui/gxsforums/CreateGxsForumMsg.cpp \ gui/gxsforums/GxsForumThreadWidget.cpp \ gui/gxsforums/GxsForumModel.cpp \ - gui/gxsforums/GxsForumsFillThread.cpp \ gui/gxsforums/GxsForumUserNotify.cpp \ gui/feeds/GxsForumGroupItem.cpp \ gui/feeds/GxsForumMsgItem.cpp From 8736380bfe15d39679e0ec3a9440eee8f5a476ab Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Dec 2018 16:45:16 +0100 Subject: [PATCH 47/79] added license, removed debug info --- .../src/gui/gxsforums/GxsForumModel.cpp | 133 +++--------------- .../src/gui/gxsforums/GxsForumModel.h | 37 ----- .../gui/gxsforums/GxsForumThreadWidget.cpp | 1 - 3 files changed, 23 insertions(+), 148 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index adadbf5bf..8ba1b9639 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -1,3 +1,23 @@ +/******************************************************************************* + * retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp * + * * + * Copyright 2018 by Cyril Soler * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + #include #include #include @@ -675,7 +695,7 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector= model.mPosts.size()) - { - std::cerr << "(EE) constructed a RsGxsForumModel::const_iterator from invalid index " << i << std::endl; - kid = -1; - return; - } - // create a stack or parents - parent_stack.clear(); - - if(i==0) - { - current_parent = 0; - kid =0; - return; - } - current_parent = model.mPosts[i].mParent; - ForumModelIndex j(i); - kid = model.mPosts[i].prow; - - while(j != 0) - { - parent_stack.push_front(model.mPosts[j].prow); - j = model.mPosts[i].mParent; - } -} - -ForumModelIndex RsGxsForumModel::const_iterator::operator*() const -{ - if(current_parent >= model.mPosts.size() || kid < 0 || kid >= (int)model.mPosts[current_parent].mChildren.size()) - { - std::cerr << "(EE) operator* on an invalid RsGxsForumModel::const_iterator"<< std::endl; - return 0; - } - - return model.mPosts[current_parent].mChildren[kid]; -} - -void RsGxsForumModel::const_iterator::operator++() -{ - kid++; - while(kid >= (int)model.mPosts[current_parent].mChildren.size()) - { - current_parent = model.mPosts[current_parent].mParent; - kid = parent_stack.back()+1; - - parent_stack.pop_back(); - - } - - if(current_parent == 0 && kid >= (int)model.mPosts[current_parent].mChildren.size()) - { - kid = -1; - return; - } - - while(!model.mPosts[model.mPosts[current_parent].mChildren[kid]].mChildren.empty()) - { - parent_stack.push_back(kid); - current_parent = model.mPosts[current_parent].mChildren[kid]; - kid = 0; - } -} - -RsGxsForumModel::const_iterator::operator bool() const -{ - return kid >= 0; -} -#endif - static void recursPrintModel(const std::vector& entries,ForumModelIndex index,int depth) { const ForumModelPostEntry& e(entries[index]); @@ -1340,7 +1253,7 @@ static void recursPrintModel(const std::vector& entries,For recursPrintModel(entries,e.mChildren[i],depth+1); } - +#ifdef DEBUG_FORUMMODEL void RsGxsForumModel::debug_dump() { std::cerr << "Model data dump:" << std::endl; @@ -1369,6 +1282,6 @@ void RsGxsForumModel::debug_dump() // recursive print recursPrintModel(mPosts,ForumModelIndex(0),0); } - +#endif diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index 8c258a826..dec3bad51 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -1,18 +1,3 @@ -#ifndef SUSPENDED_CODE -#else -#include -#include - -struct RsMsgMetaData -{ - std::string mMsgName ; - time_t mPublishTs; - uint32_t mMsgStatus; - QString mAuthorId; -}; - -#endif - #include "retroshare/rsgxsforums.h" #include "retroshare/rsgxsifacetypes.h" #include @@ -99,28 +84,6 @@ public: std::vector > getPostVersions(const RsGxsMessageId& mid) const; -#ifdef TO_REMOVE - QModelIndex getNextIndex(const QModelIndex& i,bool unread_only) const; - - class const_iterator - { - public: - const_iterator(const RsGxsForumModel& Model,ForumModelIndex = 0) ; - - ForumModelIndex operator*() const ; - void operator++(); - - inline operator bool() const ; - - private: - std::list parent_stack; - int kid; - ForumModelIndex current_parent; - const RsGxsForumModel& model; - }; - void test_iterator() const; -#endif - // This method will asynchroneously update the data void setForum(const RsGxsGroupId& forumGroup); void setTreeMode(TreeMode mode) ; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index a83d3d590..8de231439 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -28,7 +28,6 @@ #include "util/misc.h" #include "GxsForumThreadWidget.h" #include "ui_GxsForumThreadWidget.h" -#include "GxsForumsFillThread.h" #include "GxsForumModel.h" #include "GxsForumsDialog.h" #include "gui/RetroShareLink.h" From 24896bc596f1e588f45dfe08ea45e01dba449809 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Dec 2018 16:49:14 +0100 Subject: [PATCH 48/79] further cleaning of ForumModel code --- .../src/gui/gxsforums/GxsForumModel.cpp | 41 ++----------------- 1 file changed, 4 insertions(+), 37 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 8ba1b9639..9f40caa47 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -185,7 +185,6 @@ bool RsGxsForumModel::convertRefPointerToTabEntry(void *ref,uint32_t& entry) QModelIndex RsGxsForumModel::index(int row, int column, const QModelIndex & parent) const { -// if(!hasIndex(row,column,parent)) if(row < 0 || column < 0 || column >= COLUMN_THREAD_NB_COLUMNS) return QModelIndex(); @@ -491,9 +490,6 @@ void RsGxsForumModel::setFilter(int column,const QStringList& strings,uint32_t& QVariant RsGxsForumModel::missingRole(const ForumModelPostEntry& fmpe,int column) const { - // if(column != COLUMN_THREAD_DATA) -// return QVariant(); - if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) return QVariant(true); else @@ -764,9 +760,9 @@ ForumModelIndex RsGxsForumModel::addEntry(std::vector& post posts[N].mParent = parent; posts[parent].mChildren.push_back(N); - +#ifdef DEBUG_FORUMMODEL std::cerr << "Added new entry " << N << " children of " << parent << std::endl; - +#endif if(N == parent) std::cerr << "(EE) trying to add a post as its own parent!" << std::endl; return ForumModelIndex(N); @@ -814,35 +810,6 @@ void RsGxsForumModel::convertMsgToPostEntry(const RsGxsForumGroup& mForumGroup,c fentry.mReputationWarningLevel = 1 ; else fentry.mReputationWarningLevel = 0 ; - -#ifdef TODO - // This is an attempt to put pinned posts on the top. We should rather use a QSortFilterProxyModel here. - QString itemSort = QString::number(msg.mMeta.mPublishTs);//Don't need to format it as for sort. - - if (useChildTS) - { - for(QTreeWidgetItem *grandParent = parent; grandParent!=NULL; grandParent = grandParent->parent()) - { - //Update Parent Child TimeStamp - QString oldTSSort = grandParent->data(COLUMN_THREAD_DATE, ROLE_THREAD_SORT).toString(); - - QString oldCTSSort = oldTSSort.split("|").at(0); - QString oldPTSSort = oldTSSort.contains("|") ? oldTSSort.split(" | ").at(1) : oldCTSSort; -#ifdef SHOW_COMBINED_DATES - QString oldTSText = grandParent->text(COLUMN_THREAD_DATE); - QString oldCTSText = oldTSText.split("|").at(0); - QString oldPTSText = oldTSText.contains("|") ? oldTSText.split(" | ").at(1) : oldCTSText;//If first time parent get only its mPublishTs - #endif - if (oldCTSSort.toDouble() < itemSort.toDouble()) - { -#ifdef SHOW_COMBINED_DATES - grandParent->setText(COLUMN_THREAD_DATE, DateTime::formatDateTime(qtime) + " | " + oldPTSText); -#endif - grandParent->setData(COLUMN_THREAD_DATE, ROLE_THREAD_SORT, itemSort + " | " + oldPTSSort); - } - } - } -#endif } static bool decreasing_time_comp(const std::pair& e1,const std::pair& e2) { return e2.first < e1.first ; } @@ -855,7 +822,7 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou { std::cerr << "updating messages data with " << msgs_array.size() << " messages" << std::endl; -//#ifdef DEBUG_FORUMS +#ifdef DEBUG_FORUMS std::cerr << "Retrieved group data: " << std::endl; std::cerr << " Group ID: " << forum_group.mMeta.mGroupId << std::endl; std::cerr << " Admin lst: " << forum_group.mAdminList.ids.size() << " elements." << std::endl; @@ -864,7 +831,7 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou std::cerr << " Pinned Post: " << forum_group.mPinnedPosts.ids.size() << " messages." << std::endl; for(auto it(forum_group.mPinnedPosts.ids.begin());it!=forum_group.mPinnedPosts.ids.end();++it) std::cerr << " " << *it << std::endl; -//#endif +#endif /* get messages */ std::map msgs; From 60e559561897eff83f64265cdcac6e3cdc96b884 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Dec 2018 22:41:48 +0100 Subject: [PATCH 49/79] fixed bug in post pinning --- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 3 --- retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 9f40caa47..9db4226c4 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -532,9 +532,6 @@ QVariant RsGxsForumModel::toolTipRole(const ForumModelPostEntry& fmpe,int column QVariant RsGxsForumModel::pinnedRole(const ForumModelPostEntry& fmpe,int column) const { - if(column != COLUMN_THREAD_DATE) - return QVariant(); - if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) return QVariant(true); else diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 8de231439..c1a55f90b 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -276,8 +276,8 @@ public: bool lessThan(const QModelIndex& left, const QModelIndex& right) const override { - bool left_is_not_pinned = ! left.data(ROLE_THREAD_PINNED).toBool(); - bool right_is_not_pinned = !right.data(ROLE_THREAD_PINNED).toBool(); + bool left_is_not_pinned = ! left.data(RsGxsForumModel::ThreadPinnedRole).toBool(); + bool right_is_not_pinned = !right.data(RsGxsForumModel::ThreadPinnedRole).toBool(); #ifdef DEBUG_PINNED_POST_SORTING std::cerr << "Comparing item date \"" << data(RsGxsForumModel::COLUMN_THREAD_DATE,Qt::DisplayRole).toString().toStdString() << "\" (" << data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toUInt() << ", \"" << data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toString().toStdString() << "\" --> " << left_is_not_pinned << ") to \"" From 49dc9bcae279d69d11f1b6c35b55f2a908a7d762 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Dec 2018 22:49:16 +0100 Subject: [PATCH 50/79] increated timeout limit for retrieving forums --- libretroshare/src/services/p3gxsforums.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretroshare/src/services/p3gxsforums.cc b/libretroshare/src/services/p3gxsforums.cc index 4541f00b7..0534128e5 100644 --- a/libretroshare/src/services/p3gxsforums.cc +++ b/libretroshare/src/services/p3gxsforums.cc @@ -478,7 +478,7 @@ bool p3GxsForums::getForumsContent( RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; if( !requestMsgInfo(token, opts, forumIds) - || waitToken(token) != RsTokenService::COMPLETE ) return false; + || waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE ) return false; return getMsgData(token, messages); } From 55022432ef1d360230c0372566916cd5bdf72393 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 3 Dec 2018 17:30:46 +0100 Subject: [PATCH 51/79] added proper update of threads when new msg is poste or received --- .../src/gui/gxsforums/GxsForumModel.cpp | 15 ++++++ .../src/gui/gxsforums/GxsForumModel.h | 22 +++++++++ .../gui/gxsforums/GxsForumThreadWidget.cpp | 47 +++++-------------- 3 files changed, 48 insertions(+), 36 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 9db4226c4..cdb8d5dcf 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -667,6 +667,18 @@ void RsGxsForumModel::setForum(const RsGxsGroupId& forum_group_id) update_posts(forum_group_id); } +void RsGxsForumModel::clear() +{ + emit layoutAboutToBeChanged(); + + mPosts.clear(); + mPostVersions.clear(); + + emit layoutChanged(); + emit forumLoaded(); + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); +} + void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector& posts,const std::map > >& post_versions) { emit layoutAboutToBeChanged(); @@ -699,6 +711,9 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + #include "retroshare/rsgxsforums.h" #include "retroshare/rsgxsifacetypes.h" #include @@ -108,6 +128,8 @@ public: QModelIndex parent(const QModelIndex& child) const override; Qt::ItemFlags flags(const QModelIndex& index) const override; + void clear() ; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index c1a55f90b..73be7595c 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -278,24 +278,10 @@ public: { bool left_is_not_pinned = ! left.data(RsGxsForumModel::ThreadPinnedRole).toBool(); bool right_is_not_pinned = !right.data(RsGxsForumModel::ThreadPinnedRole).toBool(); -#ifdef DEBUG_PINNED_POST_SORTING - std::cerr << "Comparing item date \"" << data(RsGxsForumModel::COLUMN_THREAD_DATE,Qt::DisplayRole).toString().toStdString() << "\" (" - << data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toUInt() << ", \"" << data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toString().toStdString() << "\" --> " << left_is_not_pinned << ") to \"" - << other.data(RsGxsForumModel::COLUMN_THREAD_DATE,Qt::DisplayRole).toString().toStdString() << "\" (" - << other.data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toUInt() << ", \"" << other.data(RsGxsForumModel::COLUMN_THREAD_DATE,ROLE_THREAD_SORT).toString().toStdString() << "\" --> " << right_is_not_pinned << ") "; -#endif if(left_is_not_pinned ^ right_is_not_pinned) - { -#ifdef DEBUG_PINNED_POST_SORTING - std::cerr << "Local: " << ((m_header->sortIndicatorOrder()==Qt::AscendingOrder)?right_is_not_pinned:left_is_not_pinned) << std::endl; -#endif return (m_header->sortIndicatorOrder()==Qt::AscendingOrder)?right_is_not_pinned:left_is_not_pinned ; // always put pinned posts on top - } -#ifdef DEBUG_PINNED_POST_SORTING - std::cerr << "Remote: " << GxsIdRSTreeWidgetItem::operator<(other) << std::endl; -#endif return left.data(RsGxsForumModel::SortRole) < right.data(RsGxsForumModel::SortRole) ; } @@ -335,7 +321,6 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mThreadProxyModel->setFilterRegExp(QRegExp(QString(RsGxsForumModel::FilterString))) ; ui->threadTreeWidget->setSortingEnabled(true); - //ui->threadTreeWidget->setDynamicSortFilter(true);// is that useful?? ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION,new DistributionItemDelegate()) ; ui->threadTreeWidget->setItemDelegateForColumn(RsGxsForumModel::COLUMN_THREAD_AUTHOR,new AuthorItemDelegate()) ; @@ -377,22 +362,10 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget itemDelegate->setOnlyPlainText(true); ui->threadTreeWidget->setItemDelegate(itemDelegate); -#ifdef SUSPENDED_CODE - /* Set text of column "Read" to empty - without this the column has a number as header text */ - QTreeWidgetItem *headerItem = ui->threadTreeWidget->headerItem(); - headerItem->setText(COLUMN_THREAD_READ, "") ; - headerItem->setText(COLUMN_THREAD_DISTRIBUTION, ""); - headerItem->setData(COLUMN_THREAD_READ,Qt::UserRole, tr("Read status")) ; // this is used to display drop menus. - headerItem->setData(COLUMN_THREAD_DISTRIBUTION,Qt::UserRole, tr("Distribution")); -#endif - /* add filter actions */ ui->filterLineEdit->addFilter(QIcon(), tr("Title"), RsGxsForumModel::COLUMN_THREAD_TITLE, tr("Search Title")); ui->filterLineEdit->addFilter(QIcon(), tr("Date"), RsGxsForumModel::COLUMN_THREAD_DATE, tr("Search Date")); ui->filterLineEdit->addFilter(QIcon(), tr("Author"), RsGxsForumModel::COLUMN_THREAD_AUTHOR, tr("Search Author")); - //ui->filterLineEdit->addFilter(QIcon(), tr("Content"), RsGxsForumModel::COLUMN_THREAD_CONTENT, tr("Search Content")); - // see processSettings - //ui->filterLineEdit->setCurrentFilter(COLUMN_THREAD_TITLE); mLastViewType = -1; @@ -415,7 +388,8 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_AUTHOR, QHeaderView::Interactive); QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_READ, QHeaderView::Fixed); QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, QHeaderView::Fixed); - ui->threadTreeWidget->header()->setCascadingSectionResizes(true); + + ttheader->setCascadingSectionResizes(true); /* Set header sizes for the fixed columns and resize modes, must be set after processSettings */ ttheader->hideSection (RsGxsForumModel::COLUMN_THREAD_CONTENT); @@ -446,7 +420,6 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget forum visible to all other friends.

Afterwards you can unsubscribe from the context menu of the forum list at left.

")); #ifdef SUSPENDED_CODE ui->threadTreeWidget->enableColumnCustomize(true); - #endif } @@ -468,6 +441,8 @@ void GxsForumThreadWidget::blank() #endif ui->forumName->setText(""); + mThreadModel->clear(); + #ifdef SUSPENDED_CODE mStateHelper->setWidgetEnabled(ui->newthreadButton, false); mStateHelper->setWidgetEnabled(ui->previousButton, false); @@ -605,7 +580,7 @@ void GxsForumThreadWidget::updateDisplay(bool complete) if (complete) { /* Fill complete */ updateGroupData(); - //insertThreads(); + mThreadModel->setForum(groupId()); insertMessage(); mIgnoredMsgId.clear(); @@ -623,7 +598,7 @@ void GxsForumThreadWidget::updateDisplay(bool complete) if (grpIds.find(groupId())!=grpIds.end()){ updateGroup = true; /* Update threads */ - //insertThreads(); + mThreadModel->setForum(groupId()); } else { std::map > msgIds; getAllMsgIds(msgIds); @@ -633,10 +608,8 @@ void GxsForumThreadWidget::updateDisplay(bool complete) removeMessages(msgIds, mIgnoredMsgId); } - if (msgIds.find(groupId()) != msgIds.end()) { - /* Update threads */ - //insertThreads(); - } + if (msgIds.find(groupId()) != msgIds.end()) + mThreadModel->setForum(groupId()); /* Update threads */ } if (updateGroup) { @@ -1646,6 +1619,9 @@ void GxsForumThreadWidget::updateGroupName() } void GxsForumThreadWidget::updateGroupData() { + if(groupId().isNull()) + return; + mSubscribeFlags = 0; mSignFlags = 0; mThreadId.clear(); @@ -1692,7 +1668,6 @@ void GxsForumThreadWidget::updateGroupData() */ mForumGroup = group; - //insertGroupData(); mSubscribeFlags = group.mMeta.mSubscribeFlags; ui->threadTreeWidget->setColumnHidden(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); From 44236000734f357258657e23bf43ddfc5a40feb5 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 3 Dec 2018 21:28:00 +0100 Subject: [PATCH 52/79] update posts when navigating with arrows --- .../src/gui/gxsforums/GxsForumThreadWidget.cpp | 12 +++++++++--- .../src/gui/gxsforums/GxsForumThreadWidget.h | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 73be7595c..070a56488 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -343,6 +343,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->newthreadButton->setText(tr("New thread")); connect(ui->threadTreeWidget, SIGNAL(clicked(QModelIndex)), this, SLOT(clickedThread(QModelIndex))); + connect(ui->threadTreeWidget->selectionModel(), SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)), this, SLOT(changedSelection(const QModelIndex&,const QModelIndex&))); connect(ui->viewBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changedViewBox())); connect(ui->expandButton, SIGNAL(clicked()), this, SLOT(togglethreadview())); @@ -497,6 +498,11 @@ void GxsForumThreadWidget::processSettings(bool load) Settings->endGroup(); } +void GxsForumThreadWidget::changedSelection(const QModelIndex& current,const QModelIndex&) +{ + changedThread(current); +} + void GxsForumThreadWidget::groupIdChanged() { ui->forumName->setText(groupId().isNull () ? "" : tr("Loading...")); @@ -628,12 +634,12 @@ QModelIndex GxsForumThreadWidget::GxsForumThreadWidget::getCurrentIndex() const } bool GxsForumThreadWidget::getCurrentPost(ForumModelPostEntry& fmpe) const { - QModelIndex index = getCurrentIndex() ; + QModelIndex indx = getCurrentIndex() ; - if(!index.isValid()) + if(!indx.isValid()) return false ; - return mThreadModel->getPostData(mThreadProxyModel->mapToSource(index),fmpe); + return mThreadModel->getPostData(mThreadProxyModel->mapToSource(indx),fmpe); } void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 07c62e76d..e4d4c8d7a 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -32,6 +32,7 @@ class QTreeWidgetItem; class RSTreeWidgetItemCompareRole; class RsGxsForumMsg; class GxsForumsFillThread; +class QItemSelection; class RsGxsForumGroup; class RsGxsForumModel; class RsGxsForumMsg; @@ -97,6 +98,7 @@ private slots: void threadListCustomPopupMenu(QPoint point); void contextMenuTextBrowser(QPoint point); + void changedSelection(const QModelIndex &, const QModelIndex &); void changedThread(QModelIndex index); void changedVersion(); void clickedThread (QModelIndex index); From ec0bb5347e17419349af588fb69098691372530c Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 3 Dec 2018 21:56:11 +0100 Subject: [PATCH 53/79] added missing emit of layoutAboutToBeChanged() in forum model --- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index cdb8d5dcf..d4ca2b085 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -664,6 +664,9 @@ void RsGxsForumModel::setForum(const RsGxsGroupId& forum_group_id) // we do not set mForumGroupId yet. We'll do it when the forum data is updated. + if(forum_group_id.isNull()) + return; + update_posts(forum_group_id); } @@ -1136,6 +1139,8 @@ void RsGxsForumModel::setMsgReadStatus(const QModelIndex& i,bool read_status,boo if(!i.isValid()) return ; + emit layoutAboutToBeChanged(); + void *ref = i.internalPointer(); uint32_t entry = 0; @@ -1146,6 +1151,7 @@ void RsGxsForumModel::setMsgReadStatus(const QModelIndex& i,bool read_status,boo recursSetMsgReadStatus(entry,read_status,with_children) ; recursUpdateReadStatusAndTimes(0,has_unread_below,has_read_below); + emit layoutChanged(); emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); } From fb962c4b5bc05b365c45962c44861f72634afa49 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 4 Dec 2018 09:36:06 +0100 Subject: [PATCH 54/79] attempt to fix crash when threads collide in forum model --- .../src/gui/gxsforums/GxsForumModel.cpp | 49 ++++++++++--------- .../src/gui/gxsforums/GxsForumModel.h | 3 ++ .../gui/gxsforums/GxsForumThreadWidget.cpp | 20 ++++++++ .../src/gui/gxsforums/GxsForumThreadWidget.h | 1 + 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index d4ca2b085..e5c49caa3 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -49,39 +49,46 @@ RsGxsForumModel::RsGxsForumModel(QObject *parent) mFilteringEnabled=false; } +void RsGxsForumModel::preMods() +{ + emit layoutAboutToBeChanged(); + beginResetModel(); +} +void RsGxsForumModel::postMods() +{ + endResetModel(); + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); + emit layoutChanged(); +} + void RsGxsForumModel::setTreeMode(TreeMode mode) { if(mode == mTreeMode) return; - emit layoutAboutToBeChanged(); - + preMods(); mTreeMode = mode; - - emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); - emit layoutChanged(); + postMods(); } void RsGxsForumModel::setSortMode(SortMode mode) { - emit layoutAboutToBeChanged(); + preMods(); mSortMode = mode; - emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); - emit layoutChanged(); + postMods(); } void RsGxsForumModel::initEmptyHierarchy(std::vector& posts) { - emit layoutAboutToBeChanged(); + preMods(); posts.resize(1); // adds a sentinel item posts[0].mTitle = "Root sentinel post" ; posts[0].mParent = 0; - emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); - emit layoutChanged(); + postMods(); } int RsGxsForumModel::rowCount(const QModelIndex& parent) const @@ -474,7 +481,7 @@ uint32_t RsGxsForumModel::recursUpdateFilterStatus(ForumModelIndex i,int column, void RsGxsForumModel::setFilter(int column,const QStringList& strings,uint32_t& count) { - emit layoutAboutToBeChanged(); + preMods(); if(!strings.empty()) { @@ -484,8 +491,7 @@ void RsGxsForumModel::setFilter(int column,const QStringList& strings,uint32_t& else mFilteringEnabled = false; - emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); - emit layoutChanged(); + postMods(); } QVariant RsGxsForumModel::missingRole(const ForumModelPostEntry& fmpe,int column) const @@ -672,19 +678,18 @@ void RsGxsForumModel::setForum(const RsGxsGroupId& forum_group_id) void RsGxsForumModel::clear() { - emit layoutAboutToBeChanged(); + preMods(); mPosts.clear(); mPostVersions.clear(); - emit layoutChanged(); + postMods(); emit forumLoaded(); - emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); } void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector& posts,const std::map > >& post_versions) { - emit layoutAboutToBeChanged(); + preMods(); mForumGroup = group; mPosts = posts; @@ -707,9 +712,8 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector > &ms void GxsForumThreadWidget::updateDisplay(bool complete) { + if(mUpdating) + return; + if (complete) { /* Fill complete */ + mUpdating=true; updateGroupData(); mThreadModel->setForum(groupId()); insertMessage(); @@ -604,6 +609,7 @@ void GxsForumThreadWidget::updateDisplay(bool complete) if (grpIds.find(groupId())!=grpIds.end()){ updateGroup = true; /* Update threads */ + mUpdating=true; mThreadModel->setForum(groupId()); } else { std::map > msgIds; @@ -615,7 +621,10 @@ void GxsForumThreadWidget::updateDisplay(bool complete) } if (msgIds.find(groupId()) != msgIds.end()) + { + mUpdating=true; mThreadModel->setForum(groupId()); /* Update threads */ + } } if (updateGroup) { @@ -855,6 +864,9 @@ void GxsForumThreadWidget::togglethreadview_internal() void GxsForumThreadWidget::changedVersion() { + if(mUpdating) + return; + mThreadId = RsGxsMessageId(ui->versions_CB->itemData(ui->versions_CB->currentIndex()).toString().toStdString()) ; ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages()) ; @@ -863,6 +875,9 @@ void GxsForumThreadWidget::changedVersion() void GxsForumThreadWidget::changedThread(QModelIndex index) { + if(mUpdating) + return; + if(!index.isValid()) { mThreadId.clear(); @@ -884,6 +899,9 @@ void GxsForumThreadWidget::changedThread(QModelIndex index) void GxsForumThreadWidget::clickedThread(QModelIndex index) { + if(mUpdating) + return; + if(!index.isValid()) return; @@ -1622,6 +1640,8 @@ void GxsForumThreadWidget::updateGroupName() ui->forumName->setText(QString::fromUtf8(mForumGroup.mMeta.mGroupName.c_str())); ui->threadTreeWidget->sortByColumn(RsGxsForumModel::COLUMN_THREAD_DATE, Qt::DescendingOrder); ui->threadTreeWidget->update(); + + mUpdating = false; } void GxsForumThreadWidget::updateGroupData() { diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index e4d4c8d7a..46e80aa33 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -176,6 +176,7 @@ private: QString mForumDescription; int mSubscribeFlags; int mSignFlags; + bool mUpdating; bool mInProcessSettings; bool mInMsgAsReadUnread; int mLastViewType; From b63544e85648b3a32faad4a72073dcac69f6ce8c Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 4 Dec 2018 22:14:54 +0100 Subject: [PATCH 55/79] suppressed 2 uninitialized memory read in ForumModel --- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index e5c49caa3..c16a8752b 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -47,6 +47,7 @@ RsGxsForumModel::RsGxsForumModel(QObject *parent) mUseChildTS=false; mFilteringEnabled=false; + mTreeMode = TREE_MODE_TREE; } void RsGxsForumModel::preMods() @@ -489,7 +490,10 @@ void RsGxsForumModel::setFilter(int column,const QStringList& strings,uint32_t& mFilteringEnabled = true; } else + { + count=0; mFilteringEnabled = false; + } postMods(); } From 6fae40d417fafcb2c0573a7755a1cb57d44b0338 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 4 Dec 2018 23:10:24 +0100 Subject: [PATCH 56/79] trying new notification system using begin/end remove/insert rows to avoid crash --- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index c16a8752b..6fe7f2ee2 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -53,13 +53,12 @@ RsGxsForumModel::RsGxsForumModel(QObject *parent) void RsGxsForumModel::preMods() { emit layoutAboutToBeChanged(); - beginResetModel(); } void RsGxsForumModel::postMods() { - endResetModel(); + //emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(rowCount(QModelIndex())-1,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); - emit layoutChanged(); + //emit layoutChanged(); } void RsGxsForumModel::setTreeMode(TreeMode mode) @@ -695,6 +694,9 @@ void RsGxsForumModel::setPosts(const RsGxsForumGroup& group, const std::vector Date: Tue, 4 Dec 2018 23:36:07 +0100 Subject: [PATCH 57/79] keep current selection when updating a forum. Still need to keep the expand/collapse property --- .../src/gui/gxsforums/GxsForumModel.cpp | 2 -- .../gui/gxsforums/GxsForumThreadWidget.cpp | 27 ++++++++++++++----- .../src/gui/gxsforums/GxsForumThreadWidget.h | 2 +- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 6fe7f2ee2..d3336abe5 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -56,9 +56,7 @@ void RsGxsForumModel::preMods() } void RsGxsForumModel::postMods() { - //emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(rowCount(QModelIndex())-1,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(0,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); - //emit layoutChanged(); } void RsGxsForumModel::setTreeMode(TreeMode mode) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 1edfe9e34..b6011a67c 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -338,7 +338,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget connect(ui->newmessageButton, SIGNAL(clicked()), this, SLOT(replytoforummessage())); connect(ui->newthreadButton, SIGNAL(clicked()), this, SLOT(createthread())); - connect(mThreadModel,SIGNAL(forumLoaded()),this,SLOT(updateGroupName())); + connect(mThreadModel,SIGNAL(forumLoaded()),this,SLOT(postForumLoading())); ui->newmessageButton->setText(tr("Reply")); ui->newthreadButton->setText(tr("New thread")); @@ -589,6 +589,8 @@ void GxsForumThreadWidget::updateDisplay(bool complete) if (complete) { /* Fill complete */ + + mUpdating=true; updateGroupData(); mThreadModel->setForum(groupId()); @@ -1601,6 +1603,7 @@ void GxsForumThreadWidget::filterItems(const QString& text) ui->filterLineEdit->setToolTip(tr("Found %1 results.").arg(count)) ; } +#ifdef TO_REMOVE bool GxsForumThreadWidget::filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn) { bool visible = true; @@ -1627,16 +1630,28 @@ bool GxsForumThreadWidget::filterItem(QTreeWidgetItem *item, const QString &text return (visible || visibleChildCount); } +#endif /*********************** **** **** **** ***********************/ /** Request / Response of Data ********************************/ /*********************** **** **** **** ***********************/ -void GxsForumThreadWidget::updateGroupName() +void GxsForumThreadWidget::postForumLoading() { - ui->threadTreeWidget->selectionModel()->clear(); - ui->threadTreeWidget->selectionModel()->reset(); - mThreadId.clear(); + QModelIndex indx = mThreadModel->getIndexOfMessage(mThreadId); + + if(indx.isValid()) + { + QModelIndex index = mThreadProxyModel->mapFromSource(indx); + ui->threadTreeWidget->selectionModel()->select(index,QItemSelectionModel::ClearAndSelect); + } + else + { + ui->threadTreeWidget->selectionModel()->clear(); + ui->threadTreeWidget->selectionModel()->reset(); + mThreadId.clear(); + } + ui->forumName->setText(QString::fromUtf8(mForumGroup.mMeta.mGroupName.c_str())); ui->threadTreeWidget->sortByColumn(RsGxsForumModel::COLUMN_THREAD_DATE, Qt::DescendingOrder); ui->threadTreeWidget->update(); @@ -1650,7 +1665,7 @@ void GxsForumThreadWidget::updateGroupData() mSubscribeFlags = 0; mSignFlags = 0; - mThreadId.clear(); + //mThreadId.clear(); mForumDescription.clear(); ui->threadTreeWidget->selectionModel()->clear(); ui->threadTreeWidget->selectionModel()->reset(); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 46e80aa33..4a01628a1 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -102,7 +102,7 @@ private slots: void changedThread(QModelIndex index); void changedVersion(); void clickedThread (QModelIndex index); - void updateGroupName(); + void postForumLoading(); void reply_with_private_message(); void replytoforummessage(); From 600a3d8e169c0bce0d7e9f1f3353f3e3082d4764 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 5 Dec 2018 20:28:58 +0100 Subject: [PATCH 58/79] fixed saving/restoring of expanded items in forum model --- .../gui/gxsforums/GxsForumThreadWidget.cpp | 100 ++++++++++++------ .../src/gui/gxsforums/GxsForumThreadWidget.h | 7 +- 2 files changed, 74 insertions(+), 33 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index b6011a67c..f664842ce 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -582,16 +582,47 @@ static void removeMessages(std::map > &ms } } +void GxsForumThreadWidget::saveExpandedItems(QList& expanded_items) const +{ + expanded_items.clear(); + + for(int row = 0; row < mThreadProxyModel->rowCount(); ++row) + { + std::string path = mThreadProxyModel->index(row,0).data(Qt::DisplayRole).toString().toStdString(); + + recursSaveExpandedItems(mThreadProxyModel->index(row,0),expanded_items); + } +} + +void GxsForumThreadWidget::recursSaveExpandedItems(const QModelIndex& index, QList& expanded_items) const +{ + if(ui->threadTreeWidget->isExpanded(index)) + { + for(int row=0;rowrowCount(index);++row) + recursSaveExpandedItems(index.child(row,0),expanded_items) ; + + RsGxsMessageId message_id(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_MSGID).data(Qt::UserRole).toString().toStdString()); + expanded_items.push_back(message_id); + } +} + +void GxsForumThreadWidget::recursRestoreExpandedItems(const QModelIndex& index, const QList& expanded_items) +{ + for(auto it(expanded_items.begin());it!=expanded_items.end();++it) + ui->threadTreeWidget->setExpanded( mThreadProxyModel->mapFromSource(mThreadModel->getIndexOfMessage(*it)) ,true) ; +} + void GxsForumThreadWidget::updateDisplay(bool complete) { - if(mUpdating) - return; + if(mUpdating) + return; if (complete) { /* Fill complete */ + saveExpandedItems(mSavedExpandedMessages); - mUpdating=true; + mUpdating=true; updateGroupData(); mThreadModel->setForum(groupId()); insertMessage(); @@ -600,37 +631,44 @@ void GxsForumThreadWidget::updateDisplay(bool complete) return; } + else + { - bool updateGroup = false; - const std::set &grpIdsMeta = getGrpIdsMeta(); + bool updateGroup = false; + const std::set &grpIdsMeta = getGrpIdsMeta(); - if(grpIdsMeta.find(groupId())!=grpIdsMeta.end()) - updateGroup = true; + if(grpIdsMeta.find(groupId())!=grpIdsMeta.end()) + updateGroup = true; - const std::set &grpIds = getGrpIds(); - if (grpIds.find(groupId())!=grpIds.end()){ - updateGroup = true; - /* Update threads */ - mUpdating=true; - mThreadModel->setForum(groupId()); - } else { - std::map > msgIds; - getAllMsgIds(msgIds); + const std::set &grpIds = getGrpIds(); - if (!mIgnoredMsgId.empty()) { - /* Filter ignored messages */ - removeMessages(msgIds, mIgnoredMsgId); + if (grpIds.find(groupId())!=grpIds.end()){ + updateGroup = true; + /* Update threads */ + mUpdating=true; + mThreadModel->setForum(groupId()); + } + else + { + std::map > msgIds; + getAllMsgIds(msgIds); + + if (!mIgnoredMsgId.empty()) /* Filter ignored messages */ + removeMessages(msgIds, mIgnoredMsgId); + + if (msgIds.find(groupId()) != msgIds.end()) + { + mUpdating=true; + + saveExpandedItems(mSavedExpandedMessages); + + mThreadModel->setForum(groupId()); /* Update threads */ + } } - if (msgIds.find(groupId()) != msgIds.end()) - { - mUpdating=true; - mThreadModel->setForum(groupId()); /* Update threads */ - } - } + if (updateGroup) + updateGroupData(); - if (updateGroup) { - updateGroupData(); } } @@ -1531,10 +1569,6 @@ void GxsForumThreadWidget::replyForumMessageData(const RsGxsForumMsg &msg) { CreateGxsForumMsg *cfm = new CreateGxsForumMsg(groupId(), mThreadId,RsGxsMessageId()); -// QTextDocument doc ; -// doc.setHtml(QString::fromUtf8(msg.mMsg.c_str()) ); -// std::string cited_text(doc.toPlainText().toStdString()) ; - RsHtml::makeQuotedText(ui->postText); cfm->insertPastedText(RsHtml::makeQuotedText(ui->postText)) ; @@ -1651,11 +1685,14 @@ void GxsForumThreadWidget::postForumLoading() ui->threadTreeWidget->selectionModel()->reset(); mThreadId.clear(); } + // we also need to restore expanded threads ui->forumName->setText(QString::fromUtf8(mForumGroup.mMeta.mGroupName.c_str())); ui->threadTreeWidget->sortByColumn(RsGxsForumModel::COLUMN_THREAD_DATE, Qt::DescendingOrder); ui->threadTreeWidget->update(); + recursRestoreExpandedItems(mThreadProxyModel->mapFromSource(mThreadModel->root()),mSavedExpandedMessages); + mUpdating = false; } void GxsForumThreadWidget::updateGroupData() @@ -1665,7 +1702,6 @@ void GxsForumThreadWidget::updateGroupData() mSubscribeFlags = 0; mSignFlags = 0; - //mThreadId.clear(); mForumDescription.clear(); ui->threadTreeWidget->selectionModel()->clear(); ui->threadTreeWidget->selectionModel()->reset(); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 4a01628a1..9dba7efb5 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -152,6 +152,10 @@ private: void insertMessage(); void insertGroupData(); + void recursRestoreExpandedItems(const QModelIndex& index, const QList& expanded_items); + void recursSaveExpandedItems(const QModelIndex& index, QList& expanded_items) const; + void saveExpandedItems(QList& expanded_items) const; + int getSelectedMsgCount(QList *pRows, QList *pRowsRead, QList *pRowsUnread); void setMsgReadStatus(QList &rows, bool read); void markMsgAsReadUnread(bool read, bool children, bool forum); @@ -159,7 +163,7 @@ private: void togglethreadview_internal(); - bool filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn); + //bool filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn); void processSettings(bool bLoad); @@ -197,6 +201,7 @@ private: RsGxsForumModel *mThreadModel; QSortFilterProxyModel *mThreadProxyModel; + QList mSavedExpandedMessages; Ui::GxsForumThreadWidget *ui; }; From 5b8a64b6777c833642e5ca3ea7e067ab9c501b34 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 6 Dec 2018 23:04:53 +0100 Subject: [PATCH 59/79] fixed a number of bugs in the update/display of forum model --- libretroshare/src/gxs/rsgxsdataaccess.cc | 5 +- retroshare-gui/src/gui/gxs/GxsIdDetails.cpp | 2 +- .../src/gui/gxsforums/GxsForumModel.cpp | 46 ++++- .../src/gui/gxsforums/GxsForumModel.h | 4 +- .../gui/gxsforums/GxsForumThreadWidget.cpp | 186 +++++++++--------- .../src/gui/gxsforums/GxsForumThreadWidget.h | 7 +- 6 files changed, 140 insertions(+), 110 deletions(-) diff --git a/libretroshare/src/gxs/rsgxsdataaccess.cc b/libretroshare/src/gxs/rsgxsdataaccess.cc index f9049d9f0..1206696f7 100644 --- a/libretroshare/src/gxs/rsgxsdataaccess.cc +++ b/libretroshare/src/gxs/rsgxsdataaccess.cc @@ -1714,10 +1714,11 @@ void RsGxsDataAccess::filterMsgList( MsgMetaFilter::const_iterator cit = msgMetas.find(groupId); if(cit == msgMetas.end()) continue; - +#ifdef DATA_DEBUG std::cerr << __PRETTY_FUNCTION__ << " " << msgsIdSet.size() << " for group: " << groupId << " before filtering" << std::endl; +#endif for( std::set::iterator msgIdIt = msgsIdSet.begin(); msgIdIt != msgsIdSet.end(); ) @@ -1738,9 +1739,11 @@ void RsGxsDataAccess::filterMsgList( else msgIdIt = msgsIdSet.erase(msgIdIt); } +#ifdef DATA_DEBUG std::cerr << __PRETTY_FUNCTION__ << " " << msgsIdSet.size() << " for group: " << groupId << " after filtering" << std::endl; +#endif } } diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp index fac557122..6168090eb 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp @@ -37,7 +37,7 @@ #define IMAGE_PGPKNOWN ":/images/contact.png" #define IMAGE_PGPUNKNOWN ":/images/tags/pgp-unknown.png" #define IMAGE_ANON ":/images/tags/anon.png" -#define IMAGE_BANNED ":/icons/yellow_biohazard64.png" +#define IMAGE_BANNED ":/icons/biohazard_red.png" #define IMAGE_DEV_AMBASSADOR ":/images/tags/dev-ambassador.png" #define IMAGE_DEV_CONTRIBUTOR ":/images/tags/vote_down.png" diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index d3336abe5..444b8e7ee 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -664,13 +664,8 @@ QVariant RsGxsForumModel::decorationRole(const ForumModelPostEntry& fmpe,int col return QVariant(); } -void RsGxsForumModel::setForum(const RsGxsGroupId& forum_group_id) +void RsGxsForumModel::updateForum(const RsGxsGroupId& forum_group_id) { - //if(mForumGroup.mMeta.mGroupId == forum_group_id) - // return ; - - // we do not set mForumGroupId yet. We'll do it when the forum data is updated. - if(forum_group_id.isNull()) return; @@ -818,12 +813,19 @@ void RsGxsForumModel::convertMsgToPostEntry(const RsGxsForumGroup& mForumGroup,c // Early check for a message that should be hidden because its author // is flagged with a bad reputation + computeReputationLevel(mForumGroup.mMeta.mSignFlags,fentry); +} + +void RsGxsForumModel::computeReputationLevel(uint32_t forum_sign_flags,ForumModelPostEntry& fentry) +{ uint32_t idflags =0; - RsReputations::ReputationLevel reputation_level = rsReputations->overallReputationLevel(msg.mMeta.mAuthorId,&idflags) ; + RsReputations::ReputationLevel reputation_level = rsReputations->overallReputationLevel(fentry.mAuthorId,&idflags) ; bool redacted = false; if(reputation_level == RsReputations::REPUTATION_LOCALLY_NEGATIVE) - fentry.mPostFlags |= ForumModelPostEntry::FLAG_POST_IS_REDACTED; + fentry.mPostFlags |= ForumModelPostEntry::FLAG_POST_IS_REDACTED; + else + fentry.mPostFlags &= ~ForumModelPostEntry::FLAG_POST_IS_REDACTED; // We use a specific item model for forums in order to handle the post pinning. @@ -831,7 +833,7 @@ void RsGxsForumModel::convertMsgToPostEntry(const RsGxsForumGroup& mForumGroup,c fentry.mReputationWarningLevel = 3 ; else if(reputation_level == RsReputations::REPUTATION_LOCALLY_NEGATIVE) fentry.mReputationWarningLevel = 2 ; - else if(reputation_level < rsGxsForums->minReputationForForwardingMessages(mForumGroup.mMeta.mSignFlags,idflags)) + else if(reputation_level < rsGxsForums->minReputationForForwardingMessages(forum_sign_flags,idflags)) fentry.mReputationWarningLevel = 1 ; else fentry.mReputationWarningLevel = 0 ; @@ -1278,4 +1280,30 @@ void RsGxsForumModel::debug_dump() } #endif +void RsGxsForumModel::setAuthorOpinion(const QModelIndex& indx,RsReputations::Opinion op) +{ + if(!indx.isValid()) + return ; + void *ref = indx.internalPointer(); + uint32_t entry = 0; + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + return ; + + std::cerr << "Setting own opinion for author " << mPosts[entry].mAuthorId << " to " << op << std::endl; + RsGxsId author_id = mPosts[entry].mAuthorId; + + rsReputations->setOwnOpinion(author_id,op) ; + + // update opinions and distribution flags. No need to re-load all posts. + + for(uint32_t i=0;i > getPostVersions(const RsGxsMessageId& mid) const; // This method will asynchroneously update the data - void setForum(const RsGxsGroupId& forumGroup); + void updateForum(const RsGxsGroupId& forumGroup); void setTreeMode(TreeMode mode) ; void setSortMode(SortMode mode) ; @@ -117,6 +117,7 @@ public: void setMsgReadStatus(const QModelIndex &i, bool read_status, bool with_children); void setFilter(int column, const QStringList &strings, uint32_t &count) ; + void setAuthorOpinion(const QModelIndex& indx,RsReputations::Opinion op); int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; @@ -175,6 +176,7 @@ private: static bool convertTabEntryToRefPointer(uint32_t entry,void *& ref); static bool convertRefPointerToTabEntry(void *ref,uint32_t& entry); + static void computeReputationLevel(uint32_t forum_sign_flags, ForumModelPostEntry& entry); void update_posts(const RsGxsGroupId &group_id); void setForumMessageSummary(const std::vector& messages); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index f664842ce..5fcdf948d 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -304,9 +304,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget setUpdateWhenInvisible(true); - mSubscribeFlags = 0; mUpdating = false; - mSignFlags = 0; mUnreadCount = 0; mNewCount = 0; @@ -405,7 +403,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget setGroupId(forumId); - ui->threadTreeWidget->installEventFilter(this) ; + //ui->threadTreeWidget->installEventFilter(this) ; ui->postText->clear() ; ui->by_label->setId(RsGxsId()) ; @@ -511,7 +509,7 @@ void GxsForumThreadWidget::groupIdChanged() mNewCount = 0; mUnreadCount = 0; - mThreadModel->setForum(groupId()); + //mThreadModel->updateForum(groupId()); updateDisplay(true); } @@ -535,6 +533,7 @@ QIcon GxsForumThreadWidget::groupIcon() return QIcon(); } +#ifdef TO_REMOVE void GxsForumThreadWidget::changeEvent(QEvent *e) { RsGxsUpdateBroadcastWidget::changeEvent(e); @@ -581,6 +580,7 @@ static void removeMessages(std::map > &ms } } } +#endif void GxsForumThreadWidget::saveExpandedItems(QList& expanded_items) const { @@ -614,62 +614,74 @@ void GxsForumThreadWidget::recursRestoreExpandedItems(const QModelIndex& index, void GxsForumThreadWidget::updateDisplay(bool complete) { + std::cerr << "udateDisplay: groupId()=" << groupId()<< std::endl; + if(mUpdating) + { + std::cerr << " Already updating. Return!"<< std::endl; return; + } - if (complete) { - /* Fill complete */ + if(groupId().isNull()) + { + std::cerr << " group_id=0. Return!"<< std::endl; + return; + } + if(mForumGroup.mMeta.mGroupId.isNull() && !groupId().isNull()) + { + std::cerr << " inconsistent group data. Reloading!"<< std::endl; + complete = true; + } + + if(!complete) + { + std::cerr << " checking changed group data and msgs"<< std::endl; + + const std::set &grpIdsMeta = getGrpIdsMeta(); + + if(grpIdsMeta.find(groupId())!=grpIdsMeta.end()) + { + std::cerr << " grpMeta change. reloading!" << std::endl; + complete = true; + } + + const std::set &grpIds = getGrpIds(); + + if (grpIds.find(groupId())!=grpIds.end()) + { + std::cerr << " grp data change. reloading!" << std::endl; + complete = true; + } + else + { + // retrieve the list of modified msg ids + // if current group is listed in the map, reload the whole hierarchy + + std::map > msgIds; + getAllMsgIds(msgIds); + + // if (!mIgnoredMsgId.empty()) /* Filter ignored messages */ + // removeMessages(msgIds, mIgnoredMsgId); + + if (msgIds.find(groupId()) != msgIds.end()) + { + std::cerr << " msg data change. reloading!" << std::endl; + complete=true; + } + } + } + + if(complete) // need to update the group data, reload the messages etc. + { saveExpandedItems(mSavedExpandedMessages); mUpdating=true; updateGroupData(); - mThreadModel->setForum(groupId()); - insertMessage(); - - mIgnoredMsgId.clear(); + mThreadModel->updateForum(groupId()); return; } - else - { - - bool updateGroup = false; - const std::set &grpIdsMeta = getGrpIdsMeta(); - - if(grpIdsMeta.find(groupId())!=grpIdsMeta.end()) - updateGroup = true; - - const std::set &grpIds = getGrpIds(); - - if (grpIds.find(groupId())!=grpIds.end()){ - updateGroup = true; - /* Update threads */ - mUpdating=true; - mThreadModel->setForum(groupId()); - } - else - { - std::map > msgIds; - getAllMsgIds(msgIds); - - if (!mIgnoredMsgId.empty()) /* Filter ignored messages */ - removeMessages(msgIds, mIgnoredMsgId); - - if (msgIds.find(groupId()) != msgIds.end()) - { - mUpdating=true; - - saveExpandedItems(mSavedExpandedMessages); - - mThreadModel->setForum(groupId()); /* Update threads */ - } - } - - if (updateGroup) - updateGroupData(); - - } } QModelIndex GxsForumThreadWidget::GxsForumThreadWidget::getCurrentIndex() const @@ -728,7 +740,7 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) connect(flagasnegativeAct, SIGNAL(triggered()), this, SLOT(flagperson())); QAction *newthreadAct = new QAction(QIcon(IMAGE_MESSAGE), tr("Start New Thread"), &contextMnu); - newthreadAct->setEnabled (IS_GROUP_SUBSCRIBED(mSubscribeFlags)); + newthreadAct->setEnabled (IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags)); connect(newthreadAct , SIGNAL(triggered()), this, SLOT(createthread())); QAction* expandAll = new QAction(tr("Expand all"), &contextMnu); @@ -752,7 +764,7 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) QAction *showinpeopleAct = new QAction(QIcon(":/images/info16.png"), tr("Show author in people tab"), &contextMnu); connect(showinpeopleAct, SIGNAL(triggered()), this, SLOT(showInPeopleTab())); - if (IS_GROUP_SUBSCRIBED(mSubscribeFlags)) + if (IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags)) { markMsgAsReadChildren->setEnabled(current_post.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN); markMsgAsUnreadChildren->setEnabled(current_post.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_READ_CHILDREN); @@ -796,7 +808,7 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) } } - if(IS_GROUP_ADMIN(mSubscribeFlags) && (current_post.mParent == 0)) + if(IS_GROUP_ADMIN(mForumGroup.mMeta.mSubscribeFlags) && (current_post.mParent == 0)) contextMnu.addAction(pinUpPostAct); } @@ -861,9 +873,9 @@ void GxsForumThreadWidget::contextMenuTextBrowser(QPoint point) delete(contextMnu); } +#ifdef TODO bool GxsForumThreadWidget::eventFilter(QObject *obj, QEvent *event) { -#ifdef TODO if (obj == ui->threadTreeWidget) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(event); @@ -877,9 +889,9 @@ bool GxsForumThreadWidget::eventFilter(QObject *obj, QEvent *event) } // pass the event on to the parent class return RsGxsUpdateBroadcastWidget::eventFilter(obj, event); -#endif return RsGxsUpdateBroadcastWidget::eventFilter(obj, event); } +#endif void GxsForumThreadWidget::togglethreadview() { @@ -945,18 +957,11 @@ void GxsForumThreadWidget::clickedThread(QModelIndex index) if(!index.isValid()) return; - RsGxsMessageId tmp(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_MSGID).data(Qt::UserRole).toString().toStdString()); - - if( tmp.isNull()) - return; - - mThreadId = tmp; - mOrigThreadId = tmp; - std::cerr << "Clicked on message ID " << mThreadId << std::endl; if (index.column() == RsGxsForumModel::COLUMN_THREAD_READ) { + std::cerr << " changing read status" << std::endl; ForumModelPostEntry fmpe; QModelIndex src_index = mThreadProxyModel->mapToSource(index); @@ -965,7 +970,7 @@ void GxsForumThreadWidget::clickedThread(QModelIndex index) mThreadModel->setMsgReadStatus(src_index, IS_MSG_UNREAD(fmpe.mMsgStatus),false); } else - changedThread(index); + std::cerr << " doing nothing" << std::endl; } static void cleanupItems (QList &items) @@ -1011,7 +1016,7 @@ void GxsForumThreadWidget::insertMessage() ui->versions_CB->hide(); ui->time_label->show(); - ui->postText->setText(mForumDescription); + ui->postText->setText(QString::fromUtf8(mForumGroup.mDescription.c_str())); return; } @@ -1034,7 +1039,7 @@ void GxsForumThreadWidget::insertMessage() return; } - mStateHelper->setWidgetEnabled(ui->newmessageButton, (IS_GROUP_SUBSCRIBED(mSubscribeFlags) && mThreadId.isNull() == false)); + mStateHelper->setWidgetEnabled(ui->newmessageButton, (IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags) && mThreadId.isNull() == false)); /* blank text, incase we get nothing */ ui->postText->clear(); @@ -1139,6 +1144,7 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) ui->lineLeft->show(); ui->by_text_label->show(); ui->by_label->show(); + ui->threadTreeWidget->setFocus(); if(redacted) { @@ -1248,7 +1254,7 @@ void GxsForumThreadWidget::nextUnreadMessage() void GxsForumThreadWidget::markMsgAsReadUnread (bool read, bool children, bool forum) { - if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { + if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags)) { return; } @@ -1337,7 +1343,7 @@ void GxsForumThreadWidget::subscribeGroup(bool subscribe) void GxsForumThreadWidget::createmessage() { - if (groupId().isNull () || !IS_GROUP_SUBSCRIBED(mSubscribeFlags)) { + if (groupId().isNull () || !IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags)) { return; } @@ -1418,14 +1424,8 @@ void GxsForumThreadWidget::flagperson() } RsReputations::Opinion opinion = static_cast(qobject_cast(sender())->data().toUInt()); - ForumModelPostEntry fmpe ; - getCurrentPost(fmpe); - RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId); - - std::cerr << "Setting own opinion for author " << fmpe.mAuthorId << " to " << opinion << std::endl; - - rsReputations->setOwnOpinion(fmpe.mAuthorId,opinion) ; + mThreadModel->setAuthorOpinion(mThreadProxyModel->mapToSource(getCurrentIndex()),opinion); } void GxsForumThreadWidget::replytoforummessage() { async_msg_action( &GxsForumThreadWidget::replyForumMessageData ); } @@ -1672,15 +1672,21 @@ bool GxsForumThreadWidget::filterItem(QTreeWidgetItem *item, const QString &text void GxsForumThreadWidget::postForumLoading() { + std::cerr << "Post forum loading..." << std::endl; + QModelIndex indx = mThreadModel->getIndexOfMessage(mThreadId); - if(indx.isValid()) + if(!mThreadId.isNull() && indx.isValid()) { QModelIndex index = mThreadProxyModel->mapFromSource(indx); - ui->threadTreeWidget->selectionModel()->select(index,QItemSelectionModel::ClearAndSelect); + ui->threadTreeWidget->selectionModel()->select(index,QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); + + std::cerr << " re-selecting index of message " << mThreadId << " to " << indx.row() << "," << indx.column() << " " << (void*)indx.internalPointer() << std::endl; } else { + std::cerr << " previously message " << mThreadId << " not visible anymore -> de-selecting" << std::endl; + ui->threadTreeWidget->selectionModel()->clear(); ui->threadTreeWidget->selectionModel()->reset(); mThreadId.clear(); @@ -1692,7 +1698,6 @@ void GxsForumThreadWidget::postForumLoading() ui->threadTreeWidget->update(); recursRestoreExpandedItems(mThreadProxyModel->mapFromSource(mThreadModel->root()),mSavedExpandedMessages); - mUpdating = false; } void GxsForumThreadWidget::updateGroupData() @@ -1700,14 +1705,9 @@ void GxsForumThreadWidget::updateGroupData() if(groupId().isNull()) return; - mSubscribeFlags = 0; - mSignFlags = 0; - mForumDescription.clear(); - ui->threadTreeWidget->selectionModel()->clear(); - ui->threadTreeWidget->selectionModel()->reset(); - mThreadProxyModel->clear(); - - emit groupChanged(this); + // ui->threadTreeWidget->selectionModel()->clear(); + // ui->threadTreeWidget->selectionModel()->reset(); + // mThreadProxyModel->clear(); RsThread::async([this]() { @@ -1732,7 +1732,7 @@ void GxsForumThreadWidget::updateGroupData() // 2 - sort the messages into a proper hierarchy - RsGxsForumGroup group = groups[0]; + RsGxsForumGroup *group = new RsGxsForumGroup(groups[0]); // we use a pointer in order to avoid group deletion while we're in the thread. // 3 - update the model in the UI thread. @@ -1744,12 +1744,11 @@ void GxsForumThreadWidget::updateGroupData() * Qt::QueuedConnection is important! */ - mForumGroup = group; - mSubscribeFlags = group.mMeta.mSubscribeFlags; + mForumGroup = *group; + delete group; ui->threadTreeWidget->setColumnHidden(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); - ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mSubscribeFlags)) ; - + ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags)) ; }, this ); }); @@ -1782,7 +1781,7 @@ void GxsForumThreadWidget::updateMessageData(const RsGxsMessageId& msgId) // 2 - sort the messages into a proper hierarchy - RsGxsForumMsg msg = msgs[0]; + RsGxsForumMsg *msg = new RsGxsForumMsg(msgs[0]); // 3 - update the model in the UI thread. @@ -1794,10 +1793,11 @@ void GxsForumThreadWidget::updateMessageData(const RsGxsMessageId& msgId) * Qt::QueuedConnection is important! */ - insertMessageData(msg); + insertMessageData(*msg); + delete msg; ui->threadTreeWidget->setColumnHidden(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); - ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mSubscribeFlags)) ; + ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags)) ; }, this ); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 9dba7efb5..cfc790324 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -84,8 +84,8 @@ public: virtual void blank(); protected: - bool eventFilter(QObject *obj, QEvent *ev); - void changeEvent(QEvent *e); + //bool eventFilter(QObject *obj, QEvent *ev); + //void changeEvent(QEvent *e); /* RsGxsUpdateBroadcastWidget */ virtual void updateDisplay(bool complete); @@ -177,9 +177,6 @@ private: RsGxsMessageId mThreadId; RsGxsMessageId mOrigThreadId; RsGxsForumGroup mForumGroup; - QString mForumDescription; - int mSubscribeFlags; - int mSignFlags; bool mUpdating; bool mInProcessSettings; bool mInMsgAsReadUnread; From 49ea15449059811f14173627e3c842262b43ef01 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 6 Dec 2018 23:18:56 +0100 Subject: [PATCH 60/79] fixed restoring of current item --- retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 5fcdf948d..70991ba83 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -1679,7 +1679,7 @@ void GxsForumThreadWidget::postForumLoading() if(!mThreadId.isNull() && indx.isValid()) { QModelIndex index = mThreadProxyModel->mapFromSource(indx); - ui->threadTreeWidget->selectionModel()->select(index,QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); + ui->threadTreeWidget->selectionModel()->setCurrentIndex(index,QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); std::cerr << " re-selecting index of message " << mThreadId << " to " << indx.row() << "," << indx.column() << " " << (void*)indx.internalPointer() << std::endl; } From 1163d00ae9ab276f4978b3edc4a4f5fbecf0ea47 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 6 Dec 2018 23:49:14 +0100 Subject: [PATCH 61/79] small check to avoid re-loading already loaded msg --- retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 70991ba83..82118ddae 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -937,7 +937,12 @@ void GxsForumThreadWidget::changedThread(QModelIndex index) return; } - mThreadId = mOrigThreadId = RsGxsMessageId(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_MSGID).data(Qt::UserRole).toString().toStdString()); + RsGxsMessageId new_id(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_MSGID).data(Qt::UserRole).toString().toStdString()); + + if(new_id == mThreadId) + return; + + mThreadId = mOrigThreadId = new_id; std::cerr << "Switched to new thread ID " << mThreadId << std::endl; @@ -1164,7 +1169,6 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) QString extraTxt = RsHtml().formatText(ui->postText->document(), QString::fromUtf8(msg.mMsg.c_str()),flags); ui->postText->setHtml(extraTxt); } - // ui->threadTitle->setText(QString::fromUtf8(msg.mMeta.mMsgName.c_str())); } void GxsForumThreadWidget::previousMessage() From 42aab55961130f66abfd4454e5a6f5d19a8ed4bb Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 7 Dec 2018 21:45:15 +0100 Subject: [PATCH 62/79] fixed changing of read status using button in forum model --- .../gui/gxsforums/GxsForumThreadWidget.cpp | 95 +++++++++++-------- 1 file changed, 55 insertions(+), 40 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 82118ddae..129b9b5a5 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -56,7 +56,7 @@ #include #include -//#define DEBUG_FORUMS +#define DEBUG_FORUMS /* Images for context menu icons */ #define IMAGE_MESSAGE ":/images/mail_new.png" @@ -614,35 +614,46 @@ void GxsForumThreadWidget::recursRestoreExpandedItems(const QModelIndex& index, void GxsForumThreadWidget::updateDisplay(bool complete) { +#ifdef DEBUG_FORUMS std::cerr << "udateDisplay: groupId()=" << groupId()<< std::endl; - +#endif if(mUpdating) { +#ifdef DEBUG_FORUMS std::cerr << " Already updating. Return!"<< std::endl; +#endif return; } if(groupId().isNull()) { +#ifdef DEBUG_FORUMS std::cerr << " group_id=0. Return!"<< std::endl; +#endif return; } if(mForumGroup.mMeta.mGroupId.isNull() && !groupId().isNull()) { +#ifdef DEBUG_FORUMS std::cerr << " inconsistent group data. Reloading!"<< std::endl; +#endif complete = true; } if(!complete) { +#ifdef DEBUG_FORUMS std::cerr << " checking changed group data and msgs"<< std::endl; +#endif const std::set &grpIdsMeta = getGrpIdsMeta(); if(grpIdsMeta.find(groupId())!=grpIdsMeta.end()) { +#ifdef DEBUG_FORUMS std::cerr << " grpMeta change. reloading!" << std::endl; +#endif complete = true; } @@ -650,7 +661,9 @@ void GxsForumThreadWidget::updateDisplay(bool complete) if (grpIds.find(groupId())!=grpIds.end()) { +#ifdef DEBUG_FORUMS std::cerr << " grp data change. reloading!" << std::endl; +#endif complete = true; } else @@ -666,7 +679,9 @@ void GxsForumThreadWidget::updateDisplay(bool complete) if (msgIds.find(groupId()) != msgIds.end()) { +#ifdef DEBUG_FORUMS std::cerr << " msg data change. reloading!" << std::endl; +#endif complete=true; } } @@ -709,8 +724,9 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) ForumModelPostEntry current_post ; bool has_current_post = getCurrentPost(current_post); - +#ifdef DEBUG_FORUMS std::cerr << "Clicked on msg " << current_post.mMsgId << std::endl; +#endif QAction *editAct = new QAction(QIcon(IMAGE_MESSAGEEDIT), tr("Edit"), &contextMnu); connect(editAct, SIGNAL(triggered()), this, SLOT(editforummessage())); @@ -827,8 +843,9 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) if(has_current_post) { +#ifdef DEBUG_FORUMS std::cerr << "Author is: " << current_post.mAuthorId << std::endl; - +#endif contextMnu.addSeparator(); RsReputations::Opinion op ; @@ -944,13 +961,17 @@ void GxsForumThreadWidget::changedThread(QModelIndex index) mThreadId = mOrigThreadId = new_id; +#ifdef DEBUG_FORUMS std::cerr << "Switched to new thread ID " << mThreadId << std::endl; - +#endif //ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages()) ; insertMessage(); QModelIndex src_index = mThreadProxyModel->mapToSource(index); +#ifdef DEBUG_FORUMS + std::cerr << "Setting message read status to true" << std::endl; +#endif mThreadModel->setMsgReadStatus(src_index, true,false); } @@ -962,20 +983,26 @@ void GxsForumThreadWidget::clickedThread(QModelIndex index) if(!index.isValid()) return; +#ifdef DEBUG_FORUMS std::cerr << "Clicked on message ID " << mThreadId << std::endl; +#endif if (index.column() == RsGxsForumModel::COLUMN_THREAD_READ) { - std::cerr << " changing read status" << std::endl; ForumModelPostEntry fmpe; QModelIndex src_index = mThreadProxyModel->mapToSource(index); mThreadModel->getPostData(src_index,fmpe); +#ifdef DEBUG_FORUMS + std::cerr << "Setting message read status to false" << std::endl; +#endif mThreadModel->setMsgReadStatus(src_index, IS_MSG_UNREAD(fmpe.mMsgStatus),false); } +#ifdef DEBUG_FORUMS else std::cerr << " doing nothing" << std::endl; +#endif } static void cleanupItems (QList &items) @@ -1059,7 +1086,9 @@ void GxsForumThreadWidget::insertMessage() std::vector > post_versions = mThreadModel->getPostVersions(mOrigThreadId); +#ifdef DEBUG_FORUMS std::cerr << "Looking into existing versions for post " << mOrigThreadId << ", thread history: " << post_versions.size() << std::endl; +#endif ui->versions_CB->blockSignals(true) ; while(ui->versions_CB->count() > 0) @@ -1067,7 +1096,9 @@ void GxsForumThreadWidget::insertMessage() if(!post_versions.empty()) { +#ifdef DEBUG_FORUMS std::cerr << post_versions.size() << " versions found " << std::endl; +#endif ui->versions_CB->setVisible(true) ; ui->time_label->hide(); @@ -1079,7 +1110,9 @@ void GxsForumThreadWidget::insertMessage() ui->versions_CB->insertItem(i, ((i==0)?tr("(Latest) "):tr("(Old) "))+" "+DateTime::formatLongDateTime( post_versions[i].first)); ui->versions_CB->setItemData(i,QString::fromStdString(post_versions[i].second.toStdString())); +#ifdef DEBUG_FORUMS std::cerr << " added new post version " << post_versions[i].first << " " << post_versions[i].second << std::endl; +#endif if(mThreadId == post_versions[i].second) current_index = i ; @@ -1098,7 +1131,7 @@ void GxsForumThreadWidget::insertMessage() /* request Post */ updateMessageData(mThreadId); - markMsgAsRead(); +// markMsgAsRead(); } void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) @@ -1127,7 +1160,7 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) uint32_t status = msg.mMeta.mMsgStatus ;//item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); QModelIndex index = getCurrentIndex(); - +#ifdef TO_REMOVE if (IS_MSG_NEW(status)) { if (setToReadOnActive) { /* set to read */ @@ -1142,6 +1175,7 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) mThreadModel->setMsgReadStatus(mThreadProxyModel->mapToSource(index), true,false); } } +#endif ui->time_label->setText(DateTime::formatLongDateTime(msg.mMeta.mPublishTs)); ui->by_label->setId(msg.mMeta.mAuthorId); @@ -1252,6 +1286,7 @@ void GxsForumThreadWidget::nextUnreadMessage() while(index.isValid() && !IS_MSG_UNREAD(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_DATA).data(RsGxsForumModel::StatusRole).toUInt())); ui->threadTreeWidget->setCurrentIndex(index); + ui->threadTreeWidget->scrollTo(index); ui->threadTreeWidget->setFocus(); changedThread(index); } @@ -1310,6 +1345,7 @@ bool GxsForumThreadWidget::navigate(const RsGxsMessageId &msgId) return false; ui->threadTreeWidget->setCurrentIndex(index); + ui->threadTreeWidget->scrollTo(index); ui->threadTreeWidget->setFocus(); changedThread(index); return true; @@ -1374,7 +1410,9 @@ void GxsForumThreadWidget::togglePinUpPost() QString thread_title = index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_TITLE).data(Qt::DisplayRole).toString(); +#ifdef DEBUG_FORUMS std::cerr << "Toggling Pin-up state of post " << mThreadId.toStdString() << ": \"" << thread_title.toStdString() << "\"" << std::endl; +#endif if(mForumGroup.mPinnedPosts.ids.find(mThreadId) == mForumGroup.mPinnedPosts.ids.end()) mForumGroup.mPinnedPosts.ids.insert(mThreadId) ; @@ -1448,7 +1486,9 @@ void GxsForumThreadWidget::async_msg_action(const MsgMethod &action) { // 1 - get message data from p3GxsForums +#ifdef DEBUG_FORUMS std::cerr << "Retrieving post data for post " << mThreadId << std::endl; +#endif std::set msgs_to_request ; std::vector msgs; @@ -1641,56 +1681,31 @@ void GxsForumThreadWidget::filterItems(const QString& text) ui->filterLineEdit->setToolTip(tr("Found %1 results.").arg(count)) ; } -#ifdef TO_REMOVE -bool GxsForumThreadWidget::filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn) -{ - bool visible = true; - - if (text.isEmpty() == false) { - if (item->text(filterColumn).contains(text, Qt::CaseInsensitive) == false) { - visible = false; - } - } - - int visibleChildCount = 0; - int count = item->childCount(); - for (int nIndex = 0; nIndex < count; ++nIndex) { - if (filterItem(item->child(nIndex), text, filterColumn)) { - ++visibleChildCount; - } - } - - if (visible || visibleChildCount) { - item->setHidden(false); - } else { - item->setHidden(true); - } - - return (visible || visibleChildCount); -} -#endif - /*********************** **** **** **** ***********************/ /** Request / Response of Data ********************************/ /*********************** **** **** **** ***********************/ void GxsForumThreadWidget::postForumLoading() { +#ifdef DEBUG_FORUMS std::cerr << "Post forum loading..." << std::endl; - +#endif QModelIndex indx = mThreadModel->getIndexOfMessage(mThreadId); if(!mThreadId.isNull() && indx.isValid()) { QModelIndex index = mThreadProxyModel->mapFromSource(indx); ui->threadTreeWidget->selectionModel()->setCurrentIndex(index,QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); - + ui->threadTreeWidget->scrollTo(index); +#ifdef DEBUG_FORUMS std::cerr << " re-selecting index of message " << mThreadId << " to " << indx.row() << "," << indx.column() << " " << (void*)indx.internalPointer() << std::endl; +#endif } else { +#ifdef DEBUG_FORUMS std::cerr << " previously message " << mThreadId << " not visible anymore -> de-selecting" << std::endl; - +#endif ui->threadTreeWidget->selectionModel()->clear(); ui->threadTreeWidget->selectionModel()->reset(); mThreadId.clear(); From a0b6962beca92916695535c0759bc8e374fb99c3 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 7 Dec 2018 22:09:55 +0100 Subject: [PATCH 63/79] fixed bug in read/unread with children menu items --- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 3 --- retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 444b8e7ee..9a34c908e 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -1201,9 +1201,6 @@ void RsGxsForumModel::recursUpdateReadStatusAndTimes(ForumModelIndex i,bool& has if(mPosts[i].mMostRecentTsInThread < mPosts[mPosts[i].mChildren[j]].mMostRecentTsInThread) mPosts[i].mMostRecentTsInThread = mPosts[mPosts[i].mChildren[j]].mMostRecentTsInThread; - - if(ub && rb) // optimization - break; } if(has_unread_below) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 129b9b5a5..cec369390 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -56,7 +56,7 @@ #include #include -#define DEBUG_FORUMS +//#define DEBUG_FORUMS /* Images for context menu icons */ #define IMAGE_MESSAGE ":/images/mail_new.png" From 7c248dc035b3f4b6a8e5983e3b62640555920008 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 8 Dec 2018 21:43:14 +0100 Subject: [PATCH 64/79] attempt to fix pb on 32bits systems --- retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 9a34c908e..dceb91ecb 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -178,7 +178,7 @@ bool RsGxsForumModel::convertRefPointerToTabEntry(void *ref,uint32_t& entry) { intptr_t val = (intptr_t)ref; - if(val > (intptr_t)(~(uint32_t(0)))) // make sure the pointer is an int that fits in 32bits + if(val > (1<<30)) // make sure the pointer is an int that fits in 32bits and not too big which would look suspicious { std::cerr << "(EE) trying to make a ForumModelIndex out of a number that is larger than 2^32-1 !" << std::endl; return false ; From 459c04a23e52311d3f3237b09a799932ca9951e2 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 8 Dec 2018 22:01:05 +0100 Subject: [PATCH 65/79] re-enabled debug output --- retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index cec369390..129b9b5a5 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -56,7 +56,7 @@ #include #include -//#define DEBUG_FORUMS +#define DEBUG_FORUMS /* Images for context menu icons */ #define IMAGE_MESSAGE ":/images/mail_new.png" From d5928ca84eee953d33fc491d0bc17c0f1daea916 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 8 Dec 2018 22:19:39 +0100 Subject: [PATCH 66/79] fixed message loading bug due to currentIndex() not being ready when insertMessage() is called --- .../src/gui/gxsforums/GxsForumThreadWidget.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 129b9b5a5..4603695c1 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -1034,8 +1034,14 @@ static QString getDurationString(uint32_t days) void GxsForumThreadWidget::insertMessage() { +#ifdef DEBUG_FORUMS + std::cerr << "Inserting message, threadId=" << mThreadId <versions_CB->hide(); ui->time_label->show(); @@ -1045,6 +1051,9 @@ void GxsForumThreadWidget::insertMessage() if (mThreadId.isNull()) { +#ifdef DEBUG_FORUMS + std::cerr << " mThreadId=NULL !! That's a bug." << std::endl; +#endif ui->versions_CB->hide(); ui->time_label->show(); @@ -1052,7 +1061,9 @@ void GxsForumThreadWidget::insertMessage() return; } - QModelIndex index = getCurrentIndex(); + // We use this instead of getCurrentIndex() because right here the currentIndex() is not set yet. + + QModelIndex index = mThreadProxyModel->mapFromSource(mThreadModel->getIndexOfMessage(mOrigThreadId)); if (index.isValid()) { @@ -1063,6 +1074,9 @@ void GxsForumThreadWidget::insertMessage() ui->previousButton->setEnabled(curr_index > 0); ui->nextButton->setEnabled(curr_index < count - 1); } else { +#ifdef DEBUG_FORUMS + std::cerr << " current index invalid! That's a bug." << std::endl; +#endif // there is something wrong ui->previousButton->setEnabled(false); ui->nextButton->setEnabled(false); @@ -1159,8 +1173,8 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) bool setToReadOnActive = Settings->getForumMsgSetToReadOnActivate(); uint32_t status = msg.mMeta.mMsgStatus ;//item->data(RsGxsForumModel::COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt(); - QModelIndex index = getCurrentIndex(); #ifdef TO_REMOVE + QModelIndex index = getCurrentIndex(); if (IS_MSG_NEW(status)) { if (setToReadOnActive) { /* set to read */ From d7b5c9766c8270241276a4cac6eae0373142f9b5 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 9 Dec 2018 13:54:30 +0100 Subject: [PATCH 67/79] fixed missing filterAcceptsRow() in forum proxy model --- .../src/gui/gxsforums/GxsForumThreadWidget.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 4603695c1..10ed08a07 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -285,6 +285,14 @@ public: return left.data(RsGxsForumModel::SortRole) < right.data(RsGxsForumModel::SortRole) ; } + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override + { + //std::cerr << "FilterAcceptsRow(): source_row=" << source_row << " parent=" << (void*)source_parent.internalPointer() << " role=\"" << + // sourceModel()->index(source_row,0,source_parent).data(RsGxsForumModel::FilterRole).toString().toStdString() << std::endl; + + return sourceModel()->index(source_row,0,source_parent).data(RsGxsForumModel::FilterRole).toString() == RsGxsForumModel::FilterString ; + } + private: const QHeaderView *m_header ; }; @@ -1684,6 +1692,9 @@ void GxsForumThreadWidget::filterItems(const QString& text) uint32_t count; mThreadModel->setFilter(filterColumn,lst,count) ; + // We do this in order to trigger a new filtering action in the proxy model. + mThreadProxyModel->setFilterRegExp(QRegExp(QString(RsGxsForumModel::FilterString))) ; + if(!lst.empty()) ui->threadTreeWidget->expandAll(); else From a6ed2b26ecefcff214c5aa9d142de31cdbdbdf65 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 9 Dec 2018 16:34:43 +0100 Subject: [PATCH 68/79] fixed author name placement and icon size when loading ID data in forums --- .../src/gui/gxsforums/GxsForumThreadWidget.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 10ed08a07..ccbfd16a2 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -66,7 +66,7 @@ #define IMAGE_DOWNLOAD ":/images/start.png" #define IMAGE_DOWNLOADALL ":/images/startall.png" #define IMAGE_COPYLINK ":/images/copyrslink.png" -#define IMAGE_BIOHAZARD ":/icons/yellow_biohazard64.png" +#define IMAGE_BIOHAZARD ":/icons/biohazard_red.png" #define IMAGE_WARNING_YELLOW ":/icons/warning_yellow_128.png" #define IMAGE_WARNING_RED ":/icons/warning_red_128.png" #define IMAGE_WARNING_UNKNOWN ":/icons/bullet_grey_128.png" @@ -255,16 +255,24 @@ public: else icon = *icons.begin(); + unsigned int warning_level = qvariant_cast(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION).data(Qt::DecorationRole)); + + if(warning_level == 2) + { + str = tr("[Banned]"); + icon = QIcon(IMAGE_BIOHAZARD); + } + if(index.data(RsGxsForumModel::MissingRole).toBool()) painter->drawText(r.topLeft() + QPoint(f/2.0,f*1.0), tr("[None]")); else { QPixmap pix = icon.pixmap(r.size()); - const QPoint p = QPoint(pix.width()/2.0, (r.height() - pix.height())/2); + const QPoint p = QPoint(r.height()/2.0, (r.height() - pix.height())/2); // draw pixmap at center of item painter->drawPixmap(r.topLeft() + p, pix); - painter->drawText(r.topLeft() + p + QPoint(pix.width()+f/2.0,f*1.0), str); + painter->drawText(r.topLeft() + QPoint(r.height()+ f/2.0 + f/2.0,f*1.0), str); } } }; @@ -287,9 +295,6 @@ public: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override { - //std::cerr << "FilterAcceptsRow(): source_row=" << source_row << " parent=" << (void*)source_parent.internalPointer() << " role=\"" << - // sourceModel()->index(source_row,0,source_parent).data(RsGxsForumModel::FilterRole).toString().toStdString() << std::endl; - return sourceModel()->index(source_row,0,source_parent).data(RsGxsForumModel::FilterRole).toString() == RsGxsForumModel::FilterString ; } From 27264cea0a65319331f3c6e67fef7e218a14bae2 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 9 Dec 2018 17:35:31 +0100 Subject: [PATCH 69/79] fixed icons and buttons in forums --- .../src/gui/gxsforums/GxsForumModel.cpp | 13 ++++- .../gui/gxsforums/GxsForumThreadWidget.cpp | 50 +++++++++++++------ .../src/gui/gxsforums/GxsForumThreadWidget.ui | 47 ++++++++++------- 3 files changed, 75 insertions(+), 35 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index dceb91ecb..975944d2a 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -1216,10 +1216,19 @@ void RsGxsForumModel::recursUpdateReadStatusAndTimes(ForumModelIndex i,bool& has QModelIndex RsGxsForumModel::getIndexOfMessage(const RsGxsMessageId& mid) const { - // brutal search. This is not so nice, so dont call that in a loop! + // Brutal search. This is not so nice, so dont call that in a loop! If too costly, we'll use a map. + + RsGxsMessageId postId = mid; + + // First look into msg versions, in case the msg is a version of an existing message + + for(auto it(mPostVersions.begin());it!=mPostVersions.end();++it) + for(uint32_t i=0;isecond.size();++i) + if(it->second[i].second == mid) + postId = it->first; for(uint32_t i=0;ithreadTreeWidget->setCurrentIndex(index); - ui->threadTreeWidget->scrollTo(index); - ui->threadTreeWidget->setFocus(); + ui->threadTreeWidget->scrollTo(index,QAbstractItemView::PositionAtCenter); + //ui->threadTreeWidget->setFocus(); changedThread(index); } @@ -1366,15 +1384,17 @@ void GxsForumThreadWidget::setAllMessagesReadDo(bool read, uint32_t &/*token*/) bool GxsForumThreadWidget::navigate(const RsGxsMessageId &msgId) { - QModelIndex index = mThreadModel->getIndexOfMessage(msgId); + QModelIndex source_index = mThreadModel->getIndexOfMessage(msgId); - if(!index.isValid()) + if(!source_index.isValid()) return false; - ui->threadTreeWidget->setCurrentIndex(index); - ui->threadTreeWidget->scrollTo(index); + QModelIndex indx = mThreadProxyModel->mapFromSource(source_index); + + ui->threadTreeWidget->setCurrentIndex(indx); + ui->threadTreeWidget->scrollTo(indx,QAbstractItemView::PositionAtCenter); ui->threadTreeWidget->setFocus(); - changedThread(index); + changedThread(indx); return true; } @@ -1720,15 +1740,15 @@ void GxsForumThreadWidget::postForumLoading() #ifdef DEBUG_FORUMS std::cerr << "Post forum loading..." << std::endl; #endif - QModelIndex indx = mThreadModel->getIndexOfMessage(mThreadId); + QModelIndex source_index = mThreadModel->getIndexOfMessage(mThreadId); - if(!mThreadId.isNull() && indx.isValid()) + if(!mThreadId.isNull() && source_index.isValid()) { - QModelIndex index = mThreadProxyModel->mapFromSource(indx); + QModelIndex index = mThreadProxyModel->mapFromSource(source_index); ui->threadTreeWidget->selectionModel()->setCurrentIndex(index,QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); - ui->threadTreeWidget->scrollTo(index); + ui->threadTreeWidget->scrollTo(index,QAbstractItemView::PositionAtCenter); #ifdef DEBUG_FORUMS - std::cerr << " re-selecting index of message " << mThreadId << " to " << indx.row() << "," << indx.column() << " " << (void*)indx.internalPointer() << std::endl; + std::cerr << " re-selecting index of message " << mThreadId << " to " << source_index.row() << "," << source_index.column() << " " << (void*)source_index.internalPointer() << std::endl; #endif } else diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui index ae79bd607..122372207 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui @@ -253,28 +253,18 @@ Download all files + + Qt::LeftToRight + - - :/images/down.png:/images/down.png + + :/icons/global_switch_on_128.png:/icons/global_switch_on_128.png true
- - - - - 0 - 0 - - - - Next unread - - - @@ -290,14 +280,14 @@ Reply Message - Reply + - :/images/mail_reply.png:/images/mail_reply.png + :/images/replymailall24-hover.png:/images/replymailall24-hover.png - Qt::ToolButtonTextBesideIcon + Qt::ToolButtonIconOnly true @@ -460,6 +450,26 @@ + + + + + 0 + 0 + + + + Next unread message + + + + + + + :/images/arrow-right.png:/images/arrow-right.png + + + @@ -540,6 +550,7 @@ + From 983ac7dda91670db47ff766c4ddd4b2c2c830906 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 9 Dec 2018 21:22:18 +0100 Subject: [PATCH 70/79] improved icons in forums and removed - button because it is not useful --- .../gui/gxsforums/GxsForumThreadWidget.cpp | 16 ++++--- .../src/gui/gxsforums/GxsForumThreadWidget.ui | 43 +++++++++---------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 9bc8fd487..f0c851b44 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -365,7 +365,9 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget connect(ui->threadTreeWidget->selectionModel(), SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)), this, SLOT(changedSelection(const QModelIndex&,const QModelIndex&))); connect(ui->viewBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changedViewBox())); - connect(ui->expandButton, SIGNAL(clicked()), this, SLOT(togglethreadview())); + //connect(ui->expandButton, SIGNAL(clicked()), this, SLOT(togglethreadview())); + ui->expandButton->hide(); + connect(ui->previousButton, SIGNAL(clicked()), this, SLOT(previousMessage())); connect(ui->nextButton, SIGNAL(clicked()), this, SLOT(nextMessage())); connect(ui->nextUnreadButton, SIGNAL(clicked()), this, SLOT(nextUnreadMessage())); @@ -940,15 +942,15 @@ void GxsForumThreadWidget::togglethreadview() void GxsForumThreadWidget::togglethreadview_internal() { - if (ui->expandButton->isChecked()) { +// if (ui->expandButton->isChecked()) { ui->postText->setVisible(true); ui->expandButton->setIcon(QIcon(QString(":/images/edit_remove24.png"))); ui->expandButton->setToolTip(tr("Hide")); - } else { - ui->postText->setVisible(false); - ui->expandButton->setIcon(QIcon(QString(":/images/edit_add24.png"))); - ui->expandButton->setToolTip(tr("Expand")); - } +// } else { +// ui->postText->setVisible(false); +// ui->expandButton->setIcon(QIcon(QString(":/images/edit_add24.png"))); +// ui->expandButton->setToolTip(tr("Expand")); +// } } void GxsForumThreadWidget::changedVersion() diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui index 122372207..f9d226c94 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui @@ -239,7 +239,7 @@ - + @@ -294,7 +294,7 @@ - + @@ -320,21 +320,14 @@ - - - - Qt::Vertical - - - - + Qt::Vertical - + Qt::Horizontal @@ -426,31 +419,38 @@ - + - - - - By + + + + Qt::Vertical - + - + - + + + + By + + + + @@ -465,8 +465,8 @@ - - :/images/arrow-right.png:/images/arrow-right.png + + :/images/start.png:/images/start.png @@ -550,7 +550,6 @@ - From 34f51fff9c04b818e20a34b9f9ed54067c3d37df Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 9 Dec 2018 23:18:50 +0100 Subject: [PATCH 71/79] made next unread post arrow also work when no post is selected --- retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index f0c851b44..d385e3a85 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -1323,6 +1323,9 @@ void GxsForumThreadWidget::nextUnreadMessage() { QModelIndex index = getCurrentIndex(); + if(!index.isValid()) + index = mThreadProxyModel->index(0,0); + do { if(index.data(RsGxsForumModel::UnreadChildrenRole).toBool()) From 1dda7c5b349d361c2646eaa46b93964387a67d3a Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 9 Dec 2018 23:25:59 +0100 Subject: [PATCH 72/79] removed mUpdating variable which was used for a safety test that is not relevant anymore and caused problems --- .../gui/gxsforums/GxsForumThreadWidget.cpp | 30 ++++++++++--------- .../src/gui/gxsforums/GxsForumThreadWidget.h | 2 +- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index d385e3a85..c769ffa96 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -324,7 +324,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget setUpdateWhenInvisible(true); - mUpdating = false; + //mUpdating = false; mUnreadCount = 0; mNewCount = 0; @@ -639,6 +639,7 @@ void GxsForumThreadWidget::updateDisplay(bool complete) #ifdef DEBUG_FORUMS std::cerr << "udateDisplay: groupId()=" << groupId()<< std::endl; #endif +#ifdef TO_REMOVE if(mUpdating) { #ifdef DEBUG_FORUMS @@ -646,6 +647,7 @@ void GxsForumThreadWidget::updateDisplay(bool complete) #endif return; } +#endif if(groupId().isNull()) { @@ -713,7 +715,7 @@ void GxsForumThreadWidget::updateDisplay(bool complete) { saveExpandedItems(mSavedExpandedMessages); - mUpdating=true; + //mUpdating=true; updateGroupData(); mThreadModel->updateForum(groupId()); @@ -955,8 +957,8 @@ void GxsForumThreadWidget::togglethreadview_internal() void GxsForumThreadWidget::changedVersion() { - if(mUpdating) - return; + //if(mUpdating) + // return; mThreadId = RsGxsMessageId(ui->versions_CB->itemData(ui->versions_CB->currentIndex()).toString().toStdString()) ; @@ -966,8 +968,8 @@ void GxsForumThreadWidget::changedVersion() void GxsForumThreadWidget::changedThread(QModelIndex index) { - if(mUpdating) - return; + //if(mUpdating) + // return; if(!index.isValid()) { @@ -1003,13 +1005,13 @@ void GxsForumThreadWidget::clickedThread(QModelIndex index) std::cerr << "Clicked on message ID " << mThreadId << ", index=" << index << std::endl; #endif - if(mUpdating) - { -#ifdef DEBUG_FORUMS - std::cerr << " early return because mUpdating=true" << std::endl; -#endif - return; - } +// if(mUpdating) +// { +//#ifdef DEBUG_FORUMS +// std::cerr << " early return because mUpdating=true" << std::endl; +//#endif +// return; +// } if(!index.isValid()) { @@ -1772,7 +1774,7 @@ void GxsForumThreadWidget::postForumLoading() ui->threadTreeWidget->update(); recursRestoreExpandedItems(mThreadProxyModel->mapFromSource(mThreadModel->root()),mSavedExpandedMessages); - mUpdating = false; + //mUpdating = false; } void GxsForumThreadWidget::updateGroupData() { diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index cfc790324..495078ea8 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -177,7 +177,7 @@ private: RsGxsMessageId mThreadId; RsGxsMessageId mOrigThreadId; RsGxsForumGroup mForumGroup; - bool mUpdating; + //bool mUpdating; bool mInProcessSettings; bool mInMsgAsReadUnread; int mLastViewType; From b38c6356497b49fb1989f26e823a01d5ce62891a Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 10 Dec 2018 22:51:09 +0100 Subject: [PATCH 73/79] restored display of forum summary when browsing forums --- .../gui/gxsforums/GxsForumThreadWidget.cpp | 104 +++++++++++++++++- .../src/gui/gxsforums/GxsForumThreadWidget.h | 1 + 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index c769ffa96..b6d2fae18 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -463,7 +463,7 @@ void GxsForumThreadWidget::blank() #endif ui->forumName->setText(""); - mThreadModel->clear(); + //mThreadModel->clear(); #ifdef SUSPENDED_CODE mStateHelper->setWidgetEnabled(ui->newthreadButton, false); @@ -530,6 +530,7 @@ void GxsForumThreadWidget::groupIdChanged() mNewCount = 0; mUnreadCount = 0; + mThreadId.clear(); //mThreadModel->updateForum(groupId()); updateDisplay(true); @@ -1067,6 +1068,103 @@ static QString getDurationString(uint32_t days) } } +void GxsForumThreadWidget::updateForumDescription() +{ + if (!mThreadId.isNull()) + return; + + RsIdentityDetails details; + + rsIdentity->getIdDetails(mForumGroup.mMeta.mAuthorId,details); + + QString author = GxsIdDetails::getName(details); + + const RsGxsForumGroup& group = mForumGroup; + + ui->forumName->setText(QString::fromUtf8(group.mMeta.mGroupName.c_str())); + + QString anti_spam_features1 ; + QString forum_description; + + if(IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags)) anti_spam_features1 = tr("Anonymous/unknown posts forwarded if reputation is positive"); + else if(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags)) anti_spam_features1 = tr("Anonymous posts forwarded if reputation is positive"); + + forum_description = QString("%1: \t%2
").arg(tr("Forum name"), QString::fromUtf8( group.mMeta.mGroupName.c_str())); + forum_description += QString("%1: %2
").arg(tr("Description"), group.mDescription.empty()? tr("[None]
") :(QString::fromUtf8(group.mDescription.c_str())+"
")); + forum_description += QString("%1: \t%2
").arg(tr("Subscribers")).arg(group.mMeta.mPop); + forum_description += QString("%1: \t%2
").arg(tr("Posts (at neighbor nodes)")).arg(group.mMeta.mVisibleMsgCount); + + if(group.mMeta.mLastPost==0) + forum_description += QString("%1: \t%2
").arg(tr("Last post")).arg(tr("Never")); + else + forum_description += QString("%1: \t%2
").arg(tr("Last post")).arg(DateTime::formatLongDateTime(group.mMeta.mLastPost)); + + forum_description += QString("%1: \t%2
").arg(tr("Synchronization")).arg(getDurationString( rsGxsForums->getSyncPeriod(group.mMeta.mGroupId)/86400 )) ; + forum_description += QString("%1: \t%2
").arg(tr("Storage")).arg(getDurationString( rsGxsForums->getStoragePeriod(group.mMeta.mGroupId)/86400)); + + QString distrib_string = tr("[unknown]"); + switch(group.mMeta.mCircleType) + { + case GXS_CIRCLE_TYPE_PUBLIC: distrib_string = tr("Public") ; + break ; + case GXS_CIRCLE_TYPE_EXTERNAL: + { + RsGxsCircleDetails det ; + + // !! What we need here is some sort of CircleLabel, which loads the circle and updates the label when done. + + if(rsGxsCircles->getCircleDetails(group.mMeta.mCircleId,det)) + distrib_string = tr("Restricted to members of circle \"")+QString::fromUtf8(det.mCircleName.c_str()) +"\""; + else + distrib_string = tr("Restricted to members of circle ")+QString::fromStdString(group.mMeta.mCircleId.toStdString()) ; + } + break ; + case GXS_CIRCLE_TYPE_YOUR_FRIENDS_ONLY: + { + distrib_string = tr("Only friends nodes in group ") ; + + RsGroupInfo ginfo ; + rsPeers->getGroupInfo(RsNodeGroupId(group.mMeta.mInternalCircle),ginfo) ; + + QString desc; + GroupChooser::makeNodeGroupDesc(ginfo, desc); + distrib_string += desc ; + } + break ; + + case GXS_CIRCLE_TYPE_LOCAL: distrib_string = tr("Your eyes only"); // this is not yet supported. If you see this, it is a bug! + break ; + default: + std::cerr << "(EE) badly initialised group distribution ID = " << group.mMeta.mCircleType << std::endl; + } + + forum_description += QString("%1: \t%2
").arg(tr("Distribution"), distrib_string); + forum_description += QString("%1: \t%2
").arg(tr("Contact"), author); + + if(!anti_spam_features1.isNull()) + forum_description += QString("%1: \t%2
").arg(tr("Anti-spam")).arg(anti_spam_features1); + + ui->subscribeToolButton->setSubscribed(IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags)); + mStateHelper->setWidgetEnabled(ui->newthreadButton, (IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags))); + + if(!group.mAdminList.ids.empty()) + { + QString admin_list_str ; + + for(auto it(group.mAdminList.ids.begin());it!=group.mAdminList.ids.end();++it) + { + RsIdentityDetails det ; + + rsIdentity->getIdDetails(*it,det); + admin_list_str += (admin_list_str.isNull()?"":", ") + QString::fromUtf8(det.mNickname.c_str()) ; + } + + forum_description += QString("%1: %2").arg(tr("Moderators"), admin_list_str); + } + + ui->postText->setText(forum_description); +} + void GxsForumThreadWidget::insertMessage() { #ifdef DEBUG_FORUMS @@ -1766,6 +1864,7 @@ void GxsForumThreadWidget::postForumLoading() ui->threadTreeWidget->selectionModel()->clear(); ui->threadTreeWidget->selectionModel()->reset(); mThreadId.clear(); + //blank(); } // we also need to restore expanded threads @@ -1825,6 +1924,9 @@ void GxsForumThreadWidget::updateGroupData() ui->threadTreeWidget->setColumnHidden(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags)) ; + + updateForumDescription(); + }, this ); }); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index 495078ea8..705d080a3 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -171,6 +171,7 @@ private: static void loadAuthorIdCallback(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &/*data*/); void updateMessageData(const RsGxsMessageId& msgId); + void updateForumDescription(); private: RsGxsGroupId mLastForumID; From 8f9c9295b22a88c7e4fc7fa35f95012724303710 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 11 Dec 2018 22:06:45 +0100 Subject: [PATCH 74/79] added proper timeout of 5 secs to all forum async-ed interactions --- libretroshare/src/services/p3gxsforums.cc | 14 +++++++------- .../src/gui/gxsforums/GxsForumThreadWidget.cpp | 4 +++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/libretroshare/src/services/p3gxsforums.cc b/libretroshare/src/services/p3gxsforums.cc index 0534128e5..1760a2f2b 100644 --- a/libretroshare/src/services/p3gxsforums.cc +++ b/libretroshare/src/services/p3gxsforums.cc @@ -389,7 +389,7 @@ bool p3GxsForums::createForum(RsGxsForumGroup& forum) return false; } - if(waitToken(token) != RsTokenService::COMPLETE) + if(waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE) { std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed." << std::endl; @@ -416,7 +416,7 @@ bool p3GxsForums::editForum(RsGxsForumGroup& forum) return false; } - if(waitToken(token) != RsTokenService::COMPLETE) + if(waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE) { std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed." << std::endl; @@ -440,7 +440,7 @@ bool p3GxsForums::getForumsSummaries( RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_GROUP_META; if( !requestGroupInfo(token, opts) - || waitToken(token) != RsTokenService::COMPLETE ) return false; + || waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE ) return false; return getGroupSummary(token, forums); } @@ -452,7 +452,7 @@ bool p3GxsForums::getForumsInfo( RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; if( !requestGroupInfo(token, opts, forumIds) - || waitToken(token) != RsTokenService::COMPLETE ) return false; + || waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE ) return false; return getGroupData(token, forumsInfo); } @@ -465,7 +465,7 @@ bool p3GxsForums::getForumsContent( const RsGxsGroupId& forumId, std::set(index.data(Qt::DecorationRole)); bool unread = IS_MSG_UNREAD(read_status); - bool missing = index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_DATA).data(ROLE_THREAD_MISSING).toBool(); + bool missing = index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_DATA).data(RsGxsForumModel::MissingRole).toBool(); // set icon if (missing) From a114856b77faa8a5ebd43d230665da8ee97eefe5 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 12 Dec 2018 11:33:38 +0100 Subject: [PATCH 75/79] changed code to create msg data map using MsgMeta instead of full Msg and added the handles to request MsgMeta data in forums --- libretroshare/src/retroshare/rsgxsforums.h | 13 +++- libretroshare/src/services/p3gxsforums.cc | 28 ++++++- libretroshare/src/services/p3gxsforums.h | 4 + .../src/gui/gxsforums/GxsForumModel.cpp | 74 +++++++++---------- .../src/gui/gxsforums/GxsForumModel.h | 4 +- 5 files changed, 81 insertions(+), 42 deletions(-) diff --git a/libretroshare/src/retroshare/rsgxsforums.h b/libretroshare/src/retroshare/rsgxsforums.h index ad73a92c2..c56074e69 100644 --- a/libretroshare/src/retroshare/rsgxsforums.h +++ b/libretroshare/src/retroshare/rsgxsforums.h @@ -139,10 +139,11 @@ public: const std::list& forumIds, std::vector& forumsInfo ) = 0; + /** * @brief Get content of specified forums. Blocking API * @jsonapi{development} - * @param[in] forumIds id of the channels of which the content is requested + * @param[in] forumIds id of the forum of which the content is requested * @param[out] messages storage for the forum messages * @return false if something failed, true otherwhise */ @@ -150,6 +151,16 @@ public: const std::list& forumIds, std::vector& messages ) = 0; + /** + * @brief Get message metadatas for some messages of a specific forum. Blocking API + * @jsonapi{development} + * @param[in] forumIds id of the forum of which the content is requested + * @param[out] msg_metas storage for the forum messages meta data + * @return false if something failed, true otherwhise + */ + virtual bool getForumMsgMetaData( const RsGxsGroupId& forumId, + std::vector& msg_metas) =0; + /** * @brief Get specific list of messages from a single forums. Blocking API * @jsonapi{development} diff --git a/libretroshare/src/services/p3gxsforums.cc b/libretroshare/src/services/p3gxsforums.cc index 1760a2f2b..aaf663d92 100644 --- a/libretroshare/src/services/p3gxsforums.cc +++ b/libretroshare/src/services/p3gxsforums.cc @@ -297,6 +297,11 @@ bool p3GxsForums::getGroupData(const uint32_t &token, std::vector& forums ) +bool p3GxsForums::getForumsSummaries( std::list& forums ) { uint32_t token; RsTokReqOptions opts; @@ -482,6 +486,26 @@ bool p3GxsForums::getForumsContent( return getMsgData(token, messages); } + +bool p3GxsForums::getForumMsgMetaData(const RsGxsGroupId& forumId, std::vector& msg_metas) +{ + uint32_t token; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_MSG_META; + + GxsMsgMetaMap meta_map; + std::list forumIds; + forumIds.push_back(forumId); + + if( !requestMsgInfo(token, opts, forumIds) || waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE ) return false; + + bool res = getMsgMetaData(token, meta_map); + + msg_metas = meta_map[forumId]; + + return res; +} + bool p3GxsForums::markRead(const RsGxsGrpMsgIdPair& msgId, bool read) { uint32_t token; diff --git a/libretroshare/src/services/p3gxsforums.h b/libretroshare/src/services/p3gxsforums.h index 29260c8cf..051368175 100644 --- a/libretroshare/src/services/p3gxsforums.h +++ b/libretroshare/src/services/p3gxsforums.h @@ -77,6 +77,9 @@ public: const std::list& forumIds, std::vector& messages ); + /// @see RsGxsForums::getForumMsgMetaData + virtual bool getForumMsgMetaData(const RsGxsGroupId& forumId, std::vector& msg_metas) ; + /// @see RsGxsForums::getForumsContent virtual bool getForumsContent( const RsGxsGroupId& forumId, std::set& msgs_to_request,std::vector& msgs) ; @@ -85,6 +88,7 @@ public: virtual bool getGroupData(const uint32_t &token, std::vector &groups); virtual bool getMsgData(const uint32_t &token, std::vector &msgs); + virtual bool getMsgMetaData(const uint32_t &token, GxsMsgMetaMap& msg_metas); virtual void setMessageReadStatus(uint32_t& token, const RsGxsGrpMsgIdPair& msgId, bool read); virtual bool createGroup(uint32_t &token, RsGxsForumGroup &group); virtual bool createMsg(uint32_t &token, RsGxsForumMsg &msg); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 975944d2a..d3713a1da 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -727,7 +727,7 @@ void RsGxsForumModel::update_posts(const RsGxsGroupId& group_id) // 1 - get message data from p3GxsForums std::list forumIds; - std::vector messages; + std::vector msg_metas; std::vector groups; forumIds.push_back(group_id); @@ -738,7 +738,7 @@ void RsGxsForumModel::update_posts(const RsGxsGroupId& group_id) return; } - if(!rsGxsForums->getForumsContent(forumIds,messages)) + if(!rsGxsForums->getForumMsgMetaData(group_id,msg_metas)) { std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve forum message info for forum " << group_id << std::endl; return; @@ -750,7 +750,7 @@ void RsGxsForumModel::update_posts(const RsGxsGroupId& group_id) std::vector *vect = new std::vector(); RsGxsForumGroup group = groups[0]; - computeMessagesHierarchy(group,messages,*vect,*post_versions); + computeMessagesHierarchy(group,msg_metas,*vect,*post_versions); // 3 - update the model in the UI thread. @@ -798,16 +798,16 @@ void RsGxsForumModel::generateMissingItem(const RsGxsMessageId &msgId,ForumModel entry.mReputationWarningLevel = 3; } -void RsGxsForumModel::convertMsgToPostEntry(const RsGxsForumGroup& mForumGroup,const RsGxsForumMsg& msg, bool useChildTS, ForumModelPostEntry& fentry) +void RsGxsForumModel::convertMsgToPostEntry(const RsGxsForumGroup& mForumGroup,const RsMsgMetaData& msg, bool useChildTS, ForumModelPostEntry& fentry) { - fentry.mTitle = msg.mMeta.mMsgName; - fentry.mAuthorId = msg.mMeta.mAuthorId; - fentry.mMsgId = msg.mMeta.mMsgId; - fentry.mPublishTs = msg.mMeta.mPublishTs; + fentry.mTitle = msg.mMsgName; + fentry.mAuthorId = msg.mAuthorId; + fentry.mMsgId = msg.mMsgId; + fentry.mPublishTs = msg.mPublishTs; fentry.mPostFlags = 0; - fentry.mMsgStatus = msg.mMeta.mMsgStatus; + fentry.mMsgStatus = msg.mMsgStatus; - if(mForumGroup.mPinnedPosts.ids.find(msg.mMeta.mMsgId) != mForumGroup.mPinnedPosts.ids.end()) + if(mForumGroup.mPinnedPosts.ids.find(msg.mMsgId) != mForumGroup.mPinnedPosts.ids.end()) fentry.mPostFlags |= ForumModelPostEntry::FLAG_POST_IS_PINNED; // Early check for a message that should be hidden because its author @@ -842,12 +842,12 @@ void RsGxsForumModel::computeReputationLevel(uint32_t forum_sign_flags,ForumMode static bool decreasing_time_comp(const std::pair& e1,const std::pair& e2) { return e2.first < e1.first ; } void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_group, - const std::vector& msgs_array, + const std::vector& msgs_metas_array, std::vector& posts, std::map > >& mPostVersions ) { - std::cerr << "updating messages data with " << msgs_array.size() << " messages" << std::endl; + std::cerr << "updating messages data with " << msgs_metas_array.size() << " messages" << std::endl; #ifdef DEBUG_FORUMS std::cerr << "Retrieved group data: " << std::endl; @@ -861,14 +861,14 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou #endif /* get messages */ - std::map msgs; + std::map msgs; - for(uint32_t i=0;i msg_stack ; - for ( std::map::iterator msgIt = msgs.begin(); msgIt != msgs.end();++msgIt) + for ( auto msgIt = msgs.begin(); msgIt != msgs.end();++msgIt) { - if(!msgIt->second.mMeta.mOrigMsgId.isNull() && msgIt->second.mMeta.mOrigMsgId != msgIt->second.mMeta.mMsgId) + if(!msgIt->second.mOrigMsgId.isNull() && msgIt->second.mOrigMsgId != msgIt->second.mMsgId) { #ifdef DEBUG_FORUMS std::cerr << " Post " << msgIt->second.mMeta.mMsgId << " is a new version of " << msgIt->second.mMeta.mOrigMsgId << std::endl; #endif - std::map::iterator msgIt2 = msgs.find(msgIt->second.mMeta.mOrigMsgId); + auto msgIt2 = msgs.find(msgIt->second.mOrigMsgId); // Ensuring that the post exists allows to only collect the existing data. @@ -917,21 +917,21 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou // Make sure that the author is the same than the original message, or is a moderator. This should always happen when messages are constructed using // the UI but nothing can prevent a nasty user to craft a new version of a message with his own signature. - if(msgIt2->second.mMeta.mAuthorId != msgIt->second.mMeta.mAuthorId) + if(msgIt2->second.mAuthorId != msgIt->second.mAuthorId) { - if( !IS_FORUM_MSG_MODERATION(msgIt->second.mMeta.mMsgFlags) ) // if authors are different the moderation flag needs to be set on the editing msg + if( !IS_FORUM_MSG_MODERATION(msgIt->second.mMsgFlags) ) // if authors are different the moderation flag needs to be set on the editing msg continue ; - if( forum_group.mAdminList.ids.find(msgIt->second.mMeta.mAuthorId)==forum_group.mAdminList.ids.end()) // if author is not a moderator, continue + if( forum_group.mAdminList.ids.find(msgIt->second.mAuthorId)==forum_group.mAdminList.ids.end()) // if author is not a moderator, continue continue ; } // always add the post a self version - if(mPostVersions[msgIt->second.mMeta.mOrigMsgId].empty()) - mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(std::make_pair(msgIt2->second.mMeta.mPublishTs,msgIt2->second.mMeta.mMsgId)) ; + if(mPostVersions[msgIt->second.mOrigMsgId].empty()) + mPostVersions[msgIt->second.mOrigMsgId].push_back(std::make_pair(msgIt2->second.mPublishTs,msgIt2->second.mMsgId)) ; - mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(std::make_pair(msgIt->second.mMeta.mPublishTs,msgIt->second.mMeta.mMsgId)) ; + mPostVersions[msgIt->second.mOrigMsgId].push_back(std::make_pair(msgIt->second.mPublishTs,msgIt->second.mMsgId)) ; } } @@ -1008,19 +1008,19 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou // this trick is needed because while we remove messages, the parents a given msg may already have been removed // and wrongly understand as a missing parent. - std::map kept_msgs; + std::map kept_msgs; - for ( std::map::iterator msgIt = msgs.begin(); msgIt != msgs.end();++msgIt) + for ( auto msgIt = msgs.begin(); msgIt != msgs.end();++msgIt) { - if(msgIt->second.mMeta.mParentId.isNull()) + if(msgIt->second.mParentId.isNull()) { /* add all threads */ - const RsGxsForumMsg& msg = msgIt->second; + const RsMsgMetaData& msg = msgIt->second; #ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::run() Adding TopLevel Thread: mId: " << msg.mMeta.mMsgId << std::endl; + std::cerr << "GxsForumsFillThread::run() Adding TopLevel Thread: mId: " << msg.mMsgId << std::endl; #endif ForumModelPostEntry entry; @@ -1029,7 +1029,7 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou ForumModelIndex entry_index = addEntry(posts,entry,0); //if (!mFlatView) - threadStack.push_back(std::make_pair(msg.mMeta.mMsgId,entry_index)) ; + threadStack.push_back(std::make_pair(msg.mMsgId,entry_index)) ; //calculateExpand(msg, item); //mItems.append(entry_index); @@ -1037,11 +1037,11 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou else { #ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::run() Storing kid " << msgIt->first << " of message " << msgIt->second.mMeta.mParentId << std::endl; + std::cerr << "GxsForumsFillThread::run() Storing kid " << msgIt->first << " of message " << msgIt->second.mParentId << std::endl; #endif // The same missing parent may appear multiple times, so we first store them into a unique container. - RsGxsMessageId parent_msg = msgIt->second.mMeta.mParentId; + RsGxsMessageId parent_msg = msgIt->second.mParentId; if(msgs.find(parent_msg) == msgs.end()) { @@ -1101,7 +1101,7 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou // We iterate through the top level thread items, and look for which message has the current item as parent. // When found, the item is put in the thread list itself, as a potential new parent. - std::map::iterator mit = msgs.find(*it2) ; + auto mit = msgs.find(*it2) ; if(mit == msgs.end()) { @@ -1109,9 +1109,9 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou continue ; } - const RsGxsForumMsg& msg(mit->second) ; + const RsMsgMetaData& msg(mit->second) ; #ifdef DEBUG_FORUMS - std::cerr << "GxsForumsFillThread::run() adding sub_item " << msg.mMeta.mMsgId << std::endl; + std::cerr << "GxsForumsFillThread::run() adding sub_item " << msg.mMsgId << std::endl; #endif @@ -1122,7 +1122,7 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou //calculateExpand(msg, item); /* add item to process list */ - threadStack.push_back(std::make_pair(msg.mMeta.mMsgId, e_index)); + threadStack.push_back(std::make_pair(msg.mMsgId, e_index)); msgs.erase(mit); } diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index 6a6b499b7..58953e263 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -186,9 +186,9 @@ private: static void generateMissingItem(const RsGxsMessageId &msgId,ForumModelPostEntry& entry); static ForumModelIndex addEntry(std::vector& posts,const ForumModelPostEntry& entry,ForumModelIndex parent); - static void convertMsgToPostEntry(const RsGxsForumGroup &mForumGroup, const RsGxsForumMsg& msg, bool useChildTS, ForumModelPostEntry& fentry); + static void convertMsgToPostEntry(const RsGxsForumGroup &mForumGroup, const RsMsgMetaData &msg, bool useChildTS, ForumModelPostEntry& fentry); - void computeMessagesHierarchy(const RsGxsForumGroup& forum_group, const std::vector& msgs_array, std::vector& posts, std::map > > &mPostVersions); + void computeMessagesHierarchy(const RsGxsForumGroup& forum_group, const std::vector &msgs_array, std::vector& posts, std::map > > &mPostVersions); void setPosts(const RsGxsForumGroup& group, const std::vector& posts,const std::map > >& post_versions); void initEmptyHierarchy(std::vector& posts); From 39b7bc818bde33ccba399bcc8ec95f8565a40e97 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 12 Dec 2018 21:31:54 +0100 Subject: [PATCH 76/79] added more debug info to figure out why some posts are not displayed --- .../src/gui/gxsforums/GxsForumThreadWidget.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index ac4adbe2e..fb7b3d1be 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -1953,10 +1953,17 @@ void GxsForumThreadWidget::updateMessageData(const RsGxsMessageId& msgId) return; } - if(msgs.size() != 1) + if(msgs.empty()) { - std::cerr << __PRETTY_FUNCTION__ << " obtained more than one msg info for msgId " << msgId << std::endl; - return; + std::cerr << __PRETTY_FUNCTION__ << " no posts for msgId " << msgId << ". Database corruption?" << std::endl; + return; + } + if(msgs.size() > 1) + { + std::cerr << __PRETTY_FUNCTION__ << " obtained more than one msg info for msgId " << msgId << ". This could be a bug. Only showing the first msg in the list." << std::endl; + std::cerr << "Messages are:" << std::endl; + for(auto it(msgs.begin());it!=msgs.end();++it) + std::cerr << (*it).mMeta << std::endl; } // 2 - sort the messages into a proper hierarchy @@ -1978,11 +1985,8 @@ void GxsForumThreadWidget::updateMessageData(const RsGxsMessageId& msgId) delete msg; ui->threadTreeWidget->setColumnHidden(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, !IS_GROUP_PGP_KNOWN_AUTHED(mForumGroup.mMeta.mSignFlags) && !(IS_GROUP_PGP_AUTHED(mForumGroup.mMeta.mSignFlags))); ui->subscribeToolButton->setHidden(IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags)) ; - }, this ); - }); - } void GxsForumThreadWidget::showAuthorInPeople(const RsGxsForumMsg& msg) From 348f88b6ec5e13a6543dc6637a4b468170afa032 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 13 Dec 2018 21:02:32 +0100 Subject: [PATCH 77/79] partially fixed async navigate action in forums --- .../src/gui/gxsforums/GxsForumThreadWidget.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index fb7b3d1be..06e8e4d9d 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -1494,7 +1494,10 @@ bool GxsForumThreadWidget::navigate(const RsGxsMessageId &msgId) QModelIndex source_index = mThreadModel->getIndexOfMessage(msgId); if(!source_index.isValid()) - return false; + { + mNavigatePendingMsgId = msgId; // not found. That means the forum may not be loaded yet. So we keep that post in mind, for after loading. + return true; // we have to return true here, otherwise the caller will intepret the async loading as an error. + } QModelIndex indx = mThreadProxyModel->mapFromSource(source_index); @@ -1847,6 +1850,12 @@ void GxsForumThreadWidget::postForumLoading() #ifdef DEBUG_FORUMS std::cerr << "Post forum loading..." << std::endl; #endif + if(!mNavigatePendingMsgId.isNull() && mThreadModel->getIndexOfMessage(mNavigatePendingMsgId).isValid()) + { + mThreadId = mNavigatePendingMsgId; + mNavigatePendingMsgId.clear(); + } + QModelIndex source_index = mThreadModel->getIndexOfMessage(mThreadId); if(!mThreadId.isNull() && source_index.isValid()) From 117c19b104936c1e18e32a4380bad999cef3cf50 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 14 Dec 2018 22:09:02 +0100 Subject: [PATCH 78/79] fixed a few problems in jumping to next unread post --- .../src/gui/gxsforums/GxsForumModel.cpp | 5 ++++ .../src/gui/gxsforums/GxsForumModel.h | 2 ++ .../gui/gxsforums/GxsForumThreadWidget.cpp | 27 ++++++++++--------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index d3713a1da..35edee9ff 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -664,6 +664,11 @@ QVariant RsGxsForumModel::decorationRole(const ForumModelPostEntry& fmpe,int col return QVariant(); } +const RsGxsGroupId& RsGxsForumModel::currentGroupId() const +{ + return mForumGroup.mMeta.mGroupId; +} + void RsGxsForumModel::updateForum(const RsGxsGroupId& forum_group_id) { if(forum_group_id.isNull()) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h index 58953e263..85714ffa2 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.h @@ -106,6 +106,8 @@ public: // This method will asynchroneously update the data void updateForum(const RsGxsGroupId& forumGroup); + const RsGxsGroupId& currentGroupId() const; + void setTreeMode(TreeMode mode) ; void setSortMode(SortMode mode) ; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 06e8e4d9d..f2627ca54 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -532,9 +532,7 @@ void GxsForumThreadWidget::groupIdChanged() mNewCount = 0; mUnreadCount = 0; - mThreadId.clear(); - //mThreadModel->updateForum(groupId()); updateDisplay(true); } @@ -718,7 +716,9 @@ void GxsForumThreadWidget::updateDisplay(bool complete) { saveExpandedItems(mSavedExpandedMessages); - //mUpdating=true; + if(groupId() != mThreadModel->currentGroupId()) + mThreadId.clear(); + updateGroupData(); mThreadModel->updateForum(groupId()); @@ -975,11 +975,7 @@ void GxsForumThreadWidget::changedThread(QModelIndex index) // return; if(!index.isValid()) - { - mThreadId.clear(); - mOrigThreadId.clear(); return; - } RsGxsMessageId new_id(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_MSGID).data(Qt::UserRole).toString().toStdString()); @@ -1427,19 +1423,24 @@ void GxsForumThreadWidget::nextUnreadMessage() if(!index.isValid()) index = mThreadProxyModel->index(0,0); + else + { + if(index.data(RsGxsForumModel::UnreadChildrenRole).toBool()) + ui->threadTreeWidget->expand(index); - do + index = ui->threadTreeWidget->indexBelow(index); + } + + while(index.isValid() && !IS_MSG_UNREAD(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_DATA).data(RsGxsForumModel::StatusRole).toUInt())) { if(index.data(RsGxsForumModel::UnreadChildrenRole).toBool()) ui->threadTreeWidget->expand(index); index = ui->threadTreeWidget->indexBelow(index); } - while(index.isValid() && !IS_MSG_UNREAD(index.sibling(index.row(),RsGxsForumModel::COLUMN_THREAD_DATA).data(RsGxsForumModel::StatusRole).toUInt())); ui->threadTreeWidget->setCurrentIndex(index); - ui->threadTreeWidget->scrollTo(index,QAbstractItemView::PositionAtCenter); - //ui->threadTreeWidget->setFocus(); + ui->threadTreeWidget->scrollTo(index); changedThread(index); } @@ -1502,7 +1503,7 @@ bool GxsForumThreadWidget::navigate(const RsGxsMessageId &msgId) QModelIndex indx = mThreadProxyModel->mapFromSource(source_index); ui->threadTreeWidget->setCurrentIndex(indx); - ui->threadTreeWidget->scrollTo(indx,QAbstractItemView::PositionAtCenter); + ui->threadTreeWidget->scrollTo(indx); ui->threadTreeWidget->setFocus(); changedThread(indx); return true; @@ -1862,7 +1863,7 @@ void GxsForumThreadWidget::postForumLoading() { QModelIndex index = mThreadProxyModel->mapFromSource(source_index); ui->threadTreeWidget->selectionModel()->setCurrentIndex(index,QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); - ui->threadTreeWidget->scrollTo(index,QAbstractItemView::PositionAtCenter); + ui->threadTreeWidget->scrollTo(index); #ifdef DEBUG_FORUMS std::cerr << " re-selecting index of message " << mThreadId << " to " << source_index.row() << "," << source_index.column() << " " << (void*)source_index.internalPointer() << std::endl; #endif From 60112e8387957130e816649de9e0feaa5d30a81f Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 14 Dec 2018 22:14:59 +0100 Subject: [PATCH 79/79] added two missing virtual desctructors in GXS interface structures --- libretroshare/src/retroshare/rsgxsforums.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libretroshare/src/retroshare/rsgxsforums.h b/libretroshare/src/retroshare/rsgxsforums.h index c56074e69..6b8fc0457 100644 --- a/libretroshare/src/retroshare/rsgxsforums.h +++ b/libretroshare/src/retroshare/rsgxsforums.h @@ -54,6 +54,8 @@ static const uint32_t RS_GXS_FORUM_MSG_FLAGS_MODERATED = 0x00000001; struct RsGxsForumGroup : RsSerializable { + virtual ~RsGxsForumGroup() {} + RsGroupMetaData mMeta; std::string mDescription; @@ -76,6 +78,8 @@ struct RsGxsForumGroup : RsSerializable struct RsGxsForumMsg : RsSerializable { + virtual ~RsGxsForumMsg() {} + RsMsgMetaData mMeta; std::string mMsg;