/******************************************************************************* * retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h * * * * Copyright 2020 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 "retroshare/rsposted.h" #include "retroshare/rsgxsifacetypes.h" #include "retroshare/rsevents.h" #include #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 // safely access the data. // The model contains a post in place 0 that is the parent of all posts. // The model contains 3 layers: // // Layer 1: list of all posts // // * this list is sorted according to the current sorting strategy // * Variables: mPosts // // Layer 2: list of post filtered by search // // * depending on which chunk of posts are actually displayed, this list contains // the subset of the general list of posts // * Variables: mFilteredPosts // // Layer 3: start and end of posts actually displayed in the previous list // // * Variables: mDisplayedStartIndex, mDisplayedNbPosts // // The array below indicates which variables are updated depending on the type of data/view change: // // | Global list (mPosts) | Filtered List | Displayed list (mDisplayedStartIndex, mDisplayedNbPosts) // -----------+-----------------------+------------------+---------------------------------------------------------- // New group | X | X | X (updated because FilteredList may change) // Sort order | X | | // Filter Str | | X | X (updated because FilteredList may change) // Chunk chng | | X | X // // In the model, indexes internal refs are pointer casts of the index in the mFilteredPosts tab. Another possible choice // was to use indexes in the tab of displayed indices, but this leads to a more complex impleemntation. typedef uint32_t PostedPostsModelIndex; // struct ChannelPostsModelPostEntry // { // ChannelPostsModelPostEntry() : mPublishTs(0),mPostFlags(0),mMsgStatus(0),prow(0) {} // // 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, // FLAG_POST_PASSES_FILTER = 0x0020, // FLAG_POST_CHILDREN_PASSES_FILTER = 0x0040, // }; // // std::string mTitle ; // RsGxsMessageId mMsgId; // uint32_t mPublishTs; // uint32_t mPostFlags; // int mMsgStatus; // // int prow ;// parent row, which basically means position in the array of posts // }; // This class is the item model used by Qt to display the information class RsPostedPostsModel : public QAbstractItemModel { Q_OBJECT public: explicit RsPostedPostsModel(QObject *parent = NULL); virtual ~RsPostedPostsModel() override; static const uint32_t COLUMN_THREAD_NB_COLUMNS = 0x01; static const uint32_t DEFAULT_DISPLAYED_NB_POSTS ; enum SortingStrategy { SORT_UNKNOWN = 0x00, SORT_NEW_SCORE = 0x01, SORT_TOP_SCORE = 0x02, SORT_HOT_SCORE = 0x03 }; enum Columns { COLUMN_POSTS =0x00, COLUMN_THREAD_MSGID =0x01, COLUMN_THREAD_DATA =0x02, }; enum Roles{ SortRole = Qt::UserRole+1, StatusRole = Qt::UserRole+2, FilterRole = Qt::UserRole+3, }; enum TreeMode{ TREE_MODE_UNKWN = 0x00, TREE_MODE_PLAIN = 0x01, TREE_MODE_FILES = 0x02, }; #ifdef TODO enum SortMode{ SORT_MODE_PUBLISH_TS = 0x00, SORT_MODE_CHILDREN_PUBLISH_TS = 0x01, }; #endif QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const; // This method will asynchroneously update the data void updateBoard(const RsGxsGroupId& posted_group_id); const RsGxsGroupId& currentGroupId() const; // Triggers a data change for all items. This can be used to redraw the view without re-loading the data. void update(); // Triggers a preMod, begin/end remove rows and data update. Could be useful if update is not enough to reset cell sizes. void deepUpdate(); // same without data update, which is far less costly void triggerRedraw(); #ifdef TODO void setSortMode(SortMode mode) ; 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;} #endif void setAllMsgReadStatus(bool read); void setMsgReadStatus(const QModelIndex &i, bool read_status); void setFilter(const QStringList &strings, uint32_t &count) ; void setSortingStrategy(SortingStrategy s); void setPostsInterval(int start,int nb_posts); #ifdef TODO void setAuthorOpinion(const QModelIndex& indx,RsOpinion op); #endif // Helper functions bool getPostData(const QModelIndex& i,RsPostedPost& fmpe) const ; uint32_t totalPostsCount() const { return mPosts.size() ; } uint32_t filteredPostsCount() const { return mFilteredPosts.size() ; } uint32_t displayedStartPostIndex() const { return mDisplayedStartIndex ; } void clear() ; // AbstractItemModel functions. 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 override; QModelIndex parent(const QModelIndex& child) const override; Qt::ItemFlags flags(const QModelIndex& index) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; // Custom item roles QVariant sizeHintRole (int col) const; QVariant displayRole (const RsPostedPost& fmpe, int col) const; QVariant toolTipRole (const RsPostedPost& fmpe, int col) const; QVariant userRole (const RsPostedPost& fmpe, int col) const; #ifdef TODO QVariant decorationRole(const RsPostedPost& fmpe, int col) const; QVariant pinnedRole (const RsPostedPost& fmpe, int col) const; QVariant missingRole (const RsPostedPost& fmpe, int col) const; QVariant statusRole (const RsPostedPost& fmpe, int col) const; QVariant authorRole (const RsPostedPost& fmpe, int col) const; QVariant sortRole (const RsPostedPost& fmpe, int col) const; QVariant fontRole (const RsPostedPost& fmpe, int col) const; QVariant filterRole (const RsPostedPost& fmpe, int col) const; QVariant textColorRole (const RsPostedPost& fmpe, int col) const; QVariant backgroundRole(const RsPostedPost& fmpe, int col) const; #endif /*! * \brief debug_dump * Dumps the hierarchy of posts in the terminal, to allow checking whether the internal representation is correct. */ void debug_dump(); signals: void boardPostsLoaded(); // emitted after the posts have been loaded. private: RsPostedGroup mPostedGroup; TreeMode mTreeMode; void preMods() ; void postMods() ; quintptr getParentRow(quintptr ref,int& row) const; quintptr getChildRef(quintptr ref, int index) const; int getChildrenCount(quintptr ref) const; static bool convertTabEntryToRefPointer(uint32_t entry, quintptr &ref); static bool convertRefPointerToTabEntry(quintptr ref,uint32_t& entry); static void computeReputationLevel(uint32_t forum_sign_flags, RsPostedPost& entry); void update_posts(const RsGxsGroupId& group_id); #ifdef TODO void setForumMessageSummary(const std::vector& messages); void recursUpdateReadStatusAndTimes(ChannelPostsModelIndex i,bool& has_unread_below,bool& has_read_below); uint32_t recursUpdateFilterStatus(ChannelPostsModelIndex i,int column,const QStringList& strings); void recursSetMsgReadStatus(ChannelPostsModelIndex i,bool read_status,bool with_children); #endif void createPostsArray(std::vector &posts); void setPosts(const RsPostedGroup& group, std::vector &posts); void initEmptyHierarchy(); void handleEvent_main_thread(std::shared_ptr event); std::vector mPosts ; std::vector mFilteredPosts; uint32_t mDisplayedStartIndex; uint32_t mDisplayedNbPosts; SortingStrategy mSortingStrategy; RsEventsHandlerId_t mEventHandlerId ; };