diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-07 18:29:58 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-07 18:29:58 +0200 |
| commit | fbc65d2413190faa873d6b0b5cb9ed31ebba453b (patch) | |
| tree | 3a85bbd06e153bac58e6d0fbed6364a50458b0d7 /src/mainwindow.h | |
| parent | 48c243d7aee3382713f7a4653be2179d313b432c (diff) | |
| download | qtmaildir-fbc65d2413190faa873d6b0b5cb9ed31ebba453b.tar.gz qtmaildir-fbc65d2413190faa873d6b0b5cb9ed31ebba453b.zip | |
feat(ui): add a Maildir overview under Help
Nothing in the UI reported database-level facts: every query gave a
thread count for that query, and nothing said how much mail there is
overall. A dialog under Help now shows messages, threads and tags from
notmuch, plus the account list from config, since notmuch does not model
accounts at all.
A separate worker call rather than a reuse of requestCounts, which counts
threads to match the row count of a query. This counts messages, which is
what a user means by "how much mail is in here". The test pins 4 messages
in 3 threads against the fixture and fails if they are ever made equal,
so routing both through one count cannot pass unnoticed.
Every field starts at -1 and renders as "unknown" when notmuch could not
answer it. Printing 0 would say the Maildir is empty, and telling someone
their mail is gone is the worst way to report an index that failed to
open.
The dialog opens showing "Counting..." rather than blocking, since
counting every message is not free on a large database. That makes two
lifetimes matter: the reply can arrive after the dialog is closed, so the
label is a QPointer, and the dialog can be closed and reopened while a
count runs, so a generation counter drops the older answer. The test
drains DeferredDelete before firing the late reply, because close()
deletes through deleteLater and without that the dangling case is never
actually reached.
Diffstat (limited to 'src/mainwindow.h')
| -rw-r--r-- | src/mainwindow.h | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/src/mainwindow.h b/src/mainwindow.h index 8043727..579597c 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -20,6 +20,7 @@ #include <QHash> #include <QMainWindow> +#include <QPointer> #include <QThread> #include <QUndoCommand> #include <QUndoStack> @@ -133,6 +134,13 @@ public: /// stale, so a test standing in for the worker has to know the current one. quint64 currentGenerationForTesting() const { return m_generation; } + /// The generation a database-stats reply must carry to be accepted. + /// + /// A test seam, for the same reason as the one above: onDatabaseStatsReady + /// discards a reply belonging to a dialog that has since been closed and + /// reopened, so a test standing in for the worker needs the current value. + quint64 statsGenerationForTesting() const { return m_statsGeneration; } + protected: void closeEvent(QCloseEvent *event) override; @@ -189,6 +197,10 @@ private slots: /// requestPlaceholderCounts() asked for them. void onCountsReady(const QVector<int> &counts, quint64 generation); + /// Fills in the overview dialog's counts when the worker answers. Does + /// nothing if the dialog has since been closed. + void onDatabaseStatsReady(const DatabaseStats &stats, quint64 generation); + /// Runs a query the user clicked on the placeholder pane. void onPlaceholderQueryRequested(const QString &query); @@ -225,6 +237,16 @@ private: void showShortcutReference(); void showAbout(); + /// The Maildir overview (item 34): what notmuch knows about the database, + /// plus the account list, which comes from config since notmuch does not + /// model accounts at all. + /// + /// Opens immediately showing the counts as pending and fills them in when + /// the worker answers, rather than blocking: counting every message is not + /// free on a large database and a dialog that hangs first is worse than one + /// that populates. + void showMaildirOverview(); + /// Creates a QAction, binds it to the sequence KeyMap holds for `name`, /// and registers it. `name` is the action name used in [keys]. QAction *addAction(const QString &name, const QString &text, @@ -422,6 +444,17 @@ private: /// attention, so it must survive until the next successful run. bool m_lastSyncFailed = false; + /// The overview dialog's counts label while that dialog is open, null + /// otherwise. A QPointer because the dialog is deleted on close and the + /// worker's reply can arrive afterwards: a raw pointer would dangle for + /// exactly as long as the count takes on a large database, which is + /// precisely when the user is most likely to close it first. + QPointer<QLabel> m_overviewCounts; + + /// Discriminates a stats reply from a dialog that has since been closed + /// and reopened, so an old answer cannot fill in a newer dialog. + quint64 m_statsGeneration = 0; + /// Holds the sync log and its close button, so the pane can be dismissed. QWidget *m_syncLogPane = nullptr; QPlainTextEdit *m_syncLog = nullptr; |
