summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/package/contents/ui/MailViewer.qml30
-rw-r--r--framework/domain/messageparser.cpp127
-rw-r--r--framework/domain/messageparser.h38
-rw-r--r--framework/domain/stringhtmlwriter.cpp5
-rw-r--r--framework/domain/stringhtmlwriter.h1
5 files changed, 175 insertions, 26 deletions
diff --git a/components/package/contents/ui/MailViewer.qml b/components/package/contents/ui/MailViewer.qml
index 771c6fa0..c51e2666 100644
--- a/components/package/contents/ui/MailViewer.qml
+++ b/components/package/contents/ui/MailViewer.qml
@@ -1,7 +1,6 @@
1import QtQuick 2.4 1import QtQuick 2.4
2import QtQuick.Controls 1.3 2import QtQuick.Controls 1.3
3import QtQuick.Layouts 1.1 3import QtQuick.Layouts 1.1
4import QtWebKit 3.0
5 4
6import org.kube.framework.domain 1.0 as KubeFramework 5import org.kube.framework.domain 1.0 as KubeFramework
7 6
@@ -10,29 +9,18 @@ Item {
10 property variant message; 9 property variant message;
11 property string html; 10 property string html;
12 11
13 WebView { 12 Rectangle {
14 id: webview 13 id: rootRectangle
15 anchors.fill: parent 14 anchors.fill: parent
16 onNavigationRequested: { 15 ScrollView {
17 // detect URL scheme prefix, most likely an external link 16 id: scrollView
18 var schemaRE = /^\w+:/; 17 anchors.fill: parent
19 if (schemaRE.test(request.url)) { 18 MessagePartTree {
20 request.action = WebView.AcceptRequest; 19 id: topPartLoader
21 } else { 20 width: rootRectangle.width
22 request.action = WebView.IgnoreRequest; 21 height: topPartLoader.desiredHeight
23 // delegate request.url here
24 } 22 }
25 } 23 }
26 onLoadingChanged: {
27 console.warn("Error is ", loadRequest.errorString);
28 console.warn("Status is ", loadRequest.status);
29 }
30 }
31
32 onHtmlChanged: {
33 // console.warn("HTML is ", html);
34 // The file:/// argument is necessary so local icons are found
35 webview.loadHtml(html, "file:///");
36 } 24 }
37 25
38 KubeFramework.MessageParser { 26 KubeFramework.MessageParser {
diff --git a/framework/domain/messageparser.cpp b/framework/domain/messageparser.cpp
index 7089e2d8..cdaf9db4 100644
--- a/framework/domain/messageparser.cpp
+++ b/framework/domain/messageparser.cpp
@@ -26,9 +26,117 @@
26#include <QImage> 26#include <QImage>
27#include <QDebug> 27#include <QDebug>
28#include <QTime> 28#include <QTime>
29#include <QUrl>
29#include <MimeTreeParser/ObjectTreeParser> 30#include <MimeTreeParser/ObjectTreeParser>
30#include <MimeTreeParser/MessagePart> 31#include <MimeTreeParser/MessagePart>
31 32
33PartModel::PartModel(QSharedPointer<MimeTreeParser::MessagePart> partTree, QMap<QByteArray, QUrl> embeddedPartMap) : mPartTree(partTree), mEmbeddedPartMap(embeddedPartMap)
34{
35}
36
37QHash<int, QByteArray> PartModel::roleNames() const
38{
39 QHash<int, QByteArray> roles;
40 roles[Text] = "text";
41 roles[IsHtml] = "isHtml";
42 roles[IsEncrypted] = "isEncrypted";
43 roles[IsAttachment] = "isAttachment";
44 roles[HasContent] = "hasContent";
45 roles[Type] = "type";
46 return roles;
47}
48
49QModelIndex PartModel::index(int row, int column, const QModelIndex &parent) const
50{
51 // qDebug() << "index " << parent << row << column << mPartTree->messageParts().size();
52 if (!parent.isValid()) {
53 if (row < mPartTree->messageParts().size()) {
54 auto part = mPartTree->messageParts().at(row);
55 return createIndex(row, column, part.data());
56 }
57 } else {
58 auto part = static_cast<MimeTreeParser::MessagePart*>(parent.internalPointer());
59 auto subPart = part->messageParts().at(row);
60 return createIndex(row, column, subPart.data());
61 }
62 return QModelIndex();
63}
64
65QVariant PartModel::data(const QModelIndex &index, int role) const
66{
67 // qDebug() << "Getting data for index";
68 if (index.isValid()) {
69 auto part = static_cast<MimeTreeParser::MessagePart*>(index.internalPointer());
70 switch (role) {
71 case Text: {
72 // qDebug() << "Getting text: " << part->property("text").toString();
73 // FIXME: we should have a list per part, and not one for all parts.
74 auto text = part->property("htmlContent").toString();
75 for (const auto &cid : mEmbeddedPartMap.keys()) {
76 text.replace(QString("src=\"cid:%1\"").arg(QString(cid)), QString("src=\"%1\"").arg(mEmbeddedPartMap.value(cid).toString()));
77 }
78 return text;
79 }
80 case IsAttachment:
81 return part->property("attachment").toBool();
82 case IsEncrypted:
83 return part->property("isEncrypted").toBool();
84 case IsHtml:
85 return part->property("isHtml").toBool();
86 case HasContent:
87 return !part->property("htmlContent").toString().isEmpty();
88 case Type:
89 return part->metaObject()->className();
90 }
91 }
92 return QVariant();
93}
94
95QModelIndex PartModel::parent(const QModelIndex &index) const
96{
97 // qDebug() << "parent " << index;
98 if (index.isValid()) {
99 auto part = static_cast<MimeTreeParser::MessagePart*>(index.internalPointer());
100 auto parentPart = static_cast<MimeTreeParser::MessagePart*>(part->parentPart());
101 auto row = 0;//get the parents parent to find the index
102 if (!parentPart) {
103 parentPart = mPartTree.data();
104 }
105 int i = 0;
106 for (const auto &p : parentPart->messageParts()) {
107 if (p.data() == part) {
108 row = i;
109 break;
110 }
111 i++;
112 }
113 return createIndex(row, index.column(), parentPart);
114 }
115 return QModelIndex();
116}
117
118int PartModel::rowCount(const QModelIndex &parent) const
119{
120 // qDebug() << "Row count " << parent;
121 if (!parent.isValid()) {
122 // qDebug() << "Row count " << mPartTree->messageParts().size();
123 return mPartTree->messageParts().size();
124 } else {
125 auto part = static_cast<MimeTreeParser::MessagePart*>(parent.internalPointer());
126 if (part) {
127 return part->messageParts().size();
128 }
129 }
130 return 0;
131}
132
133int PartModel::columnCount(const QModelIndex &parent) const
134{
135 // qDebug() << "Column count " << parent;
136 return 1;
137}
138
139
32MessageParser::MessageParser(QObject *parent) 140MessageParser::MessageParser(QObject *parent)
33 : QObject(parent) 141 : QObject(parent)
34{ 142{
@@ -64,20 +172,29 @@ void MessageParser::setMessage(const QVariant &message)
64 ObjectTreeSource source(&htmlWriter, &cssHelper); 172 ObjectTreeSource source(&htmlWriter, &cssHelper);
65 MimeTreeParser::ObjectTreeParser otp(&source, mNodeHelper.get()); 173 MimeTreeParser::ObjectTreeParser otp(&source, mNodeHelper.get());
66 174
67 const auto partTree = otp.parseToTree(msg.data()).dynamicCast<MimeTreeParser::MessagePartList>(); 175 mPartTree = otp.parseToTree(msg.data()).dynamicCast<MimeTreeParser::MessagePart>();
68 176
69 htmlWriter.begin(QString()); 177 htmlWriter.begin(QString());
70 htmlWriter.queue(cssHelper.htmlHead(false)); 178 htmlWriter.queue(cssHelper.htmlHead(false));
71 179
72 if (partTree) { 180 if (mPartTree) {
73 partTree->fix(); 181 mPartTree->fix();
74 partTree->copyContentFrom(); 182 mPartTree->copyContentFrom();
75 partTree->html(false); 183 mPartTree->html(false);
76 } 184 }
77 185
78 htmlWriter.queue(QStringLiteral("</body></html>")); 186 htmlWriter.queue(QStringLiteral("</body></html>"));
79 htmlWriter.end(); 187 htmlWriter.end();
80 188
189 mEmbeddedPartMap = htmlWriter.embeddedParts();
81 mHtml = htmlWriter.html(); 190 mHtml = htmlWriter.html();
82 emit htmlChanged(); 191 emit htmlChanged();
83} 192}
193
194QAbstractItemModel *MessageParser::partTree() const
195{
196 qDebug() << "Getting partTree";
197 qDebug() << "Row count " << mPartTree->messageParts().size();
198 return new PartModel(mPartTree, mEmbeddedPartMap);
199}
200
diff --git a/framework/domain/messageparser.h b/framework/domain/messageparser.h
index 72b55a5a..ac14fad9 100644
--- a/framework/domain/messageparser.h
+++ b/framework/domain/messageparser.h
@@ -22,17 +22,24 @@
22#include <QObject> 22#include <QObject>
23#include <QString> 23#include <QString>
24#include <QStringList> 24#include <QStringList>
25
26#include <QAbstractItemModel>
27#include <QModelIndex>
28
25#include <memory> 29#include <memory>
30#include <MimeTreeParser/MessagePart>
26 31
27namespace MimeTreeParser { 32namespace MimeTreeParser {
28 class NodeHelper; 33 class NodeHelper;
29}; 34};
35class QAbstractItemModel;
30 36
31class MessageParser : public QObject 37class MessageParser : public QObject
32{ 38{
33 Q_OBJECT 39 Q_OBJECT
34 Q_PROPERTY (QVariant message READ message WRITE setMessage) 40 Q_PROPERTY (QVariant message READ message WRITE setMessage)
35 Q_PROPERTY (QString html READ html NOTIFY htmlChanged) 41 Q_PROPERTY (QString html READ html NOTIFY htmlChanged)
42 Q_PROPERTY (QAbstractItemModel* partTree READ partTree NOTIFY htmlChanged)
36 43
37public: 44public:
38 explicit MessageParser(QObject *parent = Q_NULLPTR); 45 explicit MessageParser(QObject *parent = Q_NULLPTR);
@@ -41,11 +48,42 @@ public:
41 48
42 QVariant message() const; 49 QVariant message() const;
43 void setMessage(const QVariant &to); 50 void setMessage(const QVariant &to);
51 QAbstractItemModel *partTree() const;
44 52
45signals: 53signals:
46 void htmlChanged(); 54 void htmlChanged();
47 55
48private: 56private:
57 QSharedPointer<MimeTreeParser::MessagePart> mPartTree;
49 QString mHtml; 58 QString mHtml;
59 QMap<QByteArray, QUrl> mEmbeddedPartMap;
50 std::shared_ptr<MimeTreeParser::NodeHelper> mNodeHelper; 60 std::shared_ptr<MimeTreeParser::NodeHelper> mNodeHelper;
51}; 61};
62
63class PartModel : public QAbstractItemModel {
64 Q_OBJECT
65public:
66 PartModel(QSharedPointer<MimeTreeParser::MessagePart> partTree, QMap<QByteArray, QUrl> embeddedPartMap);
67
68public:
69 enum Roles {
70 Text = Qt::UserRole + 1,
71 IsHtml,
72 IsEncrypted,
73 IsAttachment,
74 HasContent,
75 Type
76 };
77
78 QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
79 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
80 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
81 QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
82 int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
83 int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
84
85private:
86 QSharedPointer<MimeTreeParser::MessagePart> mPartTree;
87 QMap<QByteArray, QUrl> mEmbeddedPartMap;
88};
89
diff --git a/framework/domain/stringhtmlwriter.cpp b/framework/domain/stringhtmlwriter.cpp
index b65c992f..88034492 100644
--- a/framework/domain/stringhtmlwriter.cpp
+++ b/framework/domain/stringhtmlwriter.cpp
@@ -136,6 +136,11 @@ void StringHtmlWriter::insertExtraHead()
136 } 136 }
137} 137}
138 138
139QMap<QByteArray, QUrl> StringHtmlWriter::embeddedParts() const
140{
141 return mEmbeddedPartMap;
142}
143
139QString StringHtmlWriter::html() const 144QString StringHtmlWriter::html() const
140{ 145{
141 if (mState != Ended) { 146 if (mState != Ended) {
diff --git a/framework/domain/stringhtmlwriter.h b/framework/domain/stringhtmlwriter.h
index c1410d57..fa5b760e 100644
--- a/framework/domain/stringhtmlwriter.h
+++ b/framework/domain/stringhtmlwriter.h
@@ -53,6 +53,7 @@ public:
53 void extraHead(const QString &str) Q_DECL_OVERRIDE; 53 void extraHead(const QString &str) Q_DECL_OVERRIDE;
54 54
55 QString html() const; 55 QString html() const;
56 QMap<QByteArray, QUrl> embeddedParts() const;
56private: 57private:
57 void insertExtraHead(); 58 void insertExtraHead();
58 void resolveCidUrls(); 59 void resolveCidUrls();