aboutsummaryrefslogtreecommitdiffstats
path: root/src/config.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.cpp')
-rw-r--r--src/config.cpp73
1 files changed, 63 insertions, 10 deletions
diff --git a/src/config.cpp b/src/config.cpp
index 23c7364..d91259a 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -80,6 +80,18 @@ QString generatorTag(const QString &generator)
return QString();
}
+/// Whether a generator lists MESSAGES rather than threads. "sent" folds a
+/// user's own message back into the conversation it answers, and "drafts" is
+/// worse: a thread row stands for its first matched message, which for a draft
+/// reply is the message being replied TO, so the draft itself is unreachable.
+/// "trash" stays threaded, since a deleted message still belongs to its
+/// conversation. Closed set, and the one place the three views are decided.
+bool generatorIsFlat(const QString &generator)
+{
+ return generator == QStringLiteral("sent")
+ || generator == QStringLiteral("drafts");
+}
+
} // namespace
QString Account::scopedQuery(const QString &query) const
@@ -459,6 +471,17 @@ void Config::load(const QString &path)
account.sent =
settings.value(QStringLiteral("sent")).toString().trimmed();
+ // Optional, and a STARTING value rather than a binding: the composer's
+ // switch keeps every signature reachable whichever account is
+ // selected. Left empty when absent, so the composer can tell "this
+ // account says nothing" from "this account says none" and fall through
+ // to [compose] signature itself; resolving that here would collapse
+ // the two. Trimmed for the same reason as sent, above: a trailing
+ // space would be carried into a filename lookup and match nothing,
+ // which is invisible in a config file.
+ account.signature =
+ settings.value(QStringLiteral("signature")).toString().trimmed();
+
// Mandatory, unlike sent: Delete moves a file into this folder, so an
// account without one cannot delete at all. Trimmed for the same
// reason as sent, above.
@@ -547,6 +570,31 @@ void Config::load(const QString &path)
m_compose.sendHtml =
settings.value(QStringLiteral("send_html"), true).toBool();
+ // Trimmed for the same reason the account key is: it reaches a filename
+ // lookup, where a trailing space matches nothing invisibly.
+ m_compose.signature =
+ settings.value(QStringLiteral("signature")).toString().trimmed();
+
+ // The same shape as quote_position directly above: an absent key is
+ // silent and the struct default holds, but a PRESENT and malformed value
+ // is reported rather than silently accepted. value(key, default) alone
+ // would read "signature_position = abov" as above_quote.
+ const QString signaturePosition =
+ settings.value(QStringLiteral("signature_position"),
+ QStringLiteral("end"))
+ .toString().trimmed();
+ if (signaturePosition.compare(QStringLiteral("above_quote"),
+ Qt::CaseInsensitive) == 0) {
+ m_compose.signaturePosition = Signatures::Position::AboveQuote;
+ } else if (signaturePosition.compare(QStringLiteral("end"),
+ Qt::CaseInsensitive) == 0) {
+ m_compose.signaturePosition = Signatures::Position::End;
+ } else {
+ addProblem(tr("[compose] signature_position '%1' is not recognised; "
+ "expected end or above_quote. Using end.")
+ .arg(signaturePosition));
+ }
+
// Three numerics, all following the shape already established at
// message_zoom, toolbar_icon_size, mark_read_delay_ms and
// auto_sync_delay_ms elsewhere in this function: a QVariant, a checked
@@ -802,14 +850,14 @@ void Config::loadSavedQueries(const QString &configPath, QSettings &settings)
query.query = object.value(QStringLiteral("query")).toString();
query.account = object.value(QStringLiteral("account")).toString();
query.generated = object.value(QStringLiteral("generated")).toString();
- // A generator carries its own view mode, so "sent" is flat whether or
- // not the file says so. Storing it as a plain field would let a
+ // A generator carries its own view mode, so a flat one is flat whether
+ // or not the file says so. Storing it as a plain field would let a
// hand-edited or migrated-from-elsewhere row produce a THREADED sent
// view, which folds every reply back into the conversation the user
// sent one message into. The file may still set it for an ordinary
// query.
query.flat = object.value(QStringLiteral("flat")).toBool(false)
- || query.generated == QStringLiteral("sent");
+ || generatorIsFlat(query.generated);
if (query.isGenerated()
&& !kQueryGenerators.contains(query.generated)) {
@@ -869,7 +917,7 @@ bool Config::saveSavedQueries() const
object.insert(QStringLiteral("account"), query.account);
// Skipped when the generator already implies it, which loadSavedQueries
// reapplies on the way back in.
- if (query.flat && query.generated != QStringLiteral("sent"))
+ if (query.flat && !generatorIsFlat(query.generated))
object.insert(QStringLiteral("flat"), true);
for (auto it = query.unknown.begin(); it != query.unknown.end(); ++it)
object.insert(it.key(), it.value());
@@ -951,6 +999,9 @@ SavedQuery Config::builtinFilter(const QString &generator)
SavedQuery filter;
filter.generated = generator;
+ // One source for the view mode, shared with the saved-query round trip, so
+ // a branch below cannot disagree with what loadSavedQueries reapplies.
+ filter.flat = generatorIsFlat(generator);
// Translated, because these are the labels on the buttons. The GENERATOR
// name is not: it is stored in queries.json and matched against a closed
@@ -969,16 +1020,18 @@ SavedQuery Config::builtinFilter(const QString &generator)
filter.name = tr("Important");
} else if (generator == QStringLiteral("sent")) {
filter.name = tr("Sent");
- // Messages rather than threads, and the only filter that sets this. A
- // thread would fold the user's sent message back into the conversation
- // it belongs to, which is item 63's finding.
- filter.flat = true;
+ // Flat, per generatorIsFlat(): a thread would fold the user's sent
+ // message back into the conversation it belongs to, item 63's finding.
} else if (generator == QStringLiteral("drafts")) {
// The LABEL is translated; the generator stays `drafts`, which is what
// queries.json stores and what a closed set is matched against.
filter.name = tr("Drafts");
- // NOT flat, like Trash and unlike Sent: a draft reply belongs with the
- // conversation it answers.
+ // Flat, per generatorIsFlat(). Item 138 chose threaded, reasoning that
+ // a draft reply belongs with the conversation it answers; item 159
+ // reversed it on what that cost. A thread row stands for its first
+ // MATCHED message, which for a draft reply is the message being
+ // replied TO, so the draft itself had no row of its own and
+ // double-clicking the conversation opened nothing.
} else if (generator == QStringLiteral("trash")) {
filter.name = tr("Trash");
// NOT flat, unlike Sent. A deleted message still belongs to its