aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/config.cpp17
-rw-r--r--src/config.h10
-rw-r--r--src/mainwindow.cpp50
-rw-r--r--src/mainwindow.h2
4 files changed, 77 insertions, 2 deletions
diff --git a/src/config.cpp b/src/config.cpp
index de6a783..f21bba9 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -89,6 +89,23 @@ void Config::load(const QString &path)
account.address = settings.value(QStringLiteral("address")).toString();
account.maildir = settings.value(QStringLiteral("maildir")).toString();
account.drafts = settings.value(QStringLiteral("drafts")).toString();
+
+ // Both optional, and both describe this account's chip in the thread
+ // list. An account tag is a different taxonomy from a functional one,
+ // saying which mailbox a thread arrived in rather than what state it
+ // is in, so these live here rather than in [tagcolors].
+ account.label = settings.value(QStringLiteral("label")).toString();
+
+ const QString colour = settings.value(QStringLiteral("color")).toString();
+ if (!colour.isEmpty()) {
+ account.color = QColor(colour);
+ if (!account.color.isValid()) {
+ addProblem(
+ QStringLiteral("Account '%1' has an unparseable color '%2'; "
+ "using a generated one.")
+ .arg(account.key, colour));
+ }
+ }
settings.endGroup();
if (!account.isValid()) {
diff --git a/src/config.h b/src/config.h
index 270b780..943cbd8 100644
--- a/src/config.h
+++ b/src/config.h
@@ -18,6 +18,7 @@
#pragma once
+#include <QColor>
#include <QList>
#include <QString>
#include <QStringList>
@@ -33,6 +34,15 @@ struct Account
QString maildir; ///< Relative to notmuch's database.path.
QString drafts; ///< Unused in v1; send is v2.
+ /// Chip colour in the thread list. Invalid when unset, in which case one
+ /// is generated from the account tag's name.
+ QColor color;
+
+ /// Text shown on the chip. Empty falls back to the key, which can be long:
+ /// "privateemail-danilo.macri" is a lot of row for one bit of information.
+ /// This renames nothing in notmuch, only what the chip displays.
+ QString label;
+
bool isValid() const { return !key.isEmpty() && !maildir.isEmpty(); }
/// Restricts a notmuch query to this account's subtree.
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index ba690b4..48b475c 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -42,6 +42,7 @@
#include "messageview.h"
#include "mimeparser.h"
#include "notmuchworker.h"
+#include "tagchip.h"
#include "threadlistmodel.h"
#include "version.h"
@@ -73,6 +74,14 @@ MainWindow::MainWindow(const Config &config, QWidget *parent)
{
QSettings settings(Config::defaultPath(), QSettings::IniFormat);
m_keyMap.loadOverrides(settings);
+ m_tagColors.load(settings);
+ }
+
+ // An account's chip colour comes from its own stanza, since an account tag
+ // is a different taxonomy from a functional one.
+ for (const Account &account : m_config.accounts()) {
+ m_tagColors.setAccountColour(account.key, account.color);
+ m_tagColors.setAccountLabel(account.key, account.label);
}
buildUi();
@@ -163,6 +172,7 @@ void MainWindow::buildUi()
// Thread list and message pane.
m_model = new ThreadListModel(this);
+ m_model->setTagColors(&m_tagColors);
m_threadView = new QTableView(central);
m_threadView->setModel(m_model);
m_threadView->setSelectionBehavior(QAbstractItemView::SelectRows);
@@ -176,6 +186,10 @@ void MainWindow::buildUi()
m_threadView->horizontalHeader()->setSectionResizeMode(
column, QHeaderView::Interactive);
}
+
+ // The subject cell carries the account chip in front of its text.
+ m_threadView->setItemDelegateForColumn(ThreadListModel::SubjectColumn,
+ new SubjectDelegate(this));
// Widening a column past the viewport scrolls rather than squeezing the
// others. Per-pixel so the scroll does not jump a whole column at a time.
m_threadView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
@@ -183,7 +197,6 @@ void MainWindow::buildUi()
// Starting widths only; a drag overrides them, and they are what the
// saved-widths item will persist.
- m_threadView->setColumnWidth(ThreadListModel::TagsColumn, 160);
m_threadView->setColumnWidth(ThreadListModel::DateColumn, 130);
m_threadView->setColumnWidth(ThreadListModel::AuthorsColumn, 180);
m_threadView->setColumnWidth(ThreadListModel::SubjectColumn, 520);
@@ -193,6 +206,7 @@ void MainWindow::buildUi()
this, &MainWindow::onThreadSelected);
m_messageView = new MessageView(central);
+ m_messageView->setTagColors(&m_tagColors);
connect(m_messageView, &MessageView::statusMessage,
this, [this](const QString &text) { m_statusLabel->setText(text); });
@@ -356,6 +370,28 @@ void MainWindow::buildMenus()
auto *about = helpMenu->addAction(tr("&About"));
connect(about, &QAction::triggered, this, &MainWindow::showAbout);
+ // Standard names from the icon theme, so the buttons match the rest of the
+ // desktop rather than shipping bespoke art. A theme that lacks one leaves
+ // that action with text alone, which still works.
+ const QHash<QString, QString> themeIcons = {
+ { QStringLiteral("sync"), QStringLiteral("mail-receive") },
+ { QStringLiteral("archive"), QStringLiteral("mail-mark-read") },
+ { QStringLiteral("delete"), QStringLiteral("edit-delete") },
+ { QStringLiteral("undo"), QStringLiteral("edit-undo") },
+ { QStringLiteral("spam"), QStringLiteral("mail-mark-junk") },
+ { QStringLiteral("flag"), QStringLiteral("mail-mark-important") },
+ { QStringLiteral("quit"), QStringLiteral("application-exit") },
+ { QStringLiteral("focus_query"), QStringLiteral("edit-find") },
+ };
+ for (auto it = themeIcons.cbegin(); it != themeIcons.cend(); ++it) {
+ QAction *action = m_actions.value(it.key());
+ if (!action)
+ continue;
+ const QIcon icon = QIcon::fromTheme(it.value());
+ if (!icon.isNull())
+ action->setIcon(icon);
+ }
+
// The frequent subset only. A toolbar holding every action is as
// unreadable as no toolbar.
auto *toolBar = addToolBar(tr("Main"));
@@ -543,7 +579,9 @@ void MainWindow::onThreadSelected(const QModelIndex &current,
if (!current.isValid())
return;
- m_currentThreadId = m_model->threadAt(current.row()).threadId;
+ const ThreadSummary thread = m_model->threadAt(current.row());
+ m_currentThreadId = thread.threadId;
+ m_messageView->setTags(thread.tags);
QMetaObject::invokeMethod(m_worker, "loadThread", Qt::QueuedConnection,
Q_ARG(QString, m_currentThreadId),
Q_ARG(QString, m_lastQuery),
@@ -665,6 +703,14 @@ void MainWindow::sendThreadTagChange(const QStringList &threadIds,
for (const QString &threadId : threadIds)
m_model->applyTagChange(threadId, add, remove);
+ // The strip shows the open thread's tags, so it has to follow a change to
+ // that thread rather than waiting for the next selection.
+ if (threadIds.contains(m_currentThreadId)) {
+ const QModelIndex current = m_threadView->currentIndex();
+ if (current.isValid())
+ m_messageView->setTags(m_model->threadAt(current.row()).tags);
+ }
+
m_pendingThreadIds = threadIds;
m_pendingChange = TagChange{ {}, add, remove, description };
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 30a128a..4445894 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -28,6 +28,7 @@
#include "config.h"
#include "keymap.h"
+#include "tagcolors.h"
#include "types.h"
class QAction;
@@ -103,6 +104,7 @@ private:
Config m_config;
KeyMap m_keyMap;
+ TagColors m_tagColors;
QThread m_workerThread;
NotmuchWorker *m_worker = nullptr;