Git commit 4566a329aeb79adbcfe745c678c2dbdb16499754 by Jan Kundr?t. Committed on 03/05/2013 at 15:30. Pushed by jkt into branch 'master'.
GUI: refactor the message envelope widget into a standalone class A +139 -0 src/Gui/EnvelopeView.cpp [License: GPL (v2/3)] A +51 -0 src/Gui/EnvelopeView.h [License: GPL (v2/3)] M +4 -2 src/Gui/Gui.pro M +7 -108 src/Gui/MessageView.cpp M +2 -3 src/Gui/MessageView.h http://commits.kde.org/trojita/4566a329aeb79adbcfe745c678c2dbdb16499754 diff --git a/src/Gui/EnvelopeView.cpp b/src/Gui/EnvelopeView.cpp new file mode 100644 index 0000000..4322deb --- /dev/null +++ b/src/Gui/EnvelopeView.cpp @@ -0,0 +1,139 @@ +/* Copyright (C) 2006 - 2013 Jan Kundr?t <jkt at flaska.net> + + This file is part of the Trojita Qt IMAP e-mail client, + http://trojita.flaska.net/ + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License or (at your option) version 3 or any later version + accepted by the membership of KDE e.V. (or its successor approved + by the membership of KDE e.V.), which shall act as a proxy + defined in Section 14 of version 3 of the license. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "EnvelopeView.h" +#include <QHeaderView> +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) +# include <QTextDocument> +#else +# include <QUrlQuery> +#endif +#include "Imap/Model/ItemRoles.h" +#include "Imap/Model/MailboxTree.h" +#include "Imap/Model/Model.h" + +namespace Gui { + +EnvelopeView::EnvelopeView(QWidget *parent): QLabel(parent) +{ + // we create a dummy header, pass it through the style and the use it's color roles so we + // know what headers in general look like in the system + QHeaderView helpingHeader(Qt::Horizontal); + helpingHeader.ensurePolished(); + + setBackgroundRole(helpingHeader.backgroundRole()); + setForegroundRole(helpingHeader.foregroundRole()); + setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse); + setIndent(5); + setWordWrap(true); + connect(this, SIGNAL(linkHovered(QString)), this, SLOT(onLinkHovered(QString))); +} + +/** @short */ +void EnvelopeView::setMessage(const QModelIndex &index) +{ + setText(headerText(index)); +} + +QString EnvelopeView::headerText(const QModelIndex &index) +{ + if (!index.isValid()) + return QString(); + + const Imap::Message::Envelope e = index.data(Imap::Mailbox::RoleMessageEnvelope).value<Imap::Message::Envelope>(); + + QString res; + if (!e.from.isEmpty()) + res += tr("<b>From:</b> %1<br/>").arg(Imap::Message::MailAddress::prettyList(e.from, Imap::Message::MailAddress::FORMAT_CLICKABLE)); + if (!e.sender.isEmpty() && e.sender != e.from) + res += tr("<b>Sender:</b> %1<br/>").arg(Imap::Message::MailAddress::prettyList(e.sender, Imap::Message::MailAddress::FORMAT_CLICKABLE)); + if (!e.replyTo.isEmpty() && e.replyTo != e.from) + res += tr("<b>Reply-To:</b> %1<br/>").arg(Imap::Message::MailAddress::prettyList(e.replyTo, Imap::Message::MailAddress::FORMAT_CLICKABLE)); + QVariantList headerListPost = index.data(Imap::Mailbox::RoleMessageHeaderListPost).toList(); + if (!headerListPost.isEmpty()) { + QStringList buf; + Q_FOREACH(const QVariant &item, headerListPost) { + const QString scheme = item.toUrl().scheme().toLower(); + if (scheme == QLatin1String("http") || scheme == QLatin1String("https") || scheme == QLatin1String("mailto")) { + QString target = item.toUrl().toString(); + QString caption = item.toUrl().toString(scheme == QLatin1String("mailto") ? QUrl::RemoveScheme : QUrl::None); +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) + target = Qt::escape(target); + caption = Qt::escape(caption); +#else + target = target.toHtmlEscaped(); + caption = caption.toHtmlEscaped(); +#endif + buf << tr("<a href=\"%1\">%2</a>").arg(target, caption); + } else { +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) + buf << Qt::escape(item.toUrl().toString()); +#else + buf << item.toUrl().toString().toHtmlEscaped(); +#endif + } + } + res += tr("<b>List-Post:</b> %1<br/>").arg(buf.join(tr(", "))); + } + if (!e.to.isEmpty()) + res += tr("<b>To:</b> %1<br/>").arg(Imap::Message::MailAddress::prettyList(e.to, Imap::Message::MailAddress::FORMAT_CLICKABLE)); + if (!e.cc.isEmpty()) + res += tr("<b>Cc:</b> %1<br/>").arg(Imap::Message::MailAddress::prettyList(e.cc, Imap::Message::MailAddress::FORMAT_CLICKABLE)); + if (!e.bcc.isEmpty()) + res += tr("<b>Bcc:</b> %1<br/>").arg(Imap::Message::MailAddress::prettyList(e.bcc, Imap::Message::MailAddress::FORMAT_CLICKABLE)); +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) + res += tr("<b>Subject:</b> %1").arg(Qt::escape(e.subject)); +#else + res += tr("<b>Subject:</b> %1").arg(e.subject.toHtmlEscaped()); +#endif + if (e.date.isValid()) + res += tr("<br/><b>Date:</b> %1").arg(e.date.toLocalTime().toString(Qt::SystemLocaleLongDate)); + return res; +} + +void EnvelopeView::onLinkHovered(const QString &target) +{ + QUrl url(target); + + if (target.isEmpty() || url.scheme().toLower() != QLatin1String("mailto")) { + setToolTip(QString()); + return; + } + + QString frontOfAtSign, afterAtSign; + if (url.path().indexOf(QLatin1String("@")) != -1) { + QStringList chunks = url.path().split(QLatin1String("@")); + frontOfAtSign = chunks[0]; + afterAtSign = QStringList(chunks.mid(1)).join(QLatin1String("@")); + } +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) + Imap::Message::MailAddress addr(url.queryItemValue(QLatin1String("X-Trojita-DisplayName")), QString(), + frontOfAtSign, afterAtSign); + setToolTip(Qt::escape(addr.prettyName(Imap::Message::MailAddress::FORMAT_READABLE))); +#else + QUrlQuery q(url); + Imap::Message::MailAddress addr(q.queryItemValue(QLatin1String("X-Trojita-DisplayName")), QString(), + frontOfAtSign, afterAtSign); + setToolTip(addr.prettyName(Imap::Message::MailAddress::FORMAT_READABLE).toHtmlEscaped()); +#endif +} + +} diff --git a/src/Gui/EnvelopeView.h b/src/Gui/EnvelopeView.h new file mode 100644 index 0000000..699825b --- /dev/null +++ b/src/Gui/EnvelopeView.h @@ -0,0 +1,51 @@ +/* Copyright (C) 2006 - 2013 Jan Kundr?t <jkt at flaska.net> + + This file is part of the Trojita Qt IMAP e-mail client, + http://trojita.flaska.net/ + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License or (at your option) version 3 or any later version + accepted by the membership of KDE e.V. (or its successor approved + by the membership of KDE e.V.), which shall act as a proxy + defined in Section 14 of version 3 of the license. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#ifndef GUI_ENVELOPEVIEW_H +#define GUI_ENVELOPEVIEW_H + +#include <QModelIndex> +#include <QLabel> + +namespace Gui { + +/** @short Widget displaying the message envelope */ +class EnvelopeView : public QLabel +{ + Q_OBJECT +public: + explicit EnvelopeView(QWidget *parent=0); + + void setMessage(const QModelIndex &index); + +private slots: + void onLinkHovered(const QString &target); + +private: + QString headerText(const QModelIndex &index); + + EnvelopeView(const EnvelopeView &); // don't implement + EnvelopeView &operator=(const EnvelopeView &); // don't implement +}; + +} + +#endif // GUI_ENVELOPEVIEW_H diff --git a/src/Gui/Gui.pro b/src/Gui/Gui.pro index 25c01b3..2cb70b9 100644 --- a/src/Gui/Gui.pro +++ b/src/Gui/Gui.pro @@ -57,7 +57,8 @@ SOURCES += \ LineEdit.cpp \ PasswordDialog.cpp \ ProgressPopUp.cpp \ - OverlayWidget.cpp + OverlayWidget.cpp \ + EnvelopeView.cpp HEADERS += \ ../Imap/Model/ModelTest/modeltest.h \ ComposeWidget.h \ @@ -100,7 +101,8 @@ HEADERS += \ LineEdit.h \ PasswordDialog.h \ ProgressPopUp.h \ - OverlayWidget.h + OverlayWidget.h \ + EnvelopeView.h FORMS += CreateMailboxDialog.ui \ ComposeWidget.ui \ SettingsImapPage.ui \ diff --git a/src/Gui/MessageView.cpp b/src/Gui/MessageView.cpp index d6fa19d..08f89dc 100644 --- a/src/Gui/MessageView.cpp +++ b/src/Gui/MessageView.cpp @@ -23,15 +23,10 @@ #include <QDesktopServices> #include <QHeaderView> #include <QKeyEvent> -#include <QLabel> #include <QMenu> #include <QMessageBox> -#include <QTextDocument> #include <QTimer> #include <QUrl> -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) -#include <QUrlQuery> -#endif #include <QVBoxLayout> #include <QWebFrame> #include <QWebHistory> @@ -42,6 +37,7 @@ #include "AbstractPartWidget.h" #include "Composer/SubjectMangling.h" #include "EmbeddedWebView.h" +#include "EnvelopeView.h" #include "ExternalElementsWidget.h" #include "PartWidgetFactory.h" #include "SimplePartWidget.h" @@ -93,14 +89,8 @@ MessageView::MessageView(QWidget *parent): QWidget(parent) headerSection->setAutoFillBackground(true); // the actual mail header - header = new QLabel(headerSection); - header->setBackgroundRole(helpingHeader.backgroundRole()); - header->setForegroundRole(helpingHeader.foregroundRole()); - header->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse); - header->setIndent(5); - header->setWordWrap(true); - connect(header, SIGNAL(linkHovered(QString)), this, SLOT(linkInTitleHovered(QString))); - connect(header, SIGNAL(linkActivated(QString)), this, SLOT(headerLinkActivated(QString))); + m_envelope = new EnvelopeView(headerSection); + connect(m_envelope, SIGNAL(linkActivated(QString)), this, SLOT(headerLinkActivated(QString))); // the tag bar tags = new TagListWidget(headerSection); @@ -117,7 +107,7 @@ MessageView::MessageView(QWidget *parent): QWidget(parent) // layout the header layout = new QVBoxLayout(headerSection); - layout->addWidget(header, 1); + layout->addWidget(m_envelope, 1); layout->addWidget(tags, 3); layout->addWidget(externalElements, 1); @@ -170,7 +160,7 @@ MessageView::~MessageView() void MessageView::setEmpty() { markAsReadTimer->stop(); - header->setText(QString()); + m_envelope->setMessage(QModelIndex()); headerSection->hide(); message = QModelIndex(); disconnect(this, SLOT(handleDataChanged(QModelIndex,QModelIndex))); @@ -229,7 +219,7 @@ void MessageView::setMessage(const QModelIndex &index) viewer->setParent(this); layout->addWidget(viewer); viewer->show(); - header->setText(headerText()); + m_envelope->setMessage(message); tags->show(); tags->setTagList(messageIndex.data(Imap::Mailbox::RoleMessageFlags).toStringList()); @@ -289,70 +279,6 @@ bool MessageView::eventFilter(QObject *object, QEvent *event) } } -Imap::Message::Envelope MessageView::envelope() const -{ - // Accessing the envelope via QVariant is just too much work here; it's way easier to just get the raw pointer - Imap::Mailbox::Model *model = dynamic_cast<Imap::Mailbox::Model *>(const_cast<QAbstractItemModel *>(message.model())); - Imap::Mailbox::TreeItemMessage *messagePtr = dynamic_cast<Imap::Mailbox::TreeItemMessage *>(static_cast<Imap::Mailbox::TreeItem *>(message.internalPointer())); - return messagePtr->envelope(model); -} - -QString MessageView::headerText() -{ - if (!message.isValid()) - return QString(); - - const Imap::Message::Envelope &e = envelope(); - - QString res; - if (!e.from.isEmpty()) - res += tr("<b>From:</b> %1<br/>").arg(Imap::Message::MailAddress::prettyList(e.from, Imap::Message::MailAddress::FORMAT_CLICKABLE)); - if (!e.sender.isEmpty() && e.sender != e.from) - res += tr("<b>Sender:</b> %1<br/>").arg(Imap::Message::MailAddress::prettyList(e.sender, Imap::Message::MailAddress::FORMAT_CLICKABLE)); - if (!e.replyTo.isEmpty() && e.replyTo != e.from) - res += tr("<b>Reply-To:</b> %1<br/>").arg(Imap::Message::MailAddress::prettyList(e.replyTo, Imap::Message::MailAddress::FORMAT_CLICKABLE)); - QVariantList headerListPost = message.data(Imap::Mailbox::RoleMessageHeaderListPost).toList(); - if (!headerListPost.isEmpty()) { - QStringList buf; - Q_FOREACH(const QVariant &item, headerListPost) { - const QString scheme = item.toUrl().scheme().toLower(); - if (scheme == QLatin1String("http") || scheme == QLatin1String("https") || scheme == QLatin1String("mailto")) { - QString target = item.toUrl().toString(); - QString caption = item.toUrl().toString(scheme == QLatin1String("mailto") ? QUrl::RemoveScheme : QUrl::None); -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - target = Qt::escape(target); - caption = Qt::escape(caption); -#else - target = target.toHtmlEscaped(); - caption = caption.toHtmlEscaped(); -#endif - buf << tr("<a href=\"%1\">%2</a>").arg(target, caption); - } else { -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - buf << Qt::escape(item.toUrl().toString()); -#else - buf << item.toUrl().toString().toHtmlEscaped(); -#endif - } - } - res += tr("<b>List-Post:</b> %1<br/>").arg(buf.join(tr(", "))); - } - if (!e.to.isEmpty()) - res += tr("<b>To:</b> %1<br/>").arg(Imap::Message::MailAddress::prettyList(e.to, Imap::Message::MailAddress::FORMAT_CLICKABLE)); - if (!e.cc.isEmpty()) - res += tr("<b>Cc:</b> %1<br/>").arg(Imap::Message::MailAddress::prettyList(e.cc, Imap::Message::MailAddress::FORMAT_CLICKABLE)); - if (!e.bcc.isEmpty()) - res += tr("<b>Bcc:</b> %1<br/>").arg(Imap::Message::MailAddress::prettyList(e.bcc, Imap::Message::MailAddress::FORMAT_CLICKABLE)); -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - res += tr("<b>Subject:</b> %1").arg(Qt::escape(e.subject)); -#else - res += tr("<b>Subject:</b> %1").arg(e.subject.toHtmlEscaped()); -#endif - if (e.date.isValid()) - res += tr("<br/><b>Date:</b> %1").arg(e.date.toLocalTime().toString(Qt::SystemLocaleLongDate)); - return res; -} - QString MessageView::quoteText() const { if (const AbstractPartWidget *w = dynamic_cast<const AbstractPartWidget *>(viewer)) { @@ -408,7 +334,7 @@ QString MessageView::quoteText() const } quote << quotemarks + line->mid(lastSpace); } - const Imap::Message::Envelope &e = envelope(); + const Imap::Message::Envelope &e = message.data(Imap::Mailbox::RoleMessageEnvelope).value<Imap::Message::Envelope>(); QString sender; if (!e.from.isEmpty()) sender = e.from[0].prettyName(Imap::Message::MailAddress::FORMAT_JUST_NAME); @@ -476,33 +402,6 @@ void MessageView::externalsEnabled() w->reloadContents(); } -void MessageView::linkInTitleHovered(const QString &target) -{ - QUrl url(target); - - if (target.isEmpty() || url.scheme().toLower() != QLatin1String("mailto")) { - header->setToolTip(QString()); - return; - } - - QString frontOfAtSign, afterAtSign; - if (url.path().indexOf(QLatin1String("@")) != -1) { - QStringList chunks = url.path().split(QLatin1String("@")); - frontOfAtSign = chunks[0]; - afterAtSign = QStringList(chunks.mid(1)).join(QLatin1String("@")); - } -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - Imap::Message::MailAddress addr(url.queryItemValue(QLatin1String("X-Trojita-DisplayName")), QString(), - frontOfAtSign, afterAtSign); - header->setToolTip(Qt::escape(addr.prettyName(Imap::Message::MailAddress::FORMAT_READABLE))); -#else - QUrlQuery q(url); - Imap::Message::MailAddress addr(q.queryItemValue(QLatin1String("X-Trojita-DisplayName")), QString(), - frontOfAtSign, afterAtSign); - header->setToolTip(addr.prettyName(Imap::Message::MailAddress::FORMAT_READABLE).toHtmlEscaped()); -#endif -} - void MessageView::newLabelAction(const QString &tag) { if (!message.isValid()) diff --git a/src/Gui/MessageView.h b/src/Gui/MessageView.h index 41dcf15..bdbad36 100644 --- a/src/Gui/MessageView.h +++ b/src/Gui/MessageView.h @@ -48,6 +48,7 @@ class Envelope; namespace Gui { +class EnvelopeView; class MainWindow; class PartWidgetFactory; class ExternalElementsWidget; @@ -78,7 +79,6 @@ private slots: void markAsRead(); void externalsRequested(const QUrl &url); void externalsEnabled(); - void linkInTitleHovered(const QString &target); void newLabelAction(const QString &tag); void deleteLabelAction(const QString &tag); void handleDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); @@ -93,12 +93,11 @@ signals: private: bool eventFilter(QObject *object, QEvent *event); Imap::Message::Envelope envelope() const; - QString headerText(); QString quoteText() const; QWidget *viewer; QWidget *headerSection; - QLabel *header; + EnvelopeView *m_envelope; ExternalElementsWidget *externalElements; QBoxLayout *layout; TagListWidget *tags;
