aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-14 18:01:28 +0200
committerDanilo M. <danix@danix.xyz>2026-08-14 18:01:28 +0200
commit78b3a9c1769d37ff7344360b6fed66b12b2f0649 (patch)
treeacc2f6f4c995f2c378e82a83f5800a9f3d6e6b48 /src
parentf7fa8bb6aefa5896fc7fdfb694f2a2752eb88ed5 (diff)
downloadqtmaildir-78b3a9c1769d37ff7344360b6fed66b12b2f0649.tar.gz
qtmaildir-78b3a9c1769d37ff7344360b6fed66b12b2f0649.zip
refactor(search): carry SearchMode instead of bool extend
Four signatures, no behaviour change: the two shipped operations map to Replace and Narrow. runSearchFromPane becomes a switch and gains the Exclude arm, which nothing can reach until the menu entry exists. Seven call sites across three test files moved with it, two more than the plan predicted: test_messageview and test_mainwindow also drive these signals directly. mainwindow.h and messagedetailsdialog.h now include searchterm.h for the type; messageview.h already did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src')
-rw-r--r--src/mainwindow.cpp23
-rw-r--r--src/mainwindow.h10
-rw-r--r--src/messagedetailsdialog.cpp15
-rw-r--r--src/messagedetailsdialog.h10
-rw-r--r--src/messageview.cpp14
-rw-r--r--src/messageview.h9
6 files changed, 56 insertions, 25 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 115646e..e82e61d 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -1651,13 +1651,30 @@ void MainWindow::onPlaceholderQueryRequested(const QString &query)
runCurrentQuery();
}
-void MainWindow::runSearchFromPane(const QString &query, bool extend)
+void MainWindow::runSearchFromPane(const QString &query,
+ SearchTerm::SearchMode mode)
{
if (query.isEmpty())
return;
- const QString next =
- extend ? SearchTerm::extend(m_queryEdit->text(), query) : query;
+ QString next;
+ switch (mode) {
+ case SearchTerm::SearchMode::Replace:
+ next = query;
+ break;
+ case SearchTerm::SearchMode::Narrow:
+ next = SearchTerm::extend(m_queryEdit->text(), query);
+ break;
+ case SearchTerm::SearchMode::Exclude:
+ next = SearchTerm::exclude(m_queryEdit->text(), query);
+ break;
+ }
+
+ // exclude() returns empty when there is nothing to exclude from, which the
+ // greyed menu entry should already have prevented. Running it would clear
+ // the query bar and show the whole Maildir, so refuse instead.
+ if (next.isEmpty())
+ return;
// Through the query bar and the existing runner, so the account scope, the
// generation counter and the flat-mode reset all behave exactly as they do
diff --git a/src/mainwindow.h b/src/mainwindow.h
index f54a889..b41f75d 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -34,6 +34,7 @@
// Included rather than forward-declared: SyncPhaseTracker is held by value, so
// its size must be known here. MailSync itself stays a forward declaration.
#include "mailsync.h"
+#include "searchterm.h"
// Complete type, not a forward declaration: showTagRulesDialog() defaults its
// seed to TagRule().
#include "tagrules.h"
@@ -375,10 +376,11 @@ private slots:
/// Runs a search asked for from the message pane.
///
- /// `extend` narrows the current query rather than replacing it. The panes
- /// carry a finished query and no knowledge of the bar; the combining
- /// happens here, because only the window can see what the bar holds.
- void runSearchFromPane(const QString &query, bool extend);
+ /// `mode` says whether to replace the query bar, narrow it, or narrow it
+ /// by everything that is not this value. The panes carry a finished query
+ /// and no knowledge of the bar; the combining happens here, because only
+ /// the window can see what the bar holds.
+ void runSearchFromPane(const QString &query, SearchTerm::SearchMode mode);
/// Runs one tagging rule's query in the thread list, so the user can see
/// which mail it collects. The rules dialog stays open; the point is to
diff --git a/src/messagedetailsdialog.cpp b/src/messagedetailsdialog.cpp
index 058814b..e487270 100644
--- a/src/messagedetailsdialog.cpp
+++ b/src/messagedetailsdialog.cpp
@@ -88,10 +88,16 @@ MessageDetailsDialog::MessageDetailsDialog(const QList<ThreadRenderItem> &items,
QMenu menu(this);
auto *replace = menu.addAction(tr("Search for this"));
connect(replace, &QAction::triggered, this,
- [this, row]() { requestSearch(row, false); });
+ [this, row]() {
+ requestSearch(
+ row, SearchTerm::SearchMode::Replace);
+ });
auto *narrow = menu.addAction(tr("Add to search"));
connect(narrow, &QAction::triggered, this,
- [this, row]() { requestSearch(row, true); });
+ [this, row]() {
+ requestSearch(
+ row, SearchTerm::SearchMode::Narrow);
+ });
menu.exec(value->mapToGlobal(pos));
});
}
@@ -145,9 +151,10 @@ void MessageDetailsDialog::buildRows(const QList<ThreadRenderItem> &items)
}
}
-void MessageDetailsDialog::requestSearch(const HeaderRow &row, bool extend)
+void MessageDetailsDialog::requestSearch(const HeaderRow &row,
+ SearchTerm::SearchMode mode)
{
if (row.query.isEmpty())
return;
- emit searchRequested(row.query, extend);
+ emit searchRequested(row.query, mode);
}
diff --git a/src/messagedetailsdialog.h b/src/messagedetailsdialog.h
index f865913..b141c39 100644
--- a/src/messagedetailsdialog.h
+++ b/src/messagedetailsdialog.h
@@ -23,6 +23,7 @@
#include <QString>
#include "htmlbuilder.h"
+#include "searchterm.h"
/// One header of one message, as shown and as searched for.
///
@@ -72,12 +73,13 @@ public:
/// Emits searchRequested for `row`, or nothing when the row carries no
/// searchable query. The menu entries call this; a test can too, without
/// popping a menu.
- void requestSearch(const HeaderRow &row, bool extend);
+ void requestSearch(const HeaderRow &row, SearchTerm::SearchMode mode);
signals:
- /// The user chose a search from a row's menu. `extend` narrows the current
- /// query rather than replacing it.
- void searchRequested(const QString &query, bool extend);
+ /// The user chose a search from a row's menu. `mode` says whether to
+ /// replace the query, narrow it, or narrow it by everything that is not
+ /// this value.
+ void searchRequested(const QString &query, SearchTerm::SearchMode mode);
private:
/// Builds the rows from the thread, one group per message.
diff --git a/src/messageview.cpp b/src/messageview.cpp
index 2e7e694..26ef7e3 100644
--- a/src/messageview.cpp
+++ b/src/messageview.cpp
@@ -569,12 +569,14 @@ void MessageView::addSearchEntries(QMenu *menu, const QList<SearchOffer> &offers
auto *sub = menu->addMenu(tr("Search for %1").arg(entry.label));
auto *replace = sub->addAction(tr("Search for this"));
- connect(replace, &QAction::triggered, this,
- [this, entry]() { emit searchRequested(entry.query, false); });
+ connect(replace, &QAction::triggered, this, [this, entry]() {
+ emit searchRequested(entry.query, SearchTerm::SearchMode::Replace);
+ });
auto *narrow = sub->addAction(tr("Add to search"));
- connect(narrow, &QAction::triggered, this,
- [this, entry]() { emit searchRequested(entry.query, true); });
+ connect(narrow, &QAction::triggered, this, [this, entry]() {
+ emit searchRequested(entry.query, SearchTerm::SearchMode::Narrow);
+ });
}
}
@@ -645,9 +647,9 @@ void MessageView::showDetailsDialog()
// from. Closing first leaves no window in which the dialog describes a
// thread the pane has already dropped.
connect(&dialog, &MessageDetailsDialog::searchRequested, this,
- [this, &dialog](const QString &query, bool extend) {
+ [this, &dialog](const QString &query, SearchTerm::SearchMode mode) {
dialog.accept();
- emit searchRequested(query, extend);
+ emit searchRequested(query, mode);
});
dialog.exec();
diff --git a/src/messageview.h b/src/messageview.h
index 3e600f0..877064e 100644
--- a/src/messageview.h
+++ b/src/messageview.h
@@ -182,15 +182,16 @@ signals:
/// The user chose a search from one of the pane's context menus.
///
- /// `extend` narrows the current query rather than replacing it. The view
- /// does not know what the query bar holds and must not: the window owns
- /// that field and does the combining.
+ /// `mode` says whether to replace the query bar, narrow it, or narrow it
+ /// by everything that is not this value. The view does not know what the
+ /// query bar holds and must not: the window owns that field and does the
+ /// combining.
///
/// Separate from queryRequested(), which carries a gate against a link in
/// a rendered document driving the thread list. These menus are chrome
/// built by our own code from values we extracted, so they need no gate,
/// and widening the existing signal would change what that gate protects.
- void searchRequested(const QString &query, bool extend);
+ void searchRequested(const QString &query, SearchTerm::SearchMode mode);
protected:
/// Turns Ctrl+wheel over the body into zoom, and Ctrl+middle-click into a