7#include "grantleeheaderformatter.h"
8#include "headerstyle_util.h"
9#include "settings/messageviewersettings.h"
10#include "utils/iconnamecache.h"
12#include <MessageCore/StringUtil>
13#include <MimeTreeParser/NodeHelper>
15#include <KMime/Message>
17#include <KColorScheme>
19#include <KLocalizedString>
20#include <KTextTemplate/Engine>
21#include <KTextTemplate/MetaType>
23using namespace MessageCore;
25using namespace MessageViewer;
41 return StringUtil::emailAddrAsAnchor(
object, StringUtil::DisplayNameOnly);
43 return !
object->asUnicodeString().isEmpty();
45 return StringUtil::emailAddrAsAnchor(
object, StringUtil::DisplayFullAddress);
47 return object->asUnicodeString();
49 const auto &
name =
property.
mid(10);
50 const QString val = MessageCore::StringUtil::emailAddrAsAnchor(
object,
51 MessageCore::StringUtil::DisplayFullAddress,
53 MessageCore::StringUtil::ShowLink,
54 MessageCore::StringUtil::ExpandableAddresses,
55 QStringLiteral(
"Full") + name + QStringLiteral(
"AddressList"));
69 return StringUtil::emailAddrAsAnchor(
object.data(), StringUtil::DisplayNameOnly);
71 return !
object->asUnicodeString().isEmpty();
73 return StringUtil::emailAddrAsAnchor(
object.data(), StringUtil::DisplayFullAddress);
75 return object->asUnicodeString();
77 const auto &
name =
property.
mid(10);
78 const QString val = MessageCore::StringUtil::emailAddrAsAnchor(
object.data(),
79 MessageCore::StringUtil::DisplayFullAddress,
81 MessageCore::StringUtil::ShowLink,
82 MessageCore::StringUtil::ExpandableAddresses,
83 QStringLiteral(
"Full") + name + QStringLiteral(
"AddressList"));
96 return StringUtil::emailAddrAsAnchor(
object, StringUtil::DisplayNameOnly);
98 return !
object->asUnicodeString().isEmpty();
100 return StringUtil::emailAddrAsAnchor(
object, StringUtil::DisplayFullAddress);
102 return object->asUnicodeString();
104 const auto &
name =
property.
mid(10);
105 const QString val = MessageCore::StringUtil::emailAddrAsAnchor(
object,
106 MessageCore::StringUtil::DisplayFullAddress,
108 MessageCore::StringUtil::ShowLink,
109 MessageCore::StringUtil::ExpandableAddresses,
110 QStringLiteral(
"Full") + name + QStringLiteral(
"AddressList"));
118 return StringUtil::emailAddrAsAnchor(
object.data(), StringUtil::DisplayNameOnly);
120 return !
object->asUnicodeString().isEmpty();
122 return StringUtil::emailAddrAsAnchor(
object.data(), StringUtil::DisplayFullAddress);
124 return object->asUnicodeString();
126 const auto &
name =
property.
mid(10);
127 const QString val = MessageCore::StringUtil::emailAddrAsAnchor(
object.data(),
128 MessageCore::StringUtil::DisplayFullAddress,
130 MessageCore::StringUtil::ShowLink,
131 MessageCore::StringUtil::ExpandableAddresses,
132 QStringLiteral(
"Full") + name + QStringLiteral(
"AddressList"));
143 return HeaderStyleUtil::dateStr(
object);
158 return HeaderStyleUtil::strToHtml(HeaderStyleUtil::dateString(
object, dateFormat));
162class Q_DECL_HIDDEN HeaderFormatter
165 virtual ~HeaderFormatter() =
default;
168 virtual QString i18nName() = 0;
171class DefaultHeaderFormatter :
public HeaderFormatter
181 if (header ==
"list-id") {
182 return i18n(
"List-Id:");
190 Q_UNUSED(showEmoticons);
198class SubjectFormatter :
public HeaderFormatter
203 return i18n(
"Subject:");
212 const auto subjectStr = nodeHelper->mailHeaderAsBase(
"subject", message)->
asUnicodeString();
214 return HeaderStyleUtil::strToHtml(subjectStr, flags);
223 return i18n(
"Date:");
228 Q_UNUSED(showEmoticons);
229 const auto value = nodeHelper->dateHeader(message);
234class MessageIdFormatter :
public HeaderFormatter
239 return i18n(
"Message-Id:");
244 const auto messageIdHeader = nodeHelper->mailHeaderAsBase(
"Message-Id", message);
245 if (messageIdHeader !=
nullptr) {
252class AddressHeaderFormatter :
public HeaderFormatter
262 if (header ==
"to") {
264 }
else if (header ==
"reply-To") {
265 return i18n(
"Reply To:");
266 }
else if (header ==
"cc") {
268 }
else if (header ==
"bcc") {
270 }
else if (header ==
"from") {
271 return i18n(
"From:");
272 }
else if (header ==
"sender") {
273 return i18n(
"Sender:");
274 }
else if (header ==
"resent-From") {
275 return i18n(
"resent from:");
276 }
else if (header ==
"resent-To") {
277 return i18n(
"resent to:");
285 Q_UNUSED(showEmoticons);
286 const auto value = nodeHelper->mailHeaderAsAddressList(header.
constData(), message);
294class MessageViewer::GrantleeHeaderFormatter::GrantleeHeaderFormatterPrivate
297 GrantleeHeaderFormatterPrivate()
311 addressHeaders <<
"to"
320 for (
const auto &header : std::as_const(addressHeaders)) {
329 ~GrantleeHeaderFormatterPrivate()
336 headerFormatter[header] = formatter;
347GrantleeHeaderFormatter::GrantleeHeaderFormatter()
352GrantleeHeaderFormatter::~GrantleeHeaderFormatter() =
default;
354QString GrantleeHeaderFormatter::toHtml(
const GrantleeHeaderFormatter::GrantleeHeaderFormatterSettings &settings)
const
357 if (!settings.theme.isValid()) {
358 errorMessage =
i18n(
"Grantlee theme \"%1\" is not valid.", settings.theme.name());
361 d->templateLoader->setTemplateDirs(
QStringList() << settings.theme.absolutePath());
363 if (headerTemplate->
error()) {
367 return format(settings.theme.absolutePath(),
369 settings.theme.displayExtraVariables(),
373 settings.showEmoticons);
381 bool isPrinting)
const
383 d->templateLoader->setTemplateDirs(
QStringList() << absolutPath);
385 if (headerTemplate->
error()) {
388 return format(absolutPath, headerTemplate, displayExtraHeaders, isPrinting, style, message);
391QString GrantleeHeaderFormatter::format(
const QString &absolutePath,
397 bool showEmoticons)
const
399 QVariantHash headerObject;
400 const auto nodeHelper = style->nodeHelper();
408 headerObject.
insert(QStringLiteral(
"absoluteThemePath"), absoluteThemePath);
412 headerObject.
insert(QStringLiteral(
"subjectDir"), d->headerStyleUtil.subjectDirectionString(message));
415 defaultHeaders <<
"to"
429 for (
const auto &header : std::as_const(defaultHeaders)) {
431 if (d->headerFormatter.contains(header)) {
432 formatter = d->headerFormatter.value(header);
436 const auto i18nName = formatter->i18nName();
438 if (nodeHelper->hasMailHeader(header.constData(), message)) {
439 const auto value = formatter->format(message, nodeHelper, showEmoticons);
440 headerObject.insert(objectName, value);
442 if (!i18nName.isEmpty()) {
443 headerObject.insert(objectName + QStringLiteral(
"i18n"), i18nName);
447 if (!nodeHelper->hasMailHeader(
"subject", message)) {
448 headerObject.insert(QStringLiteral(
"subject"),
i18n(
"No Subject"));
451 const QString spamHtml = d->headerStyleUtil.spamStatus(message);
453 headerObject.insert(QStringLiteral(
"spamstatusi18n"),
i18n(
"Spam Status:"));
454 headerObject.insert(QStringLiteral(
"spamHTML"), spamHtml);
457 if (!style->vCardName().
isEmpty()) {
458 headerObject.insert(QStringLiteral(
"vcardname"), style->vCardName());
465 headerObject.insert(QStringLiteral(
"isprinting"),
i18n(
"Printing mode"));
466 headerObject.insert(QStringLiteral(
"printmode"), QStringLiteral(
"printmode"));
468 headerObject.insert(QStringLiteral(
"screenmode"), QStringLiteral(
"screenmode"));
473 QString linkColor = QStringLiteral(
"white");
475 if (!d->activeColor.isValid()) {
478 QColor activeColorDark = d->activeColor.darker(130);
480 if (!style->isTopLevel()) {
481 activeColorDark = d->activeColor.darker(50);
483 linkColor = QStringLiteral(
"black");
487 headerObject.insert(QStringLiteral(
"activecolordark"), activeColorDark.
name());
488 headerObject.insert(QStringLiteral(
"fontcolor"), fontColor.name());
489 headerObject.insert(QStringLiteral(
"linkcolor"), linkColor);
491 MessageViewer::HeaderStyleUtil::xfaceSettings xface = d->headerStyleUtil.xface(style, message);
492 if (!xface.photoURL.
isEmpty()) {
493 headerObject.insert(QStringLiteral(
"photowidth"), xface.photoWidth);
494 headerObject.insert(QStringLiteral(
"photoheight"), xface.photoHeight);
495 headerObject.insert(QStringLiteral(
"photourl"), xface.photoURL);
498 for (
QString header : std::as_const(displayExtraHeaders)) {
499 const QByteArray baHeader = header.toLocal8Bit();
500 if (
auto hrd = message->headerByType(baHeader.
constData())) {
503 headerObject.insert(header, hrd->asUnicodeString());
507 headerObject.insert(QStringLiteral(
"vcardi18n"),
i18n(
"[vcard]"));
508 headerObject.insert(QStringLiteral(
"readOnlyMessage"), style->readOnlyMessage());
510 const QString attachmentHtml = style->attachmentHtml();
511 const bool messageHasAttachment = !attachmentHtml.
isEmpty();
512 headerObject.insert(QStringLiteral(
"hasAttachment"), messageHasAttachment);
513 headerObject.insert(QStringLiteral(
"attachmentHtml"), attachmentHtml);
514 headerObject.insert(QStringLiteral(
"attachmentI18n"),
i18n(
"Attachments:"));
516 if (messageHasAttachment) {
517 const QString iconPath = MessageViewer::IconNameCache::instance()->iconPath(QStringLiteral(
"mail-attachment"),
KIconLoader::Toolbar);
518 const QString html = QStringLiteral(
"<img height=\"%2\" width=\"%2\" src=\"%1\"></a>").
arg(iconPath,
QString::number(d->iconSize));
519 headerObject.
insert(QStringLiteral(
"attachmentIcon"), html);
522 const bool messageIsSigned = KMime::isSigned(message);
523 headerObject.insert(QStringLiteral(
"messageIsSigned"), messageIsSigned);
524 if (messageIsSigned) {
526 const QString html = QStringLiteral(
"<img height=\"%2\" width=\"%2\" src=\"%1\"></a>").
arg(iconPath,
QString::number(d->iconSize));
527 headerObject.
insert(QStringLiteral(
"signedIcon"), html);
530 const bool messageIsEncrypted = KMime::isEncrypted(message);
531 headerObject.insert(QStringLiteral(
"messageIsEncrypted"), messageIsEncrypted);
532 if (messageIsEncrypted) {
533 const QString iconPath = MessageViewer::IconNameCache::instance()->iconPath(QStringLiteral(
"mail-encrypted"),
KIconLoader::Toolbar);
534 const QString html = QStringLiteral(
"<img height=\"%2\" width=\"%2\" src=\"%1\"></a>").
arg(iconPath,
QString::number(d->iconSize));
535 headerObject.
insert(QStringLiteral(
"encryptedIcon"), html);
538 const bool messageHasSecurityInfo = messageIsEncrypted || messageIsSigned;
539 headerObject.insert(QStringLiteral(
"messageHasSecurityInfo"), messageHasSecurityInfo);
540 headerObject.insert(QStringLiteral(
"messageHasSecurityInfoI18n"),
i18n(
"Security:"));
542 QVariantHash mapping;
543 mapping.insert(QStringLiteral(
"header"), headerObject);
546 return headerTemplate->
render(&context);
QBrush background(BackgroundRole=NormalBackground) const
int currentSize(KIconLoader::Group group) const
static KIconLoader * global()
void addTemplateLoader(QSharedPointer< AbstractTemplateLoader > loader)
QString errorString() const
QString render(Context *c) const
QString i18n(const char *text, const TYPE &arg...)
KCALUTILS_EXPORT QString errorMessage(const KCalendarCore::Exception &exception)
QString name(GameStandardAction id)
const QColor & color() const const
const char * constData() const const
QString name(NameFormat format) const const
QString arg(Args &&... args) const const
QString fromUtf8(QByteArrayView str)
QString & insert(qsizetype position, QChar ch)
bool isEmpty() const const
QString mid(qsizetype position, qsizetype n) const const
QString number(double n, char format, int precision)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QUrl fromLocalFile(const QString &localFile)
QString url(FormattingOptions options) const const
QVariant fromValue(T &&value)