diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/notmuchworker.cpp | 82 | ||||
| -rw-r--r-- | src/notmuchworker.h | 22 |
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 |
