aboutsummaryrefslogtreecommitdiffstats
path: root/src/tagdialog.cpp
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-07 10:32:08 +0200
committerDanilo M. <danix@danix.xyz>2026-08-07 10:32:08 +0200
commit6935bfc99ed0df5c79867f7015ba04041e03f908 (patch)
tree38c407c5ce7a5ae55331c89603fa2b6e4776d147 /src/tagdialog.cpp
parentdb4dbbf4bf4fd8aab1a9e20d87c266ce7836a946 (diff)
downloadqtmaildir-6935bfc99ed0df5c79867f7015ba04041e03f908.tar.gz
qtmaildir-6935bfc99ed0df5c79867f7015ba04041e03f908.zip
fix(tags): the Remove field suggests only tags the selection has
Both TagDialog fields built their completer from knownTags, the whole database's tag list, so removing a tag offered every tag in existence rather than the handful the selected threads actually carry. The candidates were already in the dialog: currentTags, used until now only to render the checkbox list. The constructor now walks two (field, vocabulary) pairs instead of two fields sharing one list, with knownTags for Add and currentTags.keys() for Remove. On a multi-thread selection that is the union, not the intersection, since removing a tag two of three threads carry is a meaningful request. The setWidget and per-token prefix machinery is untouched: these fields hold a comma-separated list, and QLineEdit::setCompleter is the trap this dialog already works around. Only the candidate list changed. Completion stays a suggestion, never a whitelist, so a tag absent from the candidates still applies. Tests type keys rather than using setText, which does not drive a completer at all. Verified load-bearing by mutation: reverting the Remove vocabulary to knownTags fails the new test. Closes item 48. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src/tagdialog.cpp')
-rw-r--r--src/tagdialog.cpp19
1 files changed, 17 insertions, 2 deletions
diff --git a/src/tagdialog.cpp b/src/tagdialog.cpp
index 75e6b03..1fb3f18 100644
--- a/src/tagdialog.cpp
+++ b/src/tagdialog.cpp
@@ -160,8 +160,23 @@ TagDialog::TagDialog(const QStringList &knownTags,
// Completion is a guard against typos, never a whitelist: a tag absent from
// this list is exactly what the dialog exists to create, so the completer
// suggests and does not constrain.
- for (QLineEdit *edit : { m_addEdit, m_removeEdit }) {
- auto *completer = new QCompleter(knownTags, edit);
+ //
+ // The two fields complete against different vocabularies. Add reaches the
+ // whole database, since naming a tag that does not exist yet is what it is
+ // for. Remove offers only what the selection actually carries: on a
+ // multi-thread selection that is the union with counts, not the
+ // intersection, because removing a tag two of three threads have is a
+ // meaningful thing to ask for.
+ QStringList removeCandidates = currentTags.keys();
+ removeCandidates.sort();
+
+ const QList<QPair<QLineEdit *, QStringList>> fields = {
+ { m_addEdit, knownTags },
+ { m_removeEdit, removeCandidates },
+ };
+
+ for (const auto &[edit, candidates] : fields) {
+ auto *completer = new QCompleter(candidates, edit);
completer->setCaseSensitivity(Qt::CaseInsensitive);
// Hierarchies are the reason this matters: typing "amazon" should find
// "shopping/amazon".