diff options
13 files changed, 176 insertions, 54 deletions
diff --git a/components/mailviewer/contents/ui/MailDataModel.qml b/components/mailviewer/contents/ui/MailDataModel.qml index 46427194..0f64972c 100644 --- a/components/mailviewer/contents/ui/MailDataModel.qml +++ b/components/mailviewer/contents/ui/MailDataModel.qml | |||
@@ -21,8 +21,7 @@ import QtQml.Models 2.2 | |||
21 | import org.kube.framework 1.0 as Kube | 21 | import org.kube.framework 1.0 as Kube |
22 | 22 | ||
23 | DelegateModel { | 23 | DelegateModel { |
24 | id: mailDataModel | 24 | id: root |
25 | property bool debug: true | ||
26 | 25 | ||
27 | delegate: Item { | 26 | delegate: Item { |
28 | id: partColumn | 27 | id: partColumn |
@@ -65,13 +64,13 @@ DelegateModel { | |||
65 | partLoader.setSource("TextContent.qml", | 64 | partLoader.setSource("TextContent.qml", |
66 | {"content": model.content, | 65 | {"content": model.content, |
67 | "embedded": model.embeded, | 66 | "embedded": model.embeded, |
68 | "type": model.type, | 67 | "type": model.type |
69 | "debug": debug}) | 68 | }) |
70 | break | 69 | break |
71 | case "html": | 70 | case "html": |
72 | partLoader.setSource("HtmlContent.qml", | 71 | partLoader.setSource("HtmlContent.qml", |
73 | {"content": model.content, | 72 | {"content": model.content, |
74 | "debug": debug}) | 73 | }) |
75 | break; | 74 | break; |
76 | case "error": | 75 | case "error": |
77 | partLoader.setSource("ErrorPart.qml", | 76 | partLoader.setSource("ErrorPart.qml", |
@@ -80,11 +79,13 @@ DelegateModel { | |||
80 | "errorString": model.errorString, | 79 | "errorString": model.errorString, |
81 | }) | 80 | }) |
82 | break; | 81 | break; |
83 | case "envelope": | 82 | case "encapsulated": |
84 | partLoader.setSource("MailPart.qml", | 83 | partLoader.setSource("MailPart.qml", |
85 | {"rootIndex": mailDataModel.modelIndex(index), | 84 | {"rootIndex": root.modelIndex(index), |
86 | "model": mailDataModel.model, | 85 | "model": root.model, |
87 | "debug": debug}) | 86 | "sender": model.sender, |
87 | "date": model.date | ||
88 | }) | ||
88 | break; | 89 | break; |
89 | } | 90 | } |
90 | } | 91 | } |
diff --git a/components/mailviewer/contents/ui/MailPart.qml b/components/mailviewer/contents/ui/MailPart.qml index bf534e85..7ff426e9 100644 --- a/components/mailviewer/contents/ui/MailPart.qml +++ b/components/mailviewer/contents/ui/MailPart.qml | |||
@@ -18,29 +18,54 @@ | |||
18 | 18 | ||
19 | import QtQuick 2.4 | 19 | import QtQuick 2.4 |
20 | 20 | ||
21 | import org.kube.framework 1.0 as Kube | ||
22 | |||
21 | Item { | 23 | Item { |
22 | id: root | 24 | id: root |
23 | property alias rootIndex: visualModel.rootIndex | 25 | property alias rootIndex: visualModel.rootIndex |
24 | property alias model: visualModel.model | 26 | property alias model: visualModel.model |
25 | property alias debug: visualModel.debug | 27 | property variant sender |
26 | height: partListView.height + 10 | 28 | property variant date |
27 | width: parent.width | 29 | height: childrenRect.height |
28 | 30 | ||
29 | MailDataModel { | 31 | MailDataModel { |
30 | id: visualModel | 32 | id: visualModel |
31 | } | 33 | } |
32 | 34 | ||
35 | Rectangle { | ||
36 | id: border | ||
37 | anchors { | ||
38 | top: parent.top | ||
39 | left: parent.left | ||
40 | leftMargin: Kube.Units.smallSpacing | ||
41 | } | ||
42 | color: "lightgrey" | ||
43 | height: partListView.height | ||
44 | width: Kube.Units.smallSpacing | ||
45 | } | ||
46 | |||
47 | Text { | ||
48 | id: sender | ||
49 | anchors { | ||
50 | left: border.right | ||
51 | leftMargin: Kube.Units.smallSpacing | ||
52 | } | ||
53 | |||
54 | text: "sent by " + root.sender + " on " + root.date | ||
55 | color: "grey" | ||
56 | } | ||
33 | ListView { | 57 | ListView { |
34 | id: partListView | 58 | id: partListView |
35 | model: visualModel | 59 | model: visualModel |
36 | anchors { | 60 | anchors { |
37 | top: parent.top | 61 | top: sender.bottom |
38 | left: parent.left | 62 | left: border.right |
39 | margins: 5 | 63 | margins: Kube.Units.smallSpacing |
64 | leftMargin: Kube.Units.smallSpacing | ||
40 | } | 65 | } |
41 | spacing: 5 | 66 | spacing: 7 |
42 | height: contentHeight | 67 | height: contentHeight |
43 | width: parent.width - 10 | 68 | width: parent.width - Kube.Units.smallSpacing * 3 |
44 | interactive: false | 69 | interactive: false |
45 | } | 70 | } |
46 | } | 71 | } |
diff --git a/components/mailviewer/contents/ui/MailViewer.qml b/components/mailviewer/contents/ui/MailViewer.qml index 23307009..9031ec17 100644 --- a/components/mailviewer/contents/ui/MailViewer.qml +++ b/components/mailviewer/contents/ui/MailViewer.qml | |||
@@ -22,7 +22,6 @@ Item { | |||
22 | id: root | 22 | id: root |
23 | property alias rootIndex: visualModel.rootIndex | 23 | property alias rootIndex: visualModel.rootIndex |
24 | property alias model: visualModel.model | 24 | property alias model: visualModel.model |
25 | property alias debug: visualModel.debug | ||
26 | height: partListView.height | 25 | height: partListView.height |
27 | 26 | ||
28 | MailDataModel { | 27 | MailDataModel { |
diff --git a/components/mailviewer/contents/ui/TextContent.qml b/components/mailviewer/contents/ui/TextContent.qml index f8ef7f9a..a0094a3e 100644 --- a/components/mailviewer/contents/ui/TextContent.qml +++ b/components/mailviewer/contents/ui/TextContent.qml | |||
@@ -24,7 +24,6 @@ Item { | |||
24 | id: root | 24 | id: root |
25 | 25 | ||
26 | property string content | 26 | property string content |
27 | property bool debug: true | ||
28 | property bool embedded: true | 27 | property bool embedded: true |
29 | property string type | 28 | property string type |
30 | 29 | ||
@@ -54,13 +53,5 @@ Item { | |||
54 | color: embedded ? Kube.Colors.disabledTextColor : Kube.Colors.textColor | 53 | color: embedded ? Kube.Colors.disabledTextColor : Kube.Colors.textColor |
55 | onLinkActivated: Qt.openUrlExternally(link) | 54 | onLinkActivated: Qt.openUrlExternally(link) |
56 | } | 55 | } |
57 | |||
58 | //BEGIN debug | ||
59 | Text { | ||
60 | width: parent.width | ||
61 | visible: root.debug | ||
62 | text: type | ||
63 | } | ||
64 | //END debug | ||
65 | } | 56 | } |
66 | } | 57 | } |
diff --git a/framework/qml/MailViewer.qml b/framework/qml/MailViewer.qml index 9e14fc7f..cd170f8f 100644 --- a/framework/qml/MailViewer.qml +++ b/framework/qml/MailViewer.qml | |||
@@ -318,7 +318,6 @@ Rectangle { | |||
318 | anchors.left: body.left | 318 | anchors.left: body.left |
319 | anchors.right: body.right | 319 | anchors.right: body.right |
320 | model: messageParser.parts | 320 | model: messageParser.parts |
321 | debug: false | ||
322 | } | 321 | } |
323 | 322 | ||
324 | } | 323 | } |
diff --git a/framework/src/domain/mime/mimetreeparser/messagepart.cpp b/framework/src/domain/mime/mimetreeparser/messagepart.cpp index 00abb003..df4dfeac 100644 --- a/framework/src/domain/mime/mimetreeparser/messagepart.cpp +++ b/framework/src/domain/mime/mimetreeparser/messagepart.cpp | |||
@@ -1292,3 +1292,18 @@ QString EncapsulatedRfc822MessagePart::text() const | |||
1292 | return renderInternalText(); | 1292 | return renderInternalText(); |
1293 | } | 1293 | } |
1294 | 1294 | ||
1295 | QString EncapsulatedRfc822MessagePart::from() const | ||
1296 | { | ||
1297 | if (auto from = mMessage->from(false)) { | ||
1298 | return from->asUnicodeString(); | ||
1299 | } | ||
1300 | return {}; | ||
1301 | } | ||
1302 | |||
1303 | QDateTime EncapsulatedRfc822MessagePart::date() const | ||
1304 | { | ||
1305 | if (auto date = mMessage->date(false)) { | ||
1306 | return date->dateTime(); | ||
1307 | } | ||
1308 | return {}; | ||
1309 | } | ||
diff --git a/framework/src/domain/mime/mimetreeparser/messagepart.h b/framework/src/domain/mime/mimetreeparser/messagepart.h index dd3a842f..7d266ac5 100644 --- a/framework/src/domain/mime/mimetreeparser/messagepart.h +++ b/framework/src/domain/mime/mimetreeparser/messagepart.h | |||
@@ -281,6 +281,8 @@ public: | |||
281 | virtual ~EncapsulatedRfc822MessagePart(); | 281 | virtual ~EncapsulatedRfc822MessagePart(); |
282 | 282 | ||
283 | QString text() const Q_DECL_OVERRIDE; | 283 | QString text() const Q_DECL_OVERRIDE; |
284 | QString from() const; | ||
285 | QDateTime date() const; | ||
284 | private: | 286 | private: |
285 | const KMime::Message::Ptr mMessage; | 287 | const KMime::Message::Ptr mMessage; |
286 | 288 | ||
diff --git a/framework/src/domain/mime/mimetreeparser/objecttreeparser.cpp b/framework/src/domain/mime/mimetreeparser/objecttreeparser.cpp index b137be87..8d8ddf12 100644 --- a/framework/src/domain/mime/mimetreeparser/objecttreeparser.cpp +++ b/framework/src/domain/mime/mimetreeparser/objecttreeparser.cpp | |||
@@ -190,20 +190,17 @@ KMime::Content *ObjectTreeParser::find(const std::function<bool(KMime::Content * | |||
190 | * Filter to avoid evaluating a subtree. | 190 | * Filter to avoid evaluating a subtree. |
191 | * Select parts to include it in the result set. Selecting a part in a branch will keep any parent parts from being selected. | 191 | * Select parts to include it in the result set. Selecting a part in a branch will keep any parent parts from being selected. |
192 | */ | 192 | */ |
193 | static QVector<MessagePart::Ptr> collect(MessagePart::Ptr start, const std::function<bool(const MessagePartPtr &)> &filter, const std::function<bool(const MessagePartPtr &)> &select) | 193 | static QVector<MessagePart::Ptr> collect(MessagePart::Ptr start, const std::function<bool(const MessagePartPtr &)> &evaluateSubtree, const std::function<bool(const MessagePartPtr &)> &select) |
194 | { | 194 | { |
195 | MessagePartPtr ptr = start.dynamicCast<MessagePart>(); | 195 | MessagePartPtr ptr = start.dynamicCast<MessagePart>(); |
196 | Q_ASSERT(ptr); | 196 | Q_ASSERT(ptr); |
197 | if (!filter(ptr)) { | ||
198 | return {}; | ||
199 | } | ||
200 | |||
201 | QVector<MessagePart::Ptr> list; | 197 | QVector<MessagePart::Ptr> list; |
202 | if (ptr) { | 198 | if (evaluateSubtree(ptr)) { |
203 | for (const auto &p: ptr->subParts()) { | 199 | for (const auto &p: ptr->subParts()) { |
204 | list << ::collect(p, filter, select); | 200 | list << ::collect(p, evaluateSubtree, select); |
205 | } | 201 | } |
206 | } | 202 | } |
203 | |||
207 | //Don't consider this part if we already selected a subpart | 204 | //Don't consider this part if we already selected a subpart |
208 | if (list.isEmpty()) { | 205 | if (list.isEmpty()) { |
209 | if (select(ptr)) { | 206 | if (select(ptr)) { |
@@ -213,14 +210,25 @@ static QVector<MessagePart::Ptr> collect(MessagePart::Ptr start, const std::func | |||
213 | return list; | 210 | return list; |
214 | } | 211 | } |
215 | 212 | ||
216 | QVector<MessagePart::Ptr> ObjectTreeParser::collectContentParts() | 213 | QVector<MessagePartPtr> ObjectTreeParser::collectContentParts() |
217 | { | 214 | { |
218 | QVector<MessagePart::Ptr> contentParts = ::collect(mParsedPart, | 215 | return collectContentParts(mParsedPart); |
219 | [] (const MessagePartPtr &part) { | 216 | } |
220 | // return p->type() != "EncapsulatedPart"; | 217 | |
218 | QVector<MessagePart::Ptr> ObjectTreeParser::collectContentParts(MessagePart::Ptr start) | ||
219 | { | ||
220 | return ::collect(start, | ||
221 | [start] (const MessagePartPtr &part) { | ||
222 | //Ignore the top-level | ||
223 | if (start.data() == part.data()) { | ||
224 | return true; | ||
225 | } | ||
226 | if (auto e = part.dynamicCast<MimeTreeParser::EncapsulatedRfc822MessagePart>()) { | ||
227 | return false; | ||
228 | } | ||
221 | return true; | 229 | return true; |
222 | }, | 230 | }, |
223 | [] (const MessagePartPtr &part) { | 231 | [start] (const MessagePartPtr &part) { |
224 | if (dynamic_cast<MimeTreeParser::AttachmentMessagePart*>(part.data())) { | 232 | if (dynamic_cast<MimeTreeParser::AttachmentMessagePart*>(part.data())) { |
225 | return false; | 233 | return false; |
226 | } else if (const auto text = dynamic_cast<MimeTreeParser::TextMessagePart*>(part.data())) { | 234 | } else if (const auto text = dynamic_cast<MimeTreeParser::TextMessagePart*>(part.data())) { |
@@ -233,6 +241,11 @@ QVector<MessagePart::Ptr> ObjectTreeParser::collectContentParts() | |||
233 | return true; | 241 | return true; |
234 | } else if (dynamic_cast<MimeTreeParser::HtmlMessagePart*>(part.data())) { | 242 | } else if (dynamic_cast<MimeTreeParser::HtmlMessagePart*>(part.data())) { |
235 | return true; | 243 | return true; |
244 | } else if (dynamic_cast<MimeTreeParser::EncapsulatedRfc822MessagePart*>(part.data())) { | ||
245 | if (start.data() == part.data()) { | ||
246 | return false; | ||
247 | } | ||
248 | return true; | ||
236 | } else if (const auto enc = dynamic_cast<MimeTreeParser::EncryptedMessagePart*>(part.data())) { | 249 | } else if (const auto enc = dynamic_cast<MimeTreeParser::EncryptedMessagePart*>(part.data())) { |
237 | if (enc->error()) { | 250 | if (enc->error()) { |
238 | return true; | 251 | return true; |
@@ -247,7 +260,6 @@ QVector<MessagePart::Ptr> ObjectTreeParser::collectContentParts() | |||
247 | } | 260 | } |
248 | return false; | 261 | return false; |
249 | }); | 262 | }); |
250 | return contentParts; | ||
251 | } | 263 | } |
252 | 264 | ||
253 | QVector<MessagePart::Ptr> ObjectTreeParser::collectAttachmentParts() | 265 | QVector<MessagePart::Ptr> ObjectTreeParser::collectAttachmentParts() |
diff --git a/framework/src/domain/mime/mimetreeparser/objecttreeparser.h b/framework/src/domain/mime/mimetreeparser/objecttreeparser.h index 398cbcd7..d219a52b 100644 --- a/framework/src/domain/mime/mimetreeparser/objecttreeparser.h +++ b/framework/src/domain/mime/mimetreeparser/objecttreeparser.h | |||
@@ -285,6 +285,7 @@ public: | |||
285 | MessagePartPtr parsedPart() const; | 285 | MessagePartPtr parsedPart() const; |
286 | KMime::Content *find(const std::function<bool(KMime::Content *)> &select); | 286 | KMime::Content *find(const std::function<bool(KMime::Content *)> &select); |
287 | QVector<MessagePartPtr> collectContentParts(); | 287 | QVector<MessagePartPtr> collectContentParts(); |
288 | QVector<MessagePartPtr> collectContentParts(MessagePart::Ptr start); | ||
288 | QVector<MessagePartPtr> collectAttachmentParts(); | 289 | QVector<MessagePartPtr> collectAttachmentParts(); |
289 | void decryptParts(); | 290 | void decryptParts(); |
290 | void importCertificates(); | 291 | void importCertificates(); |
diff --git a/framework/src/domain/mime/mimetreeparser/tests/interfacetest.cpp b/framework/src/domain/mime/mimetreeparser/tests/interfacetest.cpp index f9b557c9..b9fdd356 100644 --- a/framework/src/domain/mime/mimetreeparser/tests/interfacetest.cpp +++ b/framework/src/domain/mime/mimetreeparser/tests/interfacetest.cpp | |||
@@ -319,6 +319,24 @@ private slots: | |||
319 | QVERIFY(bool(part)); | 319 | QVERIFY(bool(part)); |
320 | QVERIFY(part->error()); | 320 | QVERIFY(part->error()); |
321 | } | 321 | } |
322 | |||
323 | void testEncapsulated() | ||
324 | { | ||
325 | MimeTreeParser::ObjectTreeParser otp; | ||
326 | otp.parseObjectTree(readMailFromFile("encapsulated-with-attachment.mbox")); | ||
327 | otp.decryptParts(); | ||
328 | auto partList = otp.collectContentParts(); | ||
329 | QCOMPARE(partList.size(), 2); | ||
330 | auto part = partList[1].dynamicCast<MimeTreeParser::EncapsulatedRfc822MessagePart>(); | ||
331 | QVERIFY(bool(part)); | ||
332 | QCOMPARE(part->from(), QLatin1String("Thomas McGuire <dontspamme@gmx.net>")); | ||
333 | QCOMPARE(part->date().toString(), QLatin1String("Wed Aug 5 10:57:58 2009 GMT+0200")); | ||
334 | auto subPartList = otp.collectContentParts(part); | ||
335 | QCOMPARE(subPartList.size(), 1); | ||
336 | qWarning() << subPartList[0]->metaObject()->className(); | ||
337 | auto subPart = subPartList[0].dynamicCast<MimeTreeParser::TextMessagePart>(); | ||
338 | QVERIFY(bool(subPart)); | ||
339 | } | ||
322 | }; | 340 | }; |
323 | 341 | ||
324 | QTEST_GUILESS_MAIN(InterfaceTest) | 342 | QTEST_GUILESS_MAIN(InterfaceTest) |
diff --git a/framework/src/domain/mime/mimetreeparser/textplain.cpp b/framework/src/domain/mime/mimetreeparser/textplain.cpp index 32201a8a..d62cb2cf 100644 --- a/framework/src/domain/mime/mimetreeparser/textplain.cpp +++ b/framework/src/domain/mime/mimetreeparser/textplain.cpp | |||
@@ -41,13 +41,12 @@ const Interface::BodyPartFormatter *TextPlainBodyPartFormatter::create() | |||
41 | MessagePart::Ptr TextPlainBodyPartFormatter::process(Interface::BodyPart &part) const | 41 | MessagePart::Ptr TextPlainBodyPartFormatter::process(Interface::BodyPart &part) const |
42 | { | 42 | { |
43 | KMime::Content *node = part.content(); | 43 | KMime::Content *node = part.content(); |
44 | const bool isFirstTextPart = (node->topLevel()->textContent() == node); | ||
45 | 44 | ||
46 | TextMessagePart::Ptr mp; | 45 | TextMessagePart::Ptr mp; |
47 | if (isFirstTextPart) { | 46 | if (KMime::isAttachment(node)) { |
48 | mp = TextMessagePart::Ptr(new TextMessagePart(part.objectTreeParser(), node)); | 47 | mp = AttachmentMessagePart::Ptr(new AttachmentMessagePart(part.objectTreeParser(), node)); |
49 | } else { | 48 | } else { |
50 | mp = TextMessagePart::Ptr(new AttachmentMessagePart(part.objectTreeParser(), node)); | 49 | mp = TextMessagePart::Ptr(new TextMessagePart(part.objectTreeParser(), node)); |
51 | } | 50 | } |
52 | 51 | ||
53 | return mp; | 52 | return mp; |
diff --git a/framework/src/domain/mime/partmodel.cpp b/framework/src/domain/mime/partmodel.cpp index ea3e90e1..6ee3d46f 100644 --- a/framework/src/domain/mime/partmodel.cpp +++ b/framework/src/domain/mime/partmodel.cpp | |||
@@ -35,6 +35,8 @@ public: | |||
35 | void createTree(); | 35 | void createTree(); |
36 | PartModel *q; | 36 | PartModel *q; |
37 | QVector<MimeTreeParser::MessagePartPtr> mParts; | 37 | QVector<MimeTreeParser::MessagePartPtr> mParts; |
38 | QHash<MimeTreeParser::MessagePart*, QVector<MimeTreeParser::MessagePartPtr>> mEncapsulatedParts; | ||
39 | QHash<MimeTreeParser::MessagePart*, MimeTreeParser::MessagePart*> mParents; | ||
38 | std::shared_ptr<MimeTreeParser::ObjectTreeParser> mParser; | 40 | std::shared_ptr<MimeTreeParser::ObjectTreeParser> mParser; |
39 | }; | 41 | }; |
40 | 42 | ||
@@ -44,6 +46,14 @@ PartModelPrivate::PartModelPrivate(PartModel *q_ptr, const std::shared_ptr<MimeT | |||
44 | { | 46 | { |
45 | mParts = mParser->collectContentParts(); | 47 | mParts = mParser->collectContentParts(); |
46 | qWarning() << "Collected content parts: " << mParts.size(); | 48 | qWarning() << "Collected content parts: " << mParts.size(); |
49 | for (auto p : mParts) { | ||
50 | if (auto e = p.dynamicCast<MimeTreeParser::EncapsulatedRfc822MessagePart>()) { | ||
51 | mEncapsulatedParts[e.data()] = mParser->collectContentParts(e); | ||
52 | for (auto subPart : mEncapsulatedParts[e.data()]) { | ||
53 | mParents[subPart.data()] = e.data(); | ||
54 | } | ||
55 | } | ||
56 | } | ||
47 | } | 57 | } |
48 | 58 | ||
49 | PartModelPrivate::~PartModelPrivate() | 59 | PartModelPrivate::~PartModelPrivate() |
@@ -71,6 +81,8 @@ QHash<int, QByteArray> PartModel::roleNames() const | |||
71 | roles[EncryptionErrorType] = "errorType"; | 81 | roles[EncryptionErrorType] = "errorType"; |
72 | roles[EncryptionErrorString] = "errorString"; | 82 | roles[EncryptionErrorString] = "errorString"; |
73 | roles[IsErrorRole] = "error"; | 83 | roles[IsErrorRole] = "error"; |
84 | roles[SenderRole] = "sender"; | ||
85 | roles[DateRole] = "date"; | ||
74 | return roles; | 86 | return roles; |
75 | } | 87 | } |
76 | 88 | ||
@@ -79,6 +91,15 @@ QModelIndex PartModel::index(int row, int column, const QModelIndex &parent) con | |||
79 | if (row < 0 || column != 0) { | 91 | if (row < 0 || column != 0) { |
80 | return QModelIndex(); | 92 | return QModelIndex(); |
81 | } | 93 | } |
94 | if (parent.isValid()) { | ||
95 | if (auto e = dynamic_cast<MimeTreeParser::EncapsulatedRfc822MessagePart*>(static_cast<MimeTreeParser::MessagePart*>(parent.internalPointer()))) { | ||
96 | const auto parts = d->mEncapsulatedParts[e]; | ||
97 | if (row < parts.size()) { | ||
98 | return createIndex(row, column, parts.at(row).data()); | ||
99 | } | ||
100 | } | ||
101 | return QModelIndex(); | ||
102 | } | ||
82 | if (row < d->mParts.size()) { | 103 | if (row < d->mParts.size()) { |
83 | return createIndex(row, column, d->mParts.at(row).data()); | 104 | return createIndex(row, column, d->mParts.at(row).data()); |
84 | } | 105 | } |
@@ -88,26 +109,35 @@ QModelIndex PartModel::index(int row, int column, const QModelIndex &parent) con | |||
88 | QVariant PartModel::data(const QModelIndex &index, int role) const | 109 | QVariant PartModel::data(const QModelIndex &index, int role) const |
89 | { | 110 | { |
90 | if (!index.isValid()) { | 111 | if (!index.isValid()) { |
91 | switch (role) { | ||
92 | case Qt::DisplayRole: | ||
93 | return QString("root"); | ||
94 | case IsEmbededRole: | ||
95 | return false; | ||
96 | } | ||
97 | return QVariant(); | 112 | return QVariant(); |
98 | } | 113 | } |
99 | 114 | ||
100 | if (index.internalPointer()) { | 115 | if (index.internalPointer()) { |
101 | const auto messagePart = static_cast<MimeTreeParser::MessagePart*>(index.internalPointer()); | 116 | const auto messagePart = static_cast<MimeTreeParser::MessagePart*>(index.internalPointer()); |
102 | qWarning() << "Found message part " << messagePart->metaObject()->className() << messagePart->partMetaData()->status << messagePart->error(); | 117 | // qWarning() << "Found message part " << messagePart->metaObject()->className() << messagePart->partMetaData()->status << messagePart->error(); |
103 | Q_ASSERT(messagePart); | 118 | Q_ASSERT(messagePart); |
104 | switch(role) { | 119 | switch(role) { |
105 | case Qt::DisplayRole: | 120 | case Qt::DisplayRole: |
106 | return QStringLiteral("Content%1"); | 121 | return QStringLiteral("Content%1"); |
122 | case SenderRole: { | ||
123 | if (auto e = dynamic_cast<MimeTreeParser::EncapsulatedRfc822MessagePart*>(messagePart)) { | ||
124 | return e->from(); | ||
125 | } | ||
126 | return {}; | ||
127 | } | ||
128 | case DateRole: { | ||
129 | if (auto e = dynamic_cast<MimeTreeParser::EncapsulatedRfc822MessagePart*>(messagePart)) { | ||
130 | return e->date(); | ||
131 | } | ||
132 | return {}; | ||
133 | } | ||
107 | case TypeRole: { | 134 | case TypeRole: { |
108 | if (messagePart->error()) { | 135 | if (messagePart->error()) { |
109 | return "error"; | 136 | return "error"; |
110 | } | 137 | } |
138 | if (dynamic_cast<MimeTreeParser::EncapsulatedRfc822MessagePart*>(messagePart)) { | ||
139 | return "encapsulated"; | ||
140 | } | ||
111 | //For simple html we don't need a browser | 141 | //For simple html we don't need a browser |
112 | auto complexHtml = [&] { | 142 | auto complexHtml = [&] { |
113 | if (messagePart->isHtml()) { | 143 | if (messagePart->isHtml()) { |
@@ -165,11 +195,39 @@ QVariant PartModel::data(const QModelIndex &index, int role) const | |||
165 | 195 | ||
166 | QModelIndex PartModel::parent(const QModelIndex &index) const | 196 | QModelIndex PartModel::parent(const QModelIndex &index) const |
167 | { | 197 | { |
168 | return QModelIndex(); | 198 | if (index.isValid()) { |
199 | if (auto e = static_cast<MimeTreeParser::MessagePart*>(index.internalPointer())) { | ||
200 | for (const auto &p : d->mParts) { | ||
201 | if (p.data() == e) { | ||
202 | return QModelIndex(); | ||
203 | } | ||
204 | } | ||
205 | const auto parentPart = d->mParents[e]; | ||
206 | Q_ASSERT(parentPart); | ||
207 | int row = 0; | ||
208 | const auto parts = d->mEncapsulatedParts[parentPart]; | ||
209 | for (const auto &p : parts) { | ||
210 | if (p.data() == e) { | ||
211 | break; | ||
212 | } | ||
213 | row++; | ||
214 | } | ||
215 | return createIndex(row, 0, parentPart); | ||
216 | } | ||
217 | return {}; | ||
218 | } | ||
219 | return {}; | ||
169 | } | 220 | } |
170 | 221 | ||
171 | int PartModel::rowCount(const QModelIndex &parent) const | 222 | int PartModel::rowCount(const QModelIndex &parent) const |
172 | { | 223 | { |
224 | if (parent.isValid()) { | ||
225 | if (auto e = dynamic_cast<MimeTreeParser::EncapsulatedRfc822MessagePart*>(static_cast<MimeTreeParser::MessagePart*>(parent.internalPointer()))) { | ||
226 | const auto parts = d->mEncapsulatedParts[e]; | ||
227 | return parts.size(); | ||
228 | } | ||
229 | return 0; | ||
230 | } | ||
173 | return d->mParts.count(); | 231 | return d->mParts.count(); |
174 | } | 232 | } |
175 | 233 | ||
diff --git a/framework/src/domain/mime/partmodel.h b/framework/src/domain/mime/partmodel.h index efbd154b..a0e14b61 100644 --- a/framework/src/domain/mime/partmodel.h +++ b/framework/src/domain/mime/partmodel.h | |||
@@ -47,7 +47,9 @@ public: | |||
47 | IsErrorRole, | 47 | IsErrorRole, |
48 | SecurityLevelRole, | 48 | SecurityLevelRole, |
49 | EncryptionErrorType, | 49 | EncryptionErrorType, |
50 | EncryptionErrorString | 50 | EncryptionErrorString, |
51 | SenderRole, | ||
52 | DateRole | ||
51 | }; | 53 | }; |
52 | 54 | ||
53 | QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE; | 55 | QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE; |