summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mainwindow.cpp8
-rw-r--r--src/threadlistmodel.cpp46
-rw-r--r--src/threadlistmodel.h15
-rw-r--r--src/types.h7
4 files changed, 71 insertions, 5 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index eaf98b8..915c1ae 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -169,8 +169,16 @@ void MainWindow::buildUi()
m_threadView->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_threadView->verticalHeader()->hide();
m_threadView->horizontalHeader()->setStretchLastSection(false);
+ // Subject is the last column and takes the leftover width; the three
+ // fixed-width ones size to their contents. Nothing sits to the right of
+ // the stretching column, so no column can be pushed out of view.
m_threadView->horizontalHeader()->setSectionResizeMode(
ThreadListModel::SubjectColumn, QHeaderView::Stretch);
+ for (int column : { ThreadListModel::TagsColumn, ThreadListModel::DateColumn,
+ ThreadListModel::AuthorsColumn }) {
+ m_threadView->horizontalHeader()->setSectionResizeMode(
+ column, QHeaderView::ResizeToContents);
+ }
connect(m_threadView->selectionModel(),
&QItemSelectionModel::currentRowChanged,
diff --git a/src/threadlistmodel.cpp b/src/threadlistmodel.cpp
index c129be1..a083145 100644
--- a/src/threadlistmodel.cpp
+++ b/src/threadlistmodel.cpp
@@ -18,8 +18,24 @@
#include "threadlistmodel.h"
+#include <QBrush>
#include <QFont>
+QColor ThreadListModel::deletedColour()
+{
+ // Desaturated crimson: legible under white text on a dark theme, and calm
+ // enough that deleting fifty threads does not repaint the list as a
+ // warning banner.
+ return QColor(0x8b, 0x2c, 0x2c);
+}
+
+QColor ThreadListModel::spamColour()
+{
+ // Distinct hue rather than a lighter red, so spam and deleted are told
+ // apart by colour and not by shade.
+ return QColor(0xa8, 0x5c, 0x18);
+}
+
ThreadListModel::ThreadListModel(QObject *parent)
: QAbstractTableModel(parent)
{
@@ -67,10 +83,34 @@ QVariant ThreadListModel::data(const QModelIndex &index, int role) const
}
}
- if (role == Qt::FontRole && thread.isUnread()) {
+ // A thread tagged deleted or spam is on its way out, and the user needs to
+ // see that the moment they act. Every one of these roles applies to the
+ // whole row: a cue on a single column disappears as soon as that column
+ // scrolls out of view, which is exactly how the tag change used to go
+ // unnoticed.
+ if (thread.isDoomed()) {
+ if (role == Qt::BackgroundRole)
+ return QBrush(thread.isDeleted() ? deletedColour() : spamColour());
+ if (role == Qt::ForegroundRole)
+ return QBrush(QColor(Qt::white));
+ }
+
+ if (role == Qt::FontRole) {
QFont font;
- font.setBold(true);
- return font;
+ bool styled = false;
+ if (thread.isUnread()) {
+ font.setBold(true);
+ styled = true;
+ }
+ // Struck through as well as filled, so the state survives a
+ // screenshot, a colourblind reader, and a theme that overrides the
+ // background.
+ if (thread.isDoomed()) {
+ font.setStrikeOut(true);
+ styled = true;
+ }
+ if (styled)
+ return font;
}
return {};
diff --git a/src/threadlistmodel.h b/src/threadlistmodel.h
index eb1a7ff..01fd241 100644
--- a/src/threadlistmodel.h
+++ b/src/threadlistmodel.h
@@ -19,6 +19,7 @@
#pragma once
#include <QAbstractTableModel>
+#include <QColor>
#include <QVector>
#include "types.h"
@@ -29,11 +30,14 @@ class ThreadListModel : public QAbstractTableModel
{
Q_OBJECT
public:
+ /// Subject stretches to fill the view, so it must come last: anything
+ /// after it is pushed out of sight. Tags leads, being the column that
+ /// changes when the user acts on a thread.
enum Column {
- DateColumn = 0,
+ TagsColumn = 0,
+ DateColumn,
AuthorsColumn,
SubjectColumn,
- TagsColumn,
ColumnCount,
};
@@ -44,6 +48,13 @@ public:
ThreadIdRole = Qt::UserRole + 1,
};
+ /// Row fill for a thread tagged `deleted`, and for one tagged `spam`.
+ /// Muted rather than saturated: a bulk delete paints every selected row,
+ /// and a wall of pure red is harder to read than the list it replaces.
+ /// Exposed so a test names the same colour the model uses.
+ static QColor deletedColour();
+ static QColor spamColour();
+
explicit ThreadListModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = {}) const override;
diff --git a/src/types.h b/src/types.h
index 2de6129..e25c3a9 100644
--- a/src/types.h
+++ b/src/types.h
@@ -35,6 +35,13 @@ struct ThreadSummary
bool isUnread() const { return tags.contains(QStringLiteral("unread")); }
bool isFlagged() const { return tags.contains(QStringLiteral("flagged")); }
+ bool isDeleted() const { return tags.contains(QStringLiteral("deleted")); }
+ bool isSpam() const { return tags.contains(QStringLiteral("spam")); }
+
+ /// True while the thread is tagged for removal. notmuch deletes nothing
+ /// itself: the tag marks the thread for whatever the user's sync script
+ /// does next, so the row has to show it is on its way out.
+ bool isDoomed() const { return isDeleted() || isSpam(); }
};
struct MessageRef