aboutsummaryrefslogtreecommitdiffstats
path: root/src/threadlistmodel.h
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-28 17:56:25 +0200
committerDanilo M. <danix@danix.xyz>2026-08-28 17:56:25 +0200
commita346bef6c08e9725f3ab41f8237f01e9eb69eea7 (patch)
treeca3ea16c23da8971d6b9f8f7d4867845e5c25e0c /src/threadlistmodel.h
parentf934029d3333396bde6ec306ab300641929c7cdc (diff)
downloadqtmaildir-a346bef6c08e9725f3ab41f8237f01e9eb69eea7.tar.gz
qtmaildir-a346bef6c08e9725f3ab41f8237f01e9eb69eea7.zip
feat: judge a row's membership on the thread's union
Closes item 170 under item 177. A conversation belongs to a view while any of its messages match, so reading one message of a thread no longer takes the conversation out of the Unread view. The current row is never evicted, and an automatic write defers its eviction until the selection moves.
Diffstat (limited to 'src/threadlistmodel.h')
-rw-r--r--src/threadlistmodel.h27
1 files changed, 27 insertions, 0 deletions
diff --git a/src/threadlistmodel.h b/src/threadlistmodel.h
index a528c7e..93474ac 100644
--- a/src/threadlistmodel.h
+++ b/src/threadlistmodel.h
@@ -236,6 +236,21 @@ public:
/// CURRENT VIEW requires, so a caller passes what the query filters on and
/// nothing else.
void removeThreadsWithoutTag(const QString &tag);
+
+ /// Drops only the NAMED threads, and only those whose UNION no longer
+ /// carries \p tag.
+ ///
+ /// Two differences from the sweeping form, both deliberate. It judges the
+ /// named rows alone, because the sweeping form is right after a move (the
+ /// query itself is what changed) and wrong after a tag write: a list can
+ /// legitimately hold rows that never matched, and one write must not evict
+ /// rows it did not touch. And it judges `summary.tags`, which is notmuch's
+ /// union over the conversation, never the displayed message's own tags: a
+ /// thread belongs to a view while ANY of its messages match it (item 177),
+ /// so reading one message of a 44-message thread leaves the conversation
+ /// in the Unread view and reading the last one takes it out.
+ void removeThreadsWithoutTag(const QStringList &threadIds,
+ const QString &tag);
bool flatMode() const { return m_flatMode; }
QModelIndex index(int row, int column,
@@ -326,6 +341,18 @@ public:
/// message the user could select is always findable here.
QString threadIdForMessage(const QString &messageId) const;
+ /// Whether a row for this thread is still in the list.
+ bool hasThread(const QString &threadId) const;
+
+ /// How many messages the thread holds, from its summary, or 0 when the
+ /// list has no row for it.
+ ///
+ /// The question a message-scoped write asks before judging membership: a
+ /// thread of one has a union that IS its message, so the write moved it
+ /// and the row can be judged, while a longer thread's union is untouched
+ /// and judging it would be judging a stale answer.
+ int threadCountFor(const QString &threadId) const;
+
/// A loaded message row's node, found by id rather than by position.
///
/// For callers that know WHICH message they mean and must not depend on it