aboutsummaryrefslogtreecommitdiffstats
path: root/src/threadlistmodel.h
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-28 12:33:52 +0200
committerDanilo M. <danix@danix.xyz>2026-08-28 12:33:52 +0200
commit978c9b51935f8597ce307166bfba29368bd4fc23 (patch)
treed07ee82615113e31f788c731ffdfffa626e7ec21 /src/threadlistmodel.h
parentcc551a4ed348e663601f2fb8e06b59c07a09ead4 (diff)
downloadqtmaildir-978c9b51935f8597ce307166bfba29368bd4fc23.tar.gz
qtmaildir-978c9b51935f8597ce307166bfba29368bd4fc23.zip
feat: scope an action to the row it was invoked on
The five *_thread actions and their submenu are gone: the row's identity is what decides the scope, so a second set of actions was a second answer to a settled question. mark_thread_unread went with them, being the sixth entry in the same submenu. tagSelected() loses its TagScope parameter, and everySelectedRowHasTag() its own, so the direction and the write ask the same question of the same object. ThreadListModel::scopeFor() and messageScopeFor() are deleted; scopeForSelection() is the one resolver. Labels name the scope. Archive, Delete, Restore, Spam, Important and the unread toggle all say "thread" on a conversation row, and Delete, Restore and Archive are ABSENT on a reply: a single reply cannot be removed from a conversation. Compose follows the same rule. Forward, Save, Reply-all and Reply without quoting disappear on a conversation row, which shows no message to act on, and Reply becomes "Reply to this thread": reply-all, quoting nothing, threaded off the conversation's NEWEST message so the answer lands at its end rather than forking the discussion at its opening post. That id is not in the model, since an unexpanded conversation holds no nodes for its replies, so it comes from resolveThreadMessages(); resolveQuery() states its newest-first sort rather than inheriting notmuch's default. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012iDeN6C7y97nHYPvP6ST4L
Diffstat (limited to 'src/threadlistmodel.h')
-rw-r--r--src/threadlistmodel.h37
1 files changed, 5 insertions, 32 deletions
diff --git a/src/threadlistmodel.h b/src/threadlistmodel.h
index fcbb8f5..a528c7e 100644
--- a/src/threadlistmodel.h
+++ b/src/threadlistmodel.h
@@ -333,40 +333,13 @@ public:
/// expanded thread holds it.
MessageNode messageById(const QString &messageId) const;
- /// Resolves a selection into whole THREADS, for the thread-scoped actions.
- ///
- /// A thread row contributes its thread; a message row still contributes
- /// only itself, since a reply's own row cannot be widened into its
- /// conversation without escalating silently. Mixed selections are honoured
- /// as given: a thread root and an unrelated reply act on that whole thread
- /// and that one message.
- ///
- /// **Not the default any more.** Since item 108 the ordinary actions use
- /// messageScopeFor(); this is what the explicit "whole thread" submenu
- /// resolves through.
- ActionScope scopeFor(const QModelIndexList &selection) const;
-
- /// Resolves a selection into individual MESSAGES, which is what the
- /// ordinary tag actions act on since item 108.
- ///
- /// A thread row contributes the ONE message its card displays, not its
- /// whole conversation. That is `ThreadSummary::firstMessageId`, carried
- /// from the query, so this needs no expansion and no worker round trip.
- /// In the Sent view that field is the first MATCHED message rather than
- /// the thread's opening one, which is right here for the same reason it is
- /// right on the card: both answer "the message this row shows".
- ///
- /// A thread row whose `firstMessageId` is empty contributes nothing. That
- /// is a row the model cannot name a message for, and acting on the whole
- /// thread instead would be the silent escalation this exists to remove.
- ActionScope messageScopeFor(const QModelIndexList &selection) const;
-
/// What a selection means, resolved per row from what that row IS.
///
- /// Replaces the scopeFor()/messageScopeFor() pair, which made the caller
- /// choose the scope and so let one gesture mean two things (item 177). A
- /// conversation row contributes its thread, any other row its message, and
- /// a mixed selection carries both.
+ /// The one answer to the question, and the only one (item 177). It
+ /// replaced a scopeFor()/messageScopeFor() pair that made the CALLER
+ /// choose, which let one gesture mean two things and needed a second set
+ /// of actions to disambiguate. A conversation row contributes its thread,
+ /// any other row its message, and a mixed selection carries both.
ActionScope scopeForSelection(const QModelIndexList &selection) const;
/// The account keys behind a thread's account tags, for item 49's