aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-28 11:49:32 +0200
committerDanilo M. <danix@danix.xyz>2026-08-28 11:49:32 +0200
commit26699b720c4135b57de6cfc84b35ab632de1c500 (patch)
treec7f4831fdf4b2b8d5960d34681eec688574c824d /src
parent5f31a037a37a928a8e21fdf0950568a689e29fb8 (diff)
downloadqtmaildir-26699b720c4135b57de6cfc84b35ab632de1c500.tar.gz
qtmaildir-26699b720c4135b57de6cfc84b35ab632de1c500.zip
feat: resolve a selection's scope from what each row is
One resolver replacing the scopeFor/messageScopeFor pair. The caller no longer chooses the scope, which is what let one gesture mean two things.
Diffstat (limited to 'src')
-rw-r--r--src/threadlistmodel.cpp37
-rw-r--r--src/threadlistmodel.h8
2 files changed, 45 insertions, 0 deletions
diff --git a/src/threadlistmodel.cpp b/src/threadlistmodel.cpp
index 4a75d47..ddddf0b 100644
--- a/src/threadlistmodel.cpp
+++ b/src/threadlistmodel.cpp
@@ -1117,6 +1117,43 @@ ActionScope ThreadListModel::scopeFor(const QModelIndexList &selection) const
return scope;
}
+ActionScope ThreadListModel::scopeForSelection(
+ const QModelIndexList &selection) const
+{
+ ActionScope scope;
+
+ for (const QModelIndex &index : selection) {
+ if (isConversationRow(index)) {
+ const ThreadSummary &summary = m_threads.at(index.row()).summary;
+ if (scope.threadIds.contains(summary.threadId))
+ continue;
+ scope.threadIds.append(summary.threadId);
+ // totalCount, not the loaded children: an unexpanded conversation
+ // still has all of its messages, and the count is what the status
+ // bar names after the fact.
+ scope.messageCount += summary.totalCount;
+ scope.wholeThread = true;
+ continue;
+ }
+
+ const QString messageId =
+ isMessageRow(index)
+ ? messageAt(index).messageId
+ : (index.row() >= 0 && index.row() < m_threads.size()
+ ? m_threads.at(index.row()).summary.firstMessageId
+ : QString());
+
+ // Skipped rather than widened. Falling back to the thread would
+ // silently act on messages the row does not stand for.
+ if (messageId.isEmpty() || scope.messageIds.contains(messageId))
+ continue;
+ scope.messageIds.append(messageId);
+ scope.messageCount += 1;
+ }
+
+ return scope;
+}
+
ThreadSummary ThreadListModel::threadAt(int row) const
{
if (row < 0 || row >= m_threads.size())
diff --git a/src/threadlistmodel.h b/src/threadlistmodel.h
index 5cd1392..fcbb8f5 100644
--- a/src/threadlistmodel.h
+++ b/src/threadlistmodel.h
@@ -361,6 +361,14 @@ public:
/// 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.
+ ActionScope scopeForSelection(const QModelIndexList &selection) const;
+
/// The account keys behind a thread's account tags, for item 49's
/// per-account sync.
///