aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-28 20:46:44 +0200
committerDanilo M. <danix@danix.xyz>2026-08-28 20:46:44 +0200
commitd7c4d03f7d583767bc23406579e11bcc884dec18 (patch)
treeabe49fa75cb88d768a892cc11a8c2258869ead85
parentae2ae2df75ed780a88423b77af3b31fbe2b26389 (diff)
downloadqtmaildir-thread-row-identity.tar.gz
qtmaildir-thread-row-identity.zip
feat: count a card's messages, not its repliesthread-row-identity
The expander pill read "N replies" while the row stood for the conversation: a thread of one message and four replies said "4 replies" over rows that listed all five messages. The user's model is messages, so it now reads "5 messages". A thread of one still shows nothing: its row is the message, the pill is the expander, and there is nothing to open. ReplyCountRole becomes MessageCountRole and CardLayout::Input::replyCount becomes messageCount, so the names stop lying about what they carry. The label is now translated under a CardLayout context, with Italian "messaggio"/"messaggi" shipped; %n's untranslated fallback on this Qt does not pluralise, so the two forms are separate entries. The card's densest geometry test needs 460px rather than 400 now that the pill is one character wider.
-rw-r--r--CHANGELOG.md6
-rw-r--r--src/carddelegate.cpp6
-rw-r--r--src/cardlayout.cpp33
-rw-r--r--src/cardlayout.h17
-rw-r--r--src/threadlistmodel.cpp18
-rw-r--r--src/threadlistmodel.h8
-rw-r--r--src/threadlistview.cpp4
-rw-r--r--src/threadlistview.h2
-rw-r--r--src/types.h6
-rw-r--r--tests/test_cardlayout.cpp24
-rw-r--r--tests/test_mainwindow.cpp9
-rw-r--r--tests/test_threadlistmodel.cpp39
-rw-r--r--translations/qtmaildir_it_IT.ts11
13 files changed, 111 insertions, 72 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 56d98e4..4bdc536 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -115,6 +115,12 @@ point at which they are stable.
removes the row at once while an automatic one waits until you move on.
Reading the last unread message of a long conversation is the one case that
still waits for the next query or sync.
+- **A conversation's card counts its MESSAGES, not its replies.** The pill
+ that opens the thread read "N replies" against the total the row actually
+ lists: a thread of one message and four replies said "4 replies" over rows
+ for all five messages. It now reads "5 messages", which is what the
+ conversation is. A thread of one message still shows no count at all, since
+ there is nothing for the pill to open.
- **Delete and Restore appear only where they apply.** Delete is hidden on
mail already in the trash, where it reported success and did nothing, and
Restore is hidden on mail that was never deleted.
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")); }
diff --git a/tests/test_cardlayout.cpp b/tests/test_cardlayout.cpp
index c81296f..09afc5f 100644
--- a/tests/test_cardlayout.cpp
+++ b/tests/test_cardlayout.cpp
@@ -58,7 +58,7 @@ CardLayout::Input threadInput()
CardLayout::Input in;
in.isMessage = false;
in.depth = 0;
- in.replyCount = 3;
+ in.messageCount = 3;
return in;
}
@@ -67,7 +67,7 @@ CardLayout::Input replyInput(int depth)
CardLayout::Input in;
in.isMessage = true;
in.depth = depth;
- in.replyCount = 0;
+ in.messageCount = 0;
return in;
}
@@ -91,7 +91,7 @@ void TestCardLayout::everyCardIsTheSameHeight()
const CardLayout deepReply =
CardLayout::compute(replyInput(3), QRect(0, 0, 400, thread), font);
CardLayout::Input noRepliesIn = threadInput();
- noRepliesIn.replyCount = 0;
+ noRepliesIn.messageCount = 0;
const CardLayout noReplies =
CardLayout::compute(noRepliesIn, QRect(0, 0, 400, thread), font);
@@ -225,7 +225,7 @@ void TestCardLayout::expanderIsEmptyWithoutReplies()
const QFont font;
const int h = CardLayout::heightFor(font);
CardLayout::Input in = threadInput();
- in.replyCount = 0;
+ in.messageCount = 0;
const CardLayout card = CardLayout::compute(in, QRect(0, 0, 400, h), font);
QVERIFY(card.expanderRect.isEmpty());
@@ -240,12 +240,12 @@ void TestCardLayout::theExpanderReadsAsAPillWithAWord()
// NO triangle in the label since item 70: it is a drawn mark now, and a
// glyph left here would be a second triangle beside the drawn one. The
// label is the words alone, and the state no longer changes it.
- QCOMPARE(CardLayout::expanderLabel(3, false), QStringLiteral("3 replies"));
- QCOMPARE(CardLayout::expanderLabel(3, true), QStringLiteral("3 replies"));
+ QCOMPARE(CardLayout::expanderLabel(3, false), QStringLiteral("3 messages"));
+ QCOMPARE(CardLayout::expanderLabel(3, true), QStringLiteral("3 messages"));
- // Singular, because "1 replies" is the kind of detail that makes an
+ // Singular, because "1 messages" is the kind of detail that makes an
// interface look unfinished.
- QCOMPARE(CardLayout::expanderLabel(1, false), QStringLiteral("1 reply"));
+ QCOMPARE(CardLayout::expanderLabel(1, false), QStringLiteral("1 message"));
// The glyphs are gone from the label entirely. Asserted rather than assumed,
// because a stray one would draw underneath the mark and look like a
@@ -377,7 +377,11 @@ void TestCardLayout::marksDoNotCollideWithEachOtherOrTheExpander()
// densest line two can get. Nothing may overlap anything.
const QFont font;
const int h = CardLayout::heightFor(font);
- const QRect rect(0, 0, 400, h);
+ // 460 rather than 400: the pill reads "3 messages" now, a character wider
+ // than "3 replies" was, and 400 left the elastic subject narrower than the
+ // avatar gutter with all four marks out. The width is a stress value, not
+ // a spec.
+ const QRect rect(0, 0, 460, h);
CardLayout::Input in = threadInput();
in.flagged = true;
@@ -421,7 +425,7 @@ void TestCardLayout::marksDoNotCollideWithEachOtherOrTheExpander()
// not leave the subject narrower than the avatar gutter beside it.
QVERIFY2(card.subjectRect.width() > card.avatarRect.width(),
"four marks left the subject narrower than the avatar gutter on a "
- "400px card");
+ "460px card");
}
void TestCardLayout::dateIsFlushRight()
diff --git a/tests/test_mainwindow.cpp b/tests/test_mainwindow.cpp
index aecefb7..2e7d220 100644
--- a/tests/test_mainwindow.cpp
+++ b/tests/test_mainwindow.cpp
@@ -1396,10 +1396,11 @@ void TestMainWindow::aThreadWithRepliesDrawsAVisibleExpander()
const QModelIndex first = model->index(0, 0, QModelIndex());
const QModelIndex second = model->index(1, 0, QModelIndex());
- // Guards: the model agrees about which thread has replies, and only that
- // one is offered an expander at all.
- QCOMPARE(model->data(first, ThreadListModel::ReplyCountRole).toInt(), 2);
- QCOMPARE(model->data(second, ThreadListModel::ReplyCountRole).toInt(), 0);
+ // Guards: the model agrees about which thread has an expander, and only
+ // that one is offered one at all. The count is MESSAGES: the three-message
+ // thread reads 3, the lone message reads 0.
+ QCOMPARE(model->data(first, ThreadListModel::MessageCountRole).toInt(), 3);
+ QCOMPARE(model->data(second, ThreadListModel::MessageCountRole).toInt(), 0);
const QFont font = view->font();
const int height = CardLayout::heightFor(font);
diff --git a/tests/test_threadlistmodel.cpp b/tests/test_threadlistmodel.cpp
index fba2d2d..28d3a8b 100644
--- a/tests/test_threadlistmodel.cpp
+++ b/tests/test_threadlistmodel.cpp
@@ -49,7 +49,7 @@ private slots:
void appendingEmptyBatchIsNoOp();
void clearResetsModel();
void reportsSubjectAndAuthors();
- void theReplyCountExcludesTheRootMessage();
+ void thePillCountsTheThreadsMessages();
void unreadThreadsRenderBold();
void readThreadsAreDimmedAndUnreadAreNot();
void flaggedThreadsShowAStar();
@@ -519,7 +519,7 @@ void TestThreadListModel::aFlatViewsAvatarFollowsTheRecipient()
QStringLiteral("me@example.org"));
}
-void TestThreadListModel::theReplyCountExcludesTheRootMessage()
+void TestThreadListModel::thePillCountsTheThreadsMessages()
{
ThreadListModel model;
@@ -530,12 +530,14 @@ void TestThreadListModel::theReplyCountExcludesTheRootMessage()
model.appendBatch({ single, multi });
// The count used to be a "(4)" suffix on the subject. It is the expander
- // on the card's second line now, and it counts REPLIES: totalCount
- // includes the root message, which is the card itself.
+ // on the card's second line now, and it counts MESSAGES: the row stands
+ // for the conversation since item 177, so a thread of one message and
+ // three replies reads "4 messages". A thread of one shows nothing to
+ // expand, so its count stays 0.
QCOMPARE(model.data(model.index(0, 0),
- ThreadListModel::ReplyCountRole).toInt(), 0);
+ ThreadListModel::MessageCountRole).toInt(), 0);
QCOMPARE(model.data(model.index(1, 0),
- ThreadListModel::ReplyCountRole).toInt(), 3);
+ ThreadListModel::MessageCountRole).toInt(), 4);
// And the subject is bare, with no count spliced into it.
QCOMPARE(model.data(model.index(1, 0),
@@ -1483,9 +1485,9 @@ void TestThreadListModel::modelHasOneColumn()
QStringLiteral("alice@example.org"));
QVERIFY(index.data(ThreadListModel::DateRole).toDateTime().isValid());
- // A single-message thread offers no expander: totalCount includes the root
- // message, which is the card itself.
- QCOMPARE(index.data(ThreadListModel::ReplyCountRole).toInt(), 0);
+ // A single-message thread offers no expander: it is its own message and
+ // has nothing to open onto.
+ QCOMPARE(index.data(ThreadListModel::MessageCountRole).toInt(), 0);
}
void TestThreadListModel::aFlatThreadStillListsItsReplies()
@@ -1520,12 +1522,11 @@ void TestThreadListModel::aFlatThreadStillListsItsReplies()
.toString(),
QStringLiteral("m1@example.org"));
- // The pill counts REPLIES while the rows are MESSAGES, so since item 177
- // the rows are one more than the pill: the conversation lists its first
- // message too. They must still move together, or the expander opens onto a
- // number the card never promised.
- QCOMPARE(root.data(ThreadListModel::ReplyCountRole).toInt(),
- model.rowCount(root) - 1);
+ // The pill counts MESSAGES, which is exactly what the rows are: since item
+ // 177 a conversation lists every message under itself, so the number on
+ // the card and the number of rows it opens onto agree.
+ QCOMPARE(root.data(ThreadListModel::MessageCountRole).toInt(),
+ model.rowCount(root));
}
void TestThreadListModel::theRootCardKnowsItsOwnMessage()
@@ -1893,7 +1894,7 @@ void TestThreadListModel::flatModeOffersNoExpanderAndNoReplyCount()
// the replies they received under a view that claims to be their outbox.
//
// Deliberately not a second model or a filtered query. The expander is
- // driven by hasChildren() and the card's count by ReplyCountRole, both
+ // driven by hasChildren() and the card's count by MessageCountRole, both
// already here, so flat mode is those two answering differently.
ThreadListModel model;
model.appendBatch({ makeThread(QStringLiteral("t1"),
@@ -1906,13 +1907,13 @@ void TestThreadListModel::flatModeOffersNoExpanderAndNoReplyCount()
// below: a test whose subject was already flat would pass either way.
QVERIFY2(model.hasChildren(thread),
"the fixture thread is not expandable, so this proves nothing");
- QCOMPARE(model.data(thread, ThreadListModel::ReplyCountRole).toInt(), 1);
+ QCOMPARE(model.data(thread, ThreadListModel::MessageCountRole).toInt(), 2);
model.setFlatMode(true);
QVERIFY2(!model.hasChildren(thread),
"a flat list still offered an expander");
- QCOMPARE(model.data(thread, ThreadListModel::ReplyCountRole).toInt(), 0);
+ QCOMPARE(model.data(thread, ThreadListModel::MessageCountRole).toInt(), 0);
// rowCount has to agree, or the view draws an expander it cannot open, or
// opens onto rows the card said were not there.
@@ -1943,7 +1944,7 @@ void TestThreadListModel::flatModeIsOffByDefaultAndReversible()
model.setFlatMode(false);
QVERIFY2(model.hasChildren(thread),
"leaving flat mode did not restore the tree");
- QCOMPARE(model.data(thread, ThreadListModel::ReplyCountRole).toInt(), 1);
+ QCOMPARE(model.data(thread, ThreadListModel::MessageCountRole).toInt(), 2);
}
void TestThreadListModel::recipientsReplaceTheSenderWhenPresent()
diff --git a/translations/qtmaildir_it_IT.ts b/translations/qtmaildir_it_IT.ts
index d158380..5249149 100644
--- a/translations/qtmaildir_it_IT.ts
+++ b/translations/qtmaildir_it_IT.ts
@@ -2,6 +2,17 @@
<!DOCTYPE TS>
<TS version="2.1" language="it_IT">
<context>
+ <name>CardLayout</name>
+ <message>
+ <source>message</source>
+ <translation>messaggio</translation>
+ </message>
+ <message>
+ <source>messages</source>
+ <translation>messaggi</translation>
+ </message>
+</context>
+<context>
<name>ComposeWindow</name>
<message>
<source>Compose[*]</source>