From 596c9a4842bf0a21defc0473205e75b52339893d Mon Sep 17 00:00:00 2001 From: jolavillette Date: Tue, 1 Sep 2026 06:29:01 +0200 Subject: [PATCH] GxsForumModel: repaint the ancestors of a read post in flat view too setMsgReadStatus() refreshes the changed post and then its ancestors, whose bold state (FLAG_POST_HAS_UNREAD_CHILDREN) depends on it. That walk used QModelIndex::parent(), which returns an invalid index in flat view by design, so nothing was refreshed there: a parent post stayed bold after its last unread reply had been read, until an unrelated repaint (hover, scroll, forum reload) caught up with the model. The has-unread-children flag is computed on the real hierarchy in both view modes, so both need the ancestors' rows refreshed. Walk the parent chain through the post table instead and build each ancestor's index with the mode's row convention, as getIndexOfMessage() already does. History: the ancestor refresh was a whole-model dataChanged() until 319ebd66f (2020), then a parent() loop since 056ab8da5, briefly a whole refresh again in f4463dd17 and back to the parent() loop in 2816dfd9f. Flat view has been left out since 2020 except for those three days. Co-Authored-By: Claude Fable 5 --- .../src/gui/gxsforums/GxsForumModel.cpp | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index 5dfe21bba..5e0f996ab 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -923,11 +923,31 @@ void RsGxsForumModel::setMsgReadStatus(const QModelIndex& i,bool read_status,boo } else { - // Emit dataChanged only for the changed message and its parents + // Emit dataChanged for the changed post and for every one of its + // ancestors: their bold state (FLAG_POST_HAS_UNREAD_CHILDREN) may have + // changed too. + // + // The ancestors are walked through the post table, not through + // QModelIndex::parent(). In flat view parent() deliberately returns an + // invalid index -- the view shows no hierarchy -- so a loop on i.parent() + // silently repaints nothing there, and a parent post stayed bold after + // its last unread reply had been read until some unrelated repaint. The + // has-unread-children flag is computed on the real hierarchy in both view + // modes, so the ancestors' rows must be refreshed in both modes as well. emit dataChanged(i, i.sibling(i.row(), COLUMN_THREAD_NB_COLUMNS - 1)); - for(QModelIndex j = i.parent(); j.isValid(); j = j.parent()) + + size_t guard = 0; // the parent chain always ends at the root sentinel; never trust it blindly + for(ForumModelIndex p = mPosts[entry].mParent; p != 0 && p < mPosts.size() && guard < mPosts.size(); p = mPosts[p].mParent, ++guard) { - emit dataChanged(j, j.sibling(j.row(), COLUMN_THREAD_NB_COLUMNS - 1)); + void *pref = nullptr; + convertTabEntryToRefPointer(p, pref); + + // Same row convention as getIndexOfMessage(): table slot minus one in + // flat view, position among the parent's children in tree view. + QModelIndex pi = (mTreeMode == TREE_MODE_FLAT) ? createIndex(p - 1, 0, pref) + : createIndex(mPosts[p].prow, 0, pref); + + emit dataChanged(pi, pi.sibling(pi.row(), COLUMN_THREAD_NB_COLUMNS - 1)); } } }