diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/carddelegate.cpp | 6 | ||||
| -rw-r--r-- | src/cardlayout.cpp | 33 | ||||
| -rw-r--r-- | src/cardlayout.h | 17 | ||||
| -rw-r--r-- | src/threadlistmodel.cpp | 18 | ||||
| -rw-r--r-- | src/threadlistmodel.h | 8 | ||||
| -rw-r--r-- | src/threadlistview.cpp | 4 | ||||
| -rw-r--r-- | src/threadlistview.h | 2 | ||||
| -rw-r--r-- | src/types.h | 6 |
8 files changed, 55 insertions, 39 deletions
diff --git a/src/carddelegate.cpp b/src/carddelegate.cpp index fbdf13f..02f1df0 100644 --- a/src/carddelegate.cpp +++ b/src/carddelegate.cpp @@ -40,7 +40,7 @@ CardLayout::Input inputFor(const QModelIndex &index) CardLayout::Input in; in.isMessage = index.data(ThreadListModel::IsMessageRole).toBool(); in.depth = index.data(ThreadListModel::MessageDepthRole).toInt(); - in.replyCount = index.data(ThreadListModel::ReplyCountRole).toInt(); + in.messageCount = index.data(ThreadListModel::MessageCountRole).toInt(); in.dateFormat = index.data(ThreadListModel::DateFormatRole).toString(); // Item 70's marks. The layout reserves a rect for each, so these have to @@ -305,14 +305,14 @@ void CardDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, drawMark(card.receivedForwardRect, Marks::Mark::ReceivedForward); drawMark(card.repliedRect, Marks::Mark::Replied); - // The reply count, which is also the expander, drawn as a PILL. + // The message count, which is also the expander, drawn as a PILL. // // A bare "3" on the card's own background read as an unexplained number // beside the subject and gave no hint that it could be clicked. The chip // shape says "this is a control", matching the tag chips on line 3, and the // word says what the number counts. if (!card.expanderRect.isEmpty()) { - const int count = index.data(ThreadListModel::ReplyCountRole).toInt(); + const int count = index.data(ThreadListModel::MessageCountRole).toInt(); const QString label = CardLayout::expanderLabel( count, option.state & QStyle::State_Open); diff --git a/src/cardlayout.cpp b/src/cardlayout.cpp index ec22635..f89d3ec 100644 --- a/src/cardlayout.cpp +++ b/src/cardlayout.cpp @@ -18,6 +18,7 @@ #include "cardlayout.h" +#include <QCoreApplication> #include <QFontMetrics> #include <QLocale> @@ -52,9 +53,9 @@ int CardLayout::markSide(const QFont &font) return qMax(8, side); } -QString CardLayout::expanderLabel(int replyCount, bool expanded) +QString CardLayout::expanderLabel(int messageCount, bool expanded) { - // "3 replies", not a bare "3". The count alone reads as an unexplained + // "5 messages", not a bare "5". The count alone reads as an unexplained // number beside the subject, and the word is what says the card opens. // // The triangle is NO LONGER part of this string. Item 70 made it a drawn @@ -65,14 +66,20 @@ QString CardLayout::expanderLabel(int replyCount, bool expanded) // when the card opens, and a caller that stopped passing the state would // hide that requirement rather than satisfy it. // - // Not translated through tr() here because CardLayout is a plain struct - // rather than a QObject; the delegate is where a translated build would - // wrap this, and the string is deliberately kept in one place so there is - // exactly one thing to change. + // CardLayout is a plain struct rather than a QObject, so this cannot use + // tr(); QCoreApplication::translate() with an explicit context is the + // equivalent, and the literal context string is what lupdate extracts + // under. The word is translated rather than the whole "%1 %2", because + // %n's untranslated fallback on this Qt does not pluralise (measured: + // "%n message(s)" stays literally "(s)"), and the two forms read cleanly + // in the .ts. Q_UNUSED(expanded); - const QString word = replyCount == 1 ? QStringLiteral("reply") - : QStringLiteral("replies"); - return QStringLiteral("%1 %2").arg(replyCount).arg(word); + const QString word = messageCount == 1 + ? QCoreApplication::translate("CardLayout", + "message") + : QCoreApplication::translate("CardLayout", + "messages"); + return QStringLiteral("%1 %2").arg(messageCount).arg(word); } QString CardLayout::widestDateSample(const QString &format) @@ -196,18 +203,18 @@ CardLayout CardLayout::compute(const Input &input, const QRect &rect, - kPaddingX), metrics.height()); - // The expander is the reply count as a PILL, on line two and on the right. + // The expander is the message count as a PILL, on line two and on the right. // // Sized from the label actually drawn rather than from a fixed sample, so // the background and the text inside it cannot disagree. Both states of the // glyph are measured because the rect must not change width when the card // is expanded: a pill that resized on click would shift the subject's // elision under the pointer. - if (input.replyCount > 0) { + if (input.messageCount > 0) { const int collapsed = smallMetrics.horizontalAdvance( - expanderLabel(input.replyCount, false)); + expanderLabel(input.messageCount, false)); const int expanded = smallMetrics.horizontalAdvance( - expanderLabel(input.replyCount, true)); + expanderLabel(input.messageCount, true)); // The triangle is a drawn mark since item 70, so the pill has to // reserve its width explicitly. It came free from the text metrics // while it was a glyph in the label, which is exactly the kind of diff --git a/src/cardlayout.h b/src/cardlayout.h index 57edca7..9620900 100644 --- a/src/cardlayout.h +++ b/src/cardlayout.h @@ -35,7 +35,7 @@ /// The card is three lines, always: /// /// sender ................................ date <- senderRect/dateRect -/// * subject @ v 3 replies <- subjectRect/expanderRect +/// * subject @ v 5 messages <- subjectRect/expanderRect /// [tag] [tag] <- tagRect struct CardLayout { @@ -45,7 +45,7 @@ struct CardLayout { bool isMessage = false; int depth = 0; ///< 0 for a thread root, 1 for a direct reply. - int replyCount = 0; ///< 0 means no expander. + int messageCount = 0; ///< Messages in the conversation; 0 means no expander. /// A QDateTime::toString() pattern from [general] date_format, or empty /// for the system's short format. @@ -105,8 +105,8 @@ struct CardLayout QRect subjectRect; QRect tagRect; - /// The reply count's rect, and the click target that toggles the thread. - /// Empty when the row has no replies. + /// The message count's rect, and the click target that toggles the thread. + /// Empty when the row has no expander. QRect expanderRect; /// The flagged mark, at the start of line two before the subject. Empty @@ -197,15 +197,18 @@ struct CardLayout /// The widest string formatDate() can return, for reserving space. static QString widestDateSample(const QString &format = QString()); - /// The expander's label: the reply count with its glyph, as drawn. + /// The expander's label: the message count with its word, as drawn. /// /// Shared with the layout for the same reason as formatDate: the rect /// reserved for the pill and the text put inside it must come from one /// place, or a count wider than the sample the layout guessed at spills /// out of its own background. /// - /// `expanded` chooses which way the triangle points. - static QString expanderLabel(int replyCount, bool expanded); + /// `expanded` chooses which way the triangle points. The word is + /// translated: a pill reading a foreign count in English next to an + /// otherwise local interface is a tiny broken window, and this is the one + /// user-facing string this plain struct owns. + static QString expanderLabel(int messageCount, bool expanded); /// Padding inside the expander pill, matching a tag chip's, so the two read /// as the same kind of object on the card. diff --git a/src/threadlistmodel.cpp b/src/threadlistmodel.cpp index 8bb9849..5c44dd4 100644 --- a/src/threadlistmodel.cpp +++ b/src/threadlistmodel.cpp @@ -439,7 +439,7 @@ QVariant ThreadListModel::data(const QModelIndex &index, int role) const m_forwardPrefixes); case IsRepliedRole: return node.isReplied(); - case ReplyCountRole: + case MessageCountRole: // A reply never offers an expander: nesting past the first level is // drawn from depth, not from further parent-child structure. return 0; @@ -714,15 +714,19 @@ QVariant ThreadListModel::data(const QModelIndex &index, int role) const m_forwardPrefixes); case IsRepliedRole: return thread.isReplied(); - case ReplyCountRole: + case MessageCountRole: // Zero in a flat list, so the card draws no expander pill. The count - // and hasChildren() must agree: a card advertising "3 replies" that - // cannot be opened is the inert-glyph defect this project has already - // shipped once. + // and hasChildren() must agree: a card advertising a count for a thread + // that cannot be opened is the inert-glyph defect this project has + // already shipped once. if (m_flatMode) return 0; - // totalCount includes the root message, which is the card itself. - return qMax(0, thread.totalCount - 1); + // The number of MESSAGES in the conversation, not the replies alone: + // the row stands for the conversation now (item 177), so a thread of + // one message and four replies reads "5 messages". A thread of one + // shows nothing: its row is the message, there is nothing to expand, + // and the pill is the expander. + return thread.totalCount > 1 ? thread.totalCount : 0; case DateFormatRole: return m_dateFormat; default: diff --git a/src/threadlistmodel.h b/src/threadlistmodel.h index 93474ac..fee4a1f 100644 --- a/src/threadlistmodel.h +++ b/src/threadlistmodel.h @@ -83,7 +83,8 @@ public: MessageIdRole, /// The message's reply depth, for the view's indentation. 1 for a - /// direct reply, since depth 0 is the root row itself. + /// direct reply; 0 is the thread's first message, which sits under the + /// conversation row unindented. MessageDepthRole, /// True when the row is a thread that has replies to show. @@ -138,7 +139,8 @@ public: /// bool; the message was replied to, from the Maildir "R" flag. IsRepliedRole, - ReplyCountRole, ///< int; 0 when a thread has no replies. + MessageCountRole, ///< int; messages in the conversation, 0 when the + ///< thread has one message and nothing to expand. /// The [general] date_format pattern, or empty for the system's short /// format. Same row value for every row. @@ -207,7 +209,7 @@ public: /// that is what keeps it from leaking: it is off by default, only the Sent /// button turns it on, and every other query turns it off again. The /// expander already comes from hasChildren() and the card's count from - /// ReplyCountRole, so flat mode is those two answering differently and + /// MessageCountRole, so flat mode is those two answering differently and /// nothing else changes. /// /// The children are not discarded, only hidden. Leaving flat mode restores diff --git a/src/threadlistview.cpp b/src/threadlistview.cpp index 5a3ce77..019d7c9 100644 --- a/src/threadlistview.cpp +++ b/src/threadlistview.cpp @@ -27,10 +27,10 @@ void ThreadListView::mousePressEvent(QMouseEvent *event) { const QModelIndex index = indexAt(event->pos()); - // The reply count IS the expander. Anything outside its rect selects the + // The message count IS the expander. Anything outside its rect selects the // card and opens it, which is what the rest of the card is for. if (event->button() == Qt::LeftButton && index.isValid() - && index.data(ThreadListModel::ReplyCountRole).toInt() > 0) { + && index.data(ThreadListModel::MessageCountRole).toInt() > 0) { QStyleOptionViewItem option; initViewItemOption(&option); diff --git a/src/threadlistview.h b/src/threadlistview.h index 3215153..a509389 100644 --- a/src/threadlistview.h +++ b/src/threadlistview.h @@ -40,7 +40,7 @@ public: using QTreeView::QTreeView; protected: - /// Toggles a thread when its reply count is clicked. + /// Toggles a thread when its message count is clicked. /// /// Being VISIBLE and being CLICKABLE are separate properties: /// setRootIsDecorated(false), needed to stop the style drawing its own diff --git a/src/types.h b/src/types.h index 8e24cd1..ee2627f 100644 --- a/src/types.h +++ b/src/types.h @@ -190,9 +190,9 @@ struct MessageNode QStringList tags; QString filePath; - /// Reply depth within the thread. 0 is the thread's first message, which - /// occupies the ROOT row rather than a child row: the user's model is - /// "N replies", so a thread of 7 shows 1 root and 6 descendants. + /// Reply depth within the thread. 0 is the thread's first message: since + /// item 177 a conversation lists it as a child row too, but it carries no + /// nesting. 1 is a direct reply. int depth = 0; bool isUnread() const { return tags.contains(QStringLiteral("unread")); } |
