diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-13 19:19:58 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-13 19:19:58 +0200 |
| commit | 0c5eea8f0d0ccc5b8eb6220814c9e212d6c1ccc2 (patch) | |
| tree | 4275734ed0c31f46609f9fd5b78412209dbeec1c /src/savequerydialog.h | |
| parent | 5e30d1805656895387ba83865d9635caf2e51618 (diff) | |
| download | qtmaildir-0c5eea8f0d0ccc5b8eb6220814c9e212d6c1ccc2.tar.gz qtmaildir-0c5eea8f0d0ccc5b8eb6220814c9e212d6c1ccc2.zip | |
feat(queries): save a query from the UI, and split the buttons off the query row
Second half of item 23, on top of the storage change. A query can now be kept
without hand-editing a file, and the row of buttons no longer grows without
bound.
Ctrl+S opens a dialog on whatever is in the query bar, taking a name, an
optional account scope and whether the query is pinned. It preselects the
account already chosen in the dropdown, since that is the scope the user is
looking at, and it says so when a name is about to replace an existing query
rather than refusing the name: overwriting a saved query on purpose is a normal
edit, and the only thing worth preventing is doing it without noticing. Saving
over an entry keeps the stored entry's unknown fields rather than the dialog's
fresh value, so a field written by a later build survives being edited here.
The saved queries move to a row of their own beneath the query bar, pinned ones
as buttons and the rest behind a More queries menu that only exists when
something is in it. The ponytail note that stood in the query row predicted
exactly this: an unbounded list of buttons sharing the row squeezed the field.
Sent moves down with them and is still not a saved query, for the reason already
recorded there.
A saved query's account scope goes through the account DROPDOWN rather than
being baked into the query text. runQuery() already wraps the query in the
selected account's path, so pre-scoping here would apply it twice, and setting
the dropdown also shows the user which scope they are in. An unscoped query
clears the selection rather than inheriting whatever the last one left, which is
the same defect the rules preview had.
Seven tests, three mutations. Ignoring the pinned flag fails two of them,
pre-scoping the text instead of setting the dropdown fails two, and letting an
unscoped query inherit the previous account fails one. The menu-absence test
initially passed against no implementation at all, since it only asserted a
widget was missing; it now proves the row was populated first, which is the
guard that class of test needs.
Two existing invariants caught real omissions rather than needing adjustment:
every registered action must appear in KeyMap::knownActions(), which is what
gives it a configurable binding, and every action needs its own icon.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src/savequerydialog.h')
| -rw-r--r-- | src/savequerydialog.h | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/src/savequerydialog.h b/src/savequerydialog.h new file mode 100644 index 0000000..be5a2af --- /dev/null +++ b/src/savequerydialog.h @@ -0,0 +1,63 @@ +/* + * qtmaildir - a Qt6 mail client for notmuch-indexed Maildirs + * Copyright (C) 2026 Danilo M. <danix@danix.xyz> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include <QDialog> + +#include "config.h" + +class QCheckBox; +class QComboBox; +class QLabel; +class QLineEdit; +class QPushButton; + +/// Names a query and keeps it in queries.json. +/// +/// Pure UI: it is handed the config and returns a SavedQuery. It writes +/// nothing, so it can be tested without touching a file, and the caller owns +/// the decision of what to do with the result. +class SaveQueryDialog : public QDialog +{ + Q_OBJECT +public: + /// `query` is the text to store, `accountKey` the scope to preselect, + /// which is the account the user is already looking at. + SaveQueryDialog(const Config &config, const QString &query, + const QString &accountKey, QWidget *parent = nullptr); + + /// The query as edited. Only meaningful after exec() returned Accepted. + SavedQuery savedQuery() const; + + /// Whether `name` already names a stored query. Case-insensitive, matching + /// how startup_query resolves, so "inbox" and "Inbox" cannot both exist and + /// leave the user unable to tell which one a button ran. + static bool namesAnExistingQuery(const Config &config, const QString &name); + +private: + void updateOkState(); + + const Config &m_config; + QLineEdit *m_name = nullptr; + QLineEdit *m_query = nullptr; + QComboBox *m_account = nullptr; + QCheckBox *m_pinned = nullptr; + QPushButton *m_ok = nullptr; + QLabel *m_notice = nullptr; +}; |
