aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/notmuchworker.cpp82
-rw-r--r--src/notmuchworker.h22
2 files changed, 104 insertions, 0 deletions
diff --git a/src/notmuchworker.cpp b/src/notmuchworker.cpp
index e78d8c8..1f28973 100644
--- a/src/notmuchworker.cpp
+++ b/src/notmuchworker.cpp
@@ -1232,6 +1232,88 @@ void NotmuchWorker::resolveThreadMessages(const QStringList &threadIds,
resolveQuery(terms.join(QStringLiteral(" or ")), requestTag);
}
+void NotmuchWorker::resolvePendingSubjects(const QStringList &ids,
+ const QList<bool> &areThreads)
+{
+ if (ids.isEmpty() || ids.size() != areThreads.size())
+ return;
+
+ QStringList subjects;
+ QList<int> counts;
+ subjects.reserve(ids.size());
+ counts.reserve(ids.size());
+
+ if (!openReadOnly()) {
+ // Answer anyway, one empty subject per row. The dialog must be able to
+ // show the user their pending changes even when the index cannot be
+ // opened: the ids and the actions are known without it, and only the
+ // subjects are missing.
+ for (int i = 0; i < ids.size(); ++i) {
+ subjects.append(QString());
+ counts.append(-1);
+ }
+ emit pendingSubjectsResolved(subjects, counts);
+ return;
+ }
+
+ // One lookup per id rather than one combined query, deliberately. The
+ // answer is POSITIONAL, and a combined query returns a set: it would lose
+ // both the order and the duplicates, and a message with two outstanding
+ // actions is exactly two rows carrying one id.
+ //
+ // The cost is bounded by what the user can have pending, which is what
+ // they did by hand since the last sync. This is not a query-sized walk.
+ for (int i = 0; i < ids.size(); ++i) {
+ QString subject;
+ int count = -1;
+
+ if (areThreads.at(i)) {
+ NmQuery query(notmuch_query_create(
+ m_db,
+ QStringLiteral("thread:%1").arg(ids.at(i)).toUtf8().constData()));
+ notmuch_threads_t *raw = nullptr;
+ if (query
+ && notmuch_query_search_threads(query.get(), &raw)
+ == NOTMUCH_STATUS_SUCCESS) {
+ NmThreads threads(raw);
+ if (notmuch_threads_valid(threads.get())) {
+ NmThread thread(notmuch_threads_get(threads.get()));
+ if (thread) {
+ subject = QString::fromUtf8(
+ notmuch_thread_get_subject(thread.get()));
+ // At snapshot time, which is what the row reports. A
+ // held thread edit applies when the sync ends, and a
+ // reply landing in between makes the real number
+ // larger; the number describes what the user is
+ // looking at, not what the write will touch.
+ count = notmuch_thread_get_total_messages(thread.get());
+ }
+ }
+ }
+ } else {
+ notmuch_message_t *raw = nullptr;
+ // find_message reports SUCCESS with a null message for an id that
+ // is not there, so both have to be checked. A missing id is not an
+ // error here: it is the stale row the dialog exists to show.
+ if (notmuch_database_find_message(
+ m_db, ids.at(i).toUtf8().constData(), &raw)
+ == NOTMUCH_STATUS_SUCCESS
+ && raw) {
+ NmMessage message(raw);
+ const char *header =
+ notmuch_message_get_header(message.get(), "Subject");
+ if (header)
+ subject = QString::fromUtf8(header);
+ }
+ }
+
+ subjects.append(subject);
+ counts.append(count);
+ }
+
+ emit pendingSubjectsResolved(subjects, counts);
+}
+
void NotmuchWorker::resolveQuery(const QString &query,
const QString &requestTag)
{
diff --git a/src/notmuchworker.h b/src/notmuchworker.h
index 77b14ec..8171f3c 100644
--- a/src/notmuchworker.h
+++ b/src/notmuchworker.h
@@ -213,6 +213,22 @@ public slots:
/// whatever the current view happens to be showing.
void resolveQueryMessages(const QString &query, const QString &requestTag);
+ /// Subjects for the list behind the unsynced-changes count (item 119).
+ ///
+ /// Takes the snapshot's ids in order, each flagged as a thread id or a
+ /// message id, and answers POSITIONALLY: one subject per input, plus a
+ /// message count for a thread id and -1 for a message id. Positional
+ /// because the caller has already decided what its rows are and in what
+ /// order; a set-based answer would make it match them back up by id, and
+ /// one id can legitimately appear on several rows.
+ ///
+ /// An id the index no longer holds yields an EMPTY subject rather than
+ /// being dropped. The dialog still shows that row: the count the user
+ /// clicked has to equal the list they are shown, and silently dropping a
+ /// row would break that for the one case where it matters most.
+ void resolvePendingSubjects(const QStringList &ids,
+ const QList<bool> &areThreads);
+
private:
/// The shared walk behind resolveMessages() and resolveThreadMessages():
/// runs `query` and emits threadMessagesResolved() with each match's id,
@@ -340,6 +356,12 @@ signals:
const QStringList &paths,
const QStringList &tags,
const QString &requestTag);
+ /// One subject per requested id, in the SAME ORDER, and one count beside
+ /// it: the thread's message total, or -1 for a message id. An empty
+ /// subject means the index no longer holds that id.
+ void pendingSubjectsResolved(const QStringList &subjects,
+ const QList<int> &messageCounts);
+
void allTagsReady(const QStringList &tags, quint64 generation);
/// One entry per requested query, in the order they were asked for. A query