summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSandro Knauß <[email protected]>2016-05-25 13:27:14 +0200
committerSandro Knauß <[email protected]>2016-05-25 14:15:18 +0200
commit1c3bd5932a83a43d3bcbb106c1a5d809a863f842 (patch)
treecebb27e14daa2666875a00e8d9cddd813971c342
parentd8d237029c4589f54c99f20449e073d4ca43f923 (diff)
Move renderingparts to own subdir.
cleanup parsing and rendering from eachother.
-rw-r--r--mimetreeparser/src/CMakeLists.txt2
-rw-r--r--mimetreeparser/src/themes/default/htmlblock.cpp (renamed from mimetreeparser/src/viewer/htmlblock.cpp)48
-rw-r--r--mimetreeparser/src/themes/default/htmlblock.h (renamed from mimetreeparser/src/viewer/htmlblock.h)16
-rw-r--r--mimetreeparser/src/themes/default/mailrenderer.cpp304
-rw-r--r--mimetreeparser/src/viewer/messagepart.cpp381
-rw-r--r--mimetreeparser/src/viewer/messagepart.h14
6 files changed, 303 insertions, 462 deletions
diff --git a/mimetreeparser/src/CMakeLists.txt b/mimetreeparser/src/CMakeLists.txt
index e0936d2..bfac460 100644
--- a/mimetreeparser/src/CMakeLists.txt
+++ b/mimetreeparser/src/CMakeLists.txt
@@ -29,7 +29,6 @@ set(libmimetreeparser_main_SRCS
viewer/bodypartformatterbasefactory.cpp
viewer/cryptohelper.cpp
viewer/csshelperbase.cpp
- viewer/htmlblock.cpp
viewer/nodehelper.cpp
viewer/objecttreeparser.cpp
viewer/messagepart.cpp
@@ -49,6 +48,7 @@ set(libmimetreeparser_extra_SRCS
htmlwriter/filehtmlwriter.cpp
htmlwriter/queuehtmlwriter.cpp
themes/default/mailrenderer.cpp
+ themes/default/htmlblock.cpp
)
set(mimetreeparser_temporaryfile_SRCS
diff --git a/mimetreeparser/src/viewer/htmlblock.cpp b/mimetreeparser/src/themes/default/htmlblock.cpp
index b4c745a..1c9aca5 100644
--- a/mimetreeparser/src/viewer/htmlblock.cpp
+++ b/mimetreeparser/src/themes/default/htmlblock.cpp
@@ -20,19 +20,10 @@
#include "htmlblock.h"
#include "mimetreeparser_debug.h"
-#include "interfaces/objecttreesource.h"
#include "interfaces/htmlwriter.h"
-#include "nodehelper.h"
-#include <MessageCore/StringUtil>
#include <KMime/Content>
-#include <gpgme.h>
-#include <Libkleo/CryptoBackendFactory>
-
-#include <KLocalizedString>
-#include <KEmailAddress>
-
#include <QApplication>
using namespace MimeTreeParser;
@@ -78,45 +69,6 @@ void AttachmentMarkBlock::internalExit()
entered = false;
}
-HTMLWarnBlock::HTMLWarnBlock(HtmlWriter *writer, const QString &msg)
- : mWriter(writer)
- , mMsg(msg)
-{
- internalEnter();
-}
-
-HTMLWarnBlock::~HTMLWarnBlock()
-{
- internalExit();
-}
-
-void HTMLWarnBlock::internalEnter()
-{
- if (!mWriter || entered) {
- return;
- }
- entered = true;
-
- if (!mMsg.isEmpty()) {
- mWriter->queue(QStringLiteral("<div class=\"htmlWarn\">\n"));
- mWriter->queue(mMsg);
- mWriter->queue(QStringLiteral("</div><br/><br/>"));
- }
-
- mWriter->queue(QStringLiteral("<div style=\"position: relative\">\n"));
-}
-
-void HTMLWarnBlock::internalExit()
-{
- if (!entered) {
- return;
- }
-
- entered = false;
-
- mWriter->queue(QStringLiteral("</div>\n"));
-}
-
RootBlock::RootBlock(HtmlWriter *writer)
: HTMLBlock()
, mWriter(writer)
diff --git a/mimetreeparser/src/viewer/htmlblock.h b/mimetreeparser/src/themes/default/htmlblock.h
index 56bc558..d2a3df1 100644
--- a/mimetreeparser/src/viewer/htmlblock.h
+++ b/mimetreeparser/src/themes/default/htmlblock.h
@@ -20,9 +20,6 @@
#ifndef __MIMETREEPARSER_HTMLBLOCK_H__
#define __MIMETREEPARSER_HTMLBLOCK_H__
-#include "partmetadata.h"
-#include <Libkleo/CryptoBackend>
-
#include <QString>
#include <QSharedPointer>
#include <QVector>
@@ -83,19 +80,6 @@ private:
HtmlWriter *mWriter;
};
-class HTMLWarnBlock : public HTMLBlock
-{
-public:
- HTMLWarnBlock(MimeTreeParser::HtmlWriter *writer, const QString &msg);
- virtual ~HTMLWarnBlock();
-private:
- void internalEnter();
- void internalExit();
-private:
- HtmlWriter *mWriter;
- const QString &mMsg;
-};
-
// Make sure the whole content is relative, so that nothing is painted over the header
// if a malicious message uses absolute positioning.
// Also force word wrapping, which is useful for printing, see https://issues.kolab.org/issue3992.
diff --git a/mimetreeparser/src/themes/default/mailrenderer.cpp b/mimetreeparser/src/themes/default/mailrenderer.cpp
index c6fbfee..e910ff0 100644
--- a/mimetreeparser/src/themes/default/mailrenderer.cpp
+++ b/mimetreeparser/src/themes/default/mailrenderer.cpp
@@ -19,10 +19,12 @@
#include "mailrenderer.h"
+#include "htmlblock.h"
+
#include "interfaces/htmlwriter.h"
#include "utils/iconnamecache.h"
+#include "viewer/csshelperbase.h"
#include "viewer/converthtmltoplaintext.h"
-#include "viewer/htmlblock.h"
#include "viewer/messagepart.h"
#include "viewer/objecttreeparser.h"
@@ -33,9 +35,11 @@
#include <KEmailAddress>
#include <KLocalizedString>
+#include <KTextToHTML>
#include <QApplication>
#include <QDebug>
+#include <QFile>
#include <QTextCodec>
#include <QUrl>
@@ -88,6 +92,96 @@ Grantlee::Template getGrantleeTemplate(QObject *parent, const QString &name)
return m_engine->loadByName(name);
}
+static QString iconToDataUrl(const QString &iconPath)
+{
+ QFile f(iconPath);
+ if (!f.open(QIODevice::ReadOnly)) {
+ return QString();
+ }
+
+ const QByteArray ba = f.readAll();
+ return QStringLiteral("data:image/png;base64,%1").arg(QLatin1String(ba.toBase64().constData()));
+}
+
+/** Check if the newline at position @p newLinePos in string @p s
+ seems to separate two paragraphs (important for correct BiDi
+ behavior, but is heuristic because paragraphs are not
+ well-defined) */
+// Guesstimate if the newline at newLinePos actually separates paragraphs in the text s
+// We use several heuristics:
+// 1. If newLinePos points after or before (=at the very beginning of) text, it is not between paragraphs
+// 2. If the previous line was longer than the wrap size, we want to consider it a paragraph on its own
+// (some clients, notably Outlook, send each para as a line in the plain-text version).
+// 3. Otherwise, we check if the newline could have been inserted for wrapping around; if this
+// was the case, then the previous line will be shorter than the wrap size (which we already
+// know because of item 2 above), but adding the first word from the next line will make it
+// longer than the wrap size.
+bool looksLikeParaBreak(const QString &s, unsigned int newLinePos)
+{
+ const unsigned int WRAP_COL = 78;
+
+ unsigned int length = s.length();
+ // 1. Is newLinePos at an end of the text?
+ if (newLinePos >= length - 1 || newLinePos == 0) {
+ return false;
+ }
+
+ // 2. Is the previous line really a paragraph -- longer than the wrap size?
+
+ // First char of prev line -- works also for first line
+ unsigned prevStart = s.lastIndexOf(QLatin1Char('\n'), newLinePos - 1) + 1;
+ unsigned prevLineLength = newLinePos - prevStart;
+ if (prevLineLength > WRAP_COL) {
+ return true;
+ }
+
+ // find next line to delimit search for first word
+ unsigned int nextStart = newLinePos + 1;
+ int nextEnd = s.indexOf(QLatin1Char('\n'), nextStart);
+ if (nextEnd == -1) {
+ nextEnd = length;
+ }
+ QString nextLine = s.mid(nextStart, nextEnd - nextStart);
+ length = nextLine.length();
+ // search for first word in next line
+ unsigned int wordStart;
+ bool found = false;
+ for (wordStart = 0; !found && wordStart < length; wordStart++) {
+ switch (nextLine[wordStart].toLatin1()) {
+ case '>':
+ case '|':
+ case ' ': // spaces, tabs and quote markers don't count
+ case '\t':
+ case '\r':
+ break;
+ default:
+ found = true;
+ break;
+ }
+ } /* for() */
+
+ if (!found) {
+ // next line is essentially empty, it seems -- empty lines are
+ // para separators
+ return true;
+ }
+ //Find end of first word.
+ //Note: flowText (in kmmessage.cpp) separates words for wrap by
+ //spaces only. This should be consistent, which calls for some
+ //refactoring.
+ int wordEnd = nextLine.indexOf(QLatin1Char(' '), wordStart);
+ if (wordEnd == (-1)) {
+ wordEnd = length;
+ }
+ int wordLength = wordEnd - wordStart;
+
+ // 3. If adding a space and the first word to the prev line don't
+ // make it reach the wrap column, then the break was probably
+ // meaningful
+ return prevLineLength + wordLength + 1 < WRAP_COL;
+}
+
+
static const int SIG_FRAME_COL_UNDEF = 99;
#define SIG_FRAME_COL_RED -1
#define SIG_FRAME_COL_YELLOW 0
@@ -355,6 +449,16 @@ public:
mHtml = renderFactory(mMsgPart, QSharedPointer<TestHtmlWriter>());
}
+ CSSHelperBase *cssHelper() const
+ {
+ return mMsgPart->cssHelper();
+ }
+
+ Interface::ObjectTreeSource *source() const
+ {
+ return mMsgPart->source();
+ }
+
void renderSubParts(MessagePart::Ptr msgPart, const QSharedPointer<TestHtmlWriter> &htmlWriter)
{
foreach (const auto &_m, msgPart->subParts()) {
@@ -514,6 +618,199 @@ public:
return htmlWriter->html;
}
+ QString quotedHTML(const QString &s, bool decorate)
+ {
+ assert(cssHelper());
+
+ KTextToHTML::Options convertFlags = KTextToHTML::PreserveSpaces | KTextToHTML::HighlightText;
+ if (decorate && source()->showEmoticons()) {
+ convertFlags |= KTextToHTML::ReplaceSmileys;
+ }
+ QString htmlStr;
+ const QString normalStartTag = cssHelper()->nonQuotedFontTag();
+ QString quoteFontTag[3];
+ QString deepQuoteFontTag[3];
+ for (int i = 0; i < 3; ++i) {
+ quoteFontTag[i] = cssHelper()->quoteFontTag(i);
+ deepQuoteFontTag[i] = cssHelper()->quoteFontTag(i + 3);
+ }
+ const QString normalEndTag = QStringLiteral("</div>");
+ const QString quoteEnd = QStringLiteral("</div>");
+
+ const unsigned int length = s.length();
+ bool paraIsRTL = false;
+ bool startNewPara = true;
+ unsigned int pos, beg;
+
+ // skip leading empty lines
+ for (pos = 0; pos < length && s[pos] <= QLatin1Char(' '); ++pos)
+ ;
+ while (pos > 0 && (s[pos - 1] == QLatin1Char(' ') || s[pos - 1] == QLatin1Char('\t'))) {
+ pos--;
+ }
+ beg = pos;
+
+ int currQuoteLevel = -2; // -2 == no previous lines
+ bool curHidden = false; // no hide any block
+
+ if (source()->showExpandQuotesMark()) {
+ // Cache Icons
+ if (mCollapseIcon.isEmpty()) {
+ mCollapseIcon = iconToDataUrl(IconNameCache::instance()->iconPath(QStringLiteral("quotecollapse"), 0));
+ }
+ if (mExpandIcon.isEmpty()) {
+ mExpandIcon = iconToDataUrl(IconNameCache::instance()->iconPath(QStringLiteral("quoteexpand"), 0));
+ }
+ }
+
+ int previousQuoteDepth = -1;
+ while (beg < length) {
+ /* search next occurrence of '\n' */
+ pos = s.indexOf(QLatin1Char('\n'), beg, Qt::CaseInsensitive);
+ if (pos == (unsigned int)(-1)) {
+ pos = length;
+ }
+
+ QString line(s.mid(beg, pos - beg));
+ beg = pos + 1;
+
+ bool foundQuote = false;
+ /* calculate line's current quoting depth */
+ int actQuoteLevel = -1;
+ const int numberOfCaracters(line.length());
+ int quoteLength = 0;
+ for (int p = 0; p < numberOfCaracters; ++p) {
+ switch (line[p].toLatin1()) {
+ case '>':
+ case '|':
+ actQuoteLevel++;
+ quoteLength = p;
+ foundQuote = true;
+ break;
+ case ' ': // spaces and tabs are allowed between the quote markers
+ case '\t':
+ case '\r':
+ quoteLength = p;
+ break;
+ default: // stop quoting depth calculation
+ p = numberOfCaracters;
+ break;
+ }
+ } /* for() */
+ if (!foundQuote) {
+ quoteLength = 0;
+ }
+ bool actHidden = false;
+
+ // This quoted line needs be hidden
+ if (source()->showExpandQuotesMark() && source()->levelQuote() >= 0
+ && source()->levelQuote() <= (actQuoteLevel)) {
+ actHidden = true;
+ }
+
+ if (actQuoteLevel != currQuoteLevel) {
+ /* finish last quotelevel */
+ if (currQuoteLevel == -1) {
+ htmlStr.append(normalEndTag);
+ } else if (currQuoteLevel >= 0 && !curHidden) {
+ htmlStr.append(quoteEnd);
+ }
+ //Close blockquote
+ if (previousQuoteDepth > actQuoteLevel) {
+ htmlStr += cssHelper()->addEndBlockQuote((previousQuoteDepth - actQuoteLevel));
+ }
+
+ /* start new quotelevel */
+ if (actQuoteLevel == -1) {
+ htmlStr += normalStartTag;
+ } else {
+ if (source()->showExpandQuotesMark()) {
+ if (actHidden) {
+ //only show the QuoteMark when is the first line of the level hidden
+ if (!curHidden) {
+ //Expand all quotes
+ htmlStr += QLatin1String("<div class=\"quotelevelmark\" >");
+ htmlStr += QStringLiteral("<a href=\"kmail:levelquote?%1 \">"
+ "<img src=\"%2\"/></a>")
+ .arg(-1)
+ .arg(mExpandIcon);
+ htmlStr += QLatin1String("</div><br/>");
+ htmlStr += quoteEnd;
+ }
+ } else {
+ htmlStr += QLatin1String("<div class=\"quotelevelmark\" >");
+ htmlStr += QStringLiteral("<a href=\"kmail:levelquote?%1 \">"
+ "<img src=\"%2\"/></a>")
+ .arg(actQuoteLevel)
+ .arg(mCollapseIcon);
+ htmlStr += QLatin1String("</div>");
+ if (actQuoteLevel < 3) {
+ htmlStr += quoteFontTag[actQuoteLevel];
+ } else {
+ htmlStr += deepQuoteFontTag[actQuoteLevel % 3];
+ }
+ }
+ } else {
+ // Add blockquote
+ if (previousQuoteDepth < actQuoteLevel) {
+ htmlStr += cssHelper()->addStartBlockQuote(actQuoteLevel - previousQuoteDepth);
+ }
+
+ if (actQuoteLevel < 3) {
+ htmlStr += quoteFontTag[actQuoteLevel];
+ } else {
+ htmlStr += deepQuoteFontTag[actQuoteLevel % 3];
+ }
+ }
+ }
+ currQuoteLevel = actQuoteLevel;
+ }
+ curHidden = actHidden;
+
+ if (!actHidden) {
+ // don't write empty <div ...></div> blocks (they have zero height)
+ // ignore ^M DOS linebreaks
+ if (!line.remove(QLatin1Char('\015')).isEmpty()) {
+ if (startNewPara) {
+ paraIsRTL = line.isRightToLeft();
+ }
+ htmlStr += QStringLiteral("<div dir=\"%1\">").arg(paraIsRTL ? QStringLiteral("rtl") : QStringLiteral("ltr"));
+ // if quoteLengh == 0 && foundQuote => a simple quote
+ if (foundQuote) {
+ quoteLength++;
+ htmlStr += QStringLiteral("<span class=\"quotemarks\">%1</span>").arg(line.left(quoteLength));
+ const int rightString = (line.length()) - quoteLength;
+ if (rightString > 0) {
+ htmlStr += QStringLiteral("<font color=\"%1\">").arg(cssHelper()->quoteColorName(actQuoteLevel)) + KTextToHTML::convertToHtml(line.right(rightString), convertFlags) + QStringLiteral("</font>");
+ }
+ } else {
+ htmlStr += KTextToHTML::convertToHtml(line, convertFlags);
+ }
+
+ htmlStr += QLatin1String("</div>");
+ startNewPara = looksLikeParaBreak(s, pos);
+ } else {
+ htmlStr += QLatin1String("<br/>");
+ // after an empty line, always start a new paragraph
+ startNewPara = true;
+ }
+ }
+ previousQuoteDepth = actQuoteLevel;
+ } /* while() */
+
+ /* really finish the last quotelevel */
+ if (currQuoteLevel == -1) {
+ htmlStr.append(normalEndTag);
+ } else {
+ htmlStr += quoteEnd + cssHelper()->addEndBlockQuote(currQuoteLevel + 1);
+ }
+
+ // qCDebug(MIMETREEPARSER_LOG) << "========================================\n"
+ // << htmlStr
+ // << "\n======================================\n";
+ return htmlStr;
+ }
+
QString render(MessagePart::Ptr mp)
{
auto htmlWriter = QSharedPointer<TestHtmlWriter>(new TestHtmlWriter(mOldWriter));
@@ -523,7 +820,7 @@ public:
aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->mAttachmentNode));
}
- htmlWriter->queue(mp->quotedHTML(mp->text(), false));
+ htmlWriter->queue(quotedHTML(mp->text(), false));
}
return htmlWriter->html;
}
@@ -1014,6 +1311,9 @@ public:
private:
HtmlRenderer *q;
HtmlWriter *mOldWriter;
+
+ QString mCollapseIcon;
+ QString mExpandIcon;
};
diff --git a/mimetreeparser/src/viewer/messagepart.cpp b/mimetreeparser/src/viewer/messagepart.cpp
index 33f06c2..7364818 100644
--- a/mimetreeparser/src/viewer/messagepart.cpp
+++ b/mimetreeparser/src/viewer/messagepart.cpp
@@ -21,14 +21,12 @@
#include "mimetreeparser_debug.h"
#include "csshelperbase.h"
#include "cryptohelper.h"
-#include "htmlblock.h"
#include "objecttreeparser.h"
#include "interfaces/htmlwriter.h"
#include "job/kleojobexecutor.h"
#include "memento/decryptverifybodypartmemento.h"
#include "memento/verifydetachedbodypartmemento.h"
#include "memento/verifyopaquebodypartmemento.h"
-#include "utils/iconnamecache.h"
#include <KMime/Content>
@@ -43,14 +41,12 @@
#include <gpgme++/keylistresult.h>
#include <gpgme.h>
-#include <QFile>
#include <QTextCodec>
#include <QWebPage>
#include <QWebElement>
#include <QWebFrame>
#include <KLocalizedString>
-#include <KTextToHTML>
using namespace MimeTreeParser;
@@ -94,14 +90,6 @@ KMime::Content *MessagePart::attachmentNode() const
return mAttachmentNode;
}
-HTMLBlock::Ptr MessagePart::attachmentBlock() const
-{
- if (htmlWriter() && isAttachment()) {
- return HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter(), mAttachmentNode));
- }
- return HTMLBlock::Ptr();
-}
-
void MessagePart::setIsRoot(bool root)
{
mRoot = root;
@@ -112,14 +100,6 @@ bool MessagePart::isRoot() const
return mRoot;
}
-HTMLBlock::Ptr MessagePart::rootBlock() const
-{
- if (htmlWriter() && isRoot()) {
- return HTMLBlock::Ptr(new RootBlock(htmlWriter()));
- }
- return HTMLBlock::Ptr();
-}
-
QString MessagePart::text() const
{
return mText;
@@ -153,300 +133,6 @@ void MessagePart::setHtmlWriter(HtmlWriter *htmlWriter) const
mOtp->mHtmlWriter = htmlWriter;
}
-static QString iconToDataUrl(const QString &iconPath)
-{
- QFile f(iconPath);
- if (!f.open(QIODevice::ReadOnly)) {
- return QString();
- }
-
- const QByteArray ba = f.readAll();
- return QStringLiteral("data:image/png;base64,%1").arg(QLatin1String(ba.toBase64().constData()));
-}
-
-/** Check if the newline at position @p newLinePos in string @p s
- seems to separate two paragraphs (important for correct BiDi
- behavior, but is heuristic because paragraphs are not
- well-defined) */
-// Guesstimate if the newline at newLinePos actually separates paragraphs in the text s
-// We use several heuristics:
-// 1. If newLinePos points after or before (=at the very beginning of) text, it is not between paragraphs
-// 2. If the previous line was longer than the wrap size, we want to consider it a paragraph on its own
-// (some clients, notably Outlook, send each para as a line in the plain-text version).
-// 3. Otherwise, we check if the newline could have been inserted for wrapping around; if this
-// was the case, then the previous line will be shorter than the wrap size (which we already
-// know because of item 2 above), but adding the first word from the next line will make it
-// longer than the wrap size.
-bool looksLikeParaBreak(const QString &s, unsigned int newLinePos)
-{
- const unsigned int WRAP_COL = 78;
-
- unsigned int length = s.length();
- // 1. Is newLinePos at an end of the text?
- if (newLinePos >= length - 1 || newLinePos == 0) {
- return false;
- }
-
- // 2. Is the previous line really a paragraph -- longer than the wrap size?
-
- // First char of prev line -- works also for first line
- unsigned prevStart = s.lastIndexOf(QLatin1Char('\n'), newLinePos - 1) + 1;
- unsigned prevLineLength = newLinePos - prevStart;
- if (prevLineLength > WRAP_COL) {
- return true;
- }
-
- // find next line to delimit search for first word
- unsigned int nextStart = newLinePos + 1;
- int nextEnd = s.indexOf(QLatin1Char('\n'), nextStart);
- if (nextEnd == -1) {
- nextEnd = length;
- }
- QString nextLine = s.mid(nextStart, nextEnd - nextStart);
- length = nextLine.length();
- // search for first word in next line
- unsigned int wordStart;
- bool found = false;
- for (wordStart = 0; !found && wordStart < length; wordStart++) {
- switch (nextLine[wordStart].toLatin1()) {
- case '>':
- case '|':
- case ' ': // spaces, tabs and quote markers don't count
- case '\t':
- case '\r':
- break;
- default:
- found = true;
- break;
- }
- } /* for() */
-
- if (!found) {
- // next line is essentially empty, it seems -- empty lines are
- // para separators
- return true;
- }
- //Find end of first word.
- //Note: flowText (in kmmessage.cpp) separates words for wrap by
- //spaces only. This should be consistent, which calls for some
- //refactoring.
- int wordEnd = nextLine.indexOf(QLatin1Char(' '), wordStart);
- if (wordEnd == (-1)) {
- wordEnd = length;
- }
- int wordLength = wordEnd - wordStart;
-
- // 3. If adding a space and the first word to the prev line don't
- // make it reach the wrap column, then the break was probably
- // meaningful
- return prevLineLength + wordLength + 1 < WRAP_COL;
-}
-
-QString MessagePart::quotedHTML(const QString &s, bool decorate)
-{
- assert(cssHelper());
-
- KTextToHTML::Options convertFlags = KTextToHTML::PreserveSpaces | KTextToHTML::HighlightText;
- if (decorate && source()->showEmoticons()) {
- convertFlags |= KTextToHTML::ReplaceSmileys;
- }
- QString htmlStr;
- const QString normalStartTag = cssHelper()->nonQuotedFontTag();
- QString quoteFontTag[3];
- QString deepQuoteFontTag[3];
- for (int i = 0; i < 3; ++i) {
- quoteFontTag[i] = cssHelper()->quoteFontTag(i);
- deepQuoteFontTag[i] = cssHelper()->quoteFontTag(i + 3);
- }
- const QString normalEndTag = QStringLiteral("</div>");
- const QString quoteEnd = QStringLiteral("</div>");
-
- const unsigned int length = s.length();
- bool paraIsRTL = false;
- bool startNewPara = true;
- unsigned int pos, beg;
-
- // skip leading empty lines
- for (pos = 0; pos < length && s[pos] <= QLatin1Char(' '); ++pos)
- ;
- while (pos > 0 && (s[pos - 1] == QLatin1Char(' ') || s[pos - 1] == QLatin1Char('\t'))) {
- pos--;
- }
- beg = pos;
-
- int currQuoteLevel = -2; // -2 == no previous lines
- bool curHidden = false; // no hide any block
-
- if (source()->showExpandQuotesMark()) {
- // Cache Icons
- if (mCollapseIcon.isEmpty()) {
- mCollapseIcon = iconToDataUrl(IconNameCache::instance()->iconPath(QStringLiteral("quotecollapse"), 0));
- }
- if (mExpandIcon.isEmpty()) {
- mExpandIcon = iconToDataUrl(IconNameCache::instance()->iconPath(QStringLiteral("quoteexpand"), 0));
- }
- }
-
- int previousQuoteDepth = -1;
- while (beg < length) {
- /* search next occurrence of '\n' */
- pos = s.indexOf(QLatin1Char('\n'), beg, Qt::CaseInsensitive);
- if (pos == (unsigned int)(-1)) {
- pos = length;
- }
-
- QString line(s.mid(beg, pos - beg));
- beg = pos + 1;
-
- bool foundQuote = false;
- /* calculate line's current quoting depth */
- int actQuoteLevel = -1;
- const int numberOfCaracters(line.length());
- int quoteLength = 0;
- for (int p = 0; p < numberOfCaracters; ++p) {
- switch (line[p].toLatin1()) {
- case '>':
- case '|':
- actQuoteLevel++;
- quoteLength = p;
- foundQuote = true;
- break;
- case ' ': // spaces and tabs are allowed between the quote markers
- case '\t':
- case '\r':
- quoteLength = p;
- break;
- default: // stop quoting depth calculation
- p = numberOfCaracters;
- break;
- }
- } /* for() */
- if (!foundQuote) {
- quoteLength = 0;
- }
- bool actHidden = false;
-
- // This quoted line needs be hidden
- if (source()->showExpandQuotesMark() && source()->levelQuote() >= 0
- && source()->levelQuote() <= (actQuoteLevel)) {
- actHidden = true;
- }
-
- if (actQuoteLevel != currQuoteLevel) {
- /* finish last quotelevel */
- if (currQuoteLevel == -1) {
- htmlStr.append(normalEndTag);
- } else if (currQuoteLevel >= 0 && !curHidden) {
- htmlStr.append(quoteEnd);
- }
- //Close blockquote
- if (previousQuoteDepth > actQuoteLevel) {
- htmlStr += cssHelper()->addEndBlockQuote((previousQuoteDepth - actQuoteLevel));
- }
-
- /* start new quotelevel */
- if (actQuoteLevel == -1) {
- htmlStr += normalStartTag;
- } else {
- if (source()->showExpandQuotesMark()) {
- if (actHidden) {
- //only show the QuoteMark when is the first line of the level hidden
- if (!curHidden) {
- //Expand all quotes
- htmlStr += QLatin1String("<div class=\"quotelevelmark\" >");
- htmlStr += QStringLiteral("<a href=\"kmail:levelquote?%1 \">"
- "<img src=\"%2\"/></a>")
- .arg(-1)
- .arg(mExpandIcon);
- htmlStr += QLatin1String("</div><br/>");
- htmlStr += quoteEnd;
- }
- } else {
- htmlStr += QLatin1String("<div class=\"quotelevelmark\" >");
- htmlStr += QStringLiteral("<a href=\"kmail:levelquote?%1 \">"
- "<img src=\"%2\"/></a>")
- .arg(actQuoteLevel)
- .arg(mCollapseIcon);
- htmlStr += QLatin1String("</div>");
- if (actQuoteLevel < 3) {
- htmlStr += quoteFontTag[actQuoteLevel];
- } else {
- htmlStr += deepQuoteFontTag[actQuoteLevel % 3];
- }
- }
- } else {
- // Add blockquote
- if (previousQuoteDepth < actQuoteLevel) {
- htmlStr += cssHelper()->addStartBlockQuote(actQuoteLevel - previousQuoteDepth);
- }
-
- if (actQuoteLevel < 3) {
- htmlStr += quoteFontTag[actQuoteLevel];
- } else {
- htmlStr += deepQuoteFontTag[actQuoteLevel % 3];
- }
- }
- }
- currQuoteLevel = actQuoteLevel;
- }
- curHidden = actHidden;
-
- if (!actHidden) {
- // don't write empty <div ...></div> blocks (they have zero height)
- // ignore ^M DOS linebreaks
- if (!line.remove(QLatin1Char('\015')).isEmpty()) {
- if (startNewPara) {
- paraIsRTL = line.isRightToLeft();
- }
- htmlStr += QStringLiteral("<div dir=\"%1\">").arg(paraIsRTL ? QStringLiteral("rtl") : QStringLiteral("ltr"));
- // if quoteLengh == 0 && foundQuote => a simple quote
- if (foundQuote) {
- quoteLength++;
- htmlStr += QStringLiteral("<span class=\"quotemarks\">%1</span>").arg(line.left(quoteLength));
- const int rightString = (line.length()) - quoteLength;
- if (rightString > 0) {
- htmlStr += QStringLiteral("<font color=\"%1\">").arg(cssHelper()->quoteColorName(actQuoteLevel)) + KTextToHTML::convertToHtml(line.right(rightString), convertFlags) + QStringLiteral("</font>");
- }
- } else {
- htmlStr += KTextToHTML::convertToHtml(line, convertFlags);
- }
-
- htmlStr += QLatin1String("</div>");
- startNewPara = looksLikeParaBreak(s, pos);
- } else {
- htmlStr += QLatin1String("<br/>");
- // after an empty line, always start a new paragraph
- startNewPara = true;
- }
- }
- previousQuoteDepth = actQuoteLevel;
- } /* while() */
-
- /* really finish the last quotelevel */
- if (currQuoteLevel == -1) {
- htmlStr.append(normalEndTag);
- } else {
- htmlStr += quoteEnd + cssHelper()->addEndBlockQuote(currQuoteLevel + 1);
- }
-
- // qCDebug(MIMETREEPARSER_LOG) << "========================================\n"
- // << htmlStr
- // << "\n======================================\n";
- return htmlStr;
-}
-
-void MessagePart::html(bool decorate)
-{
- MimeTreeParser::HtmlWriter *writer = htmlWriter();
-
- if (!writer) {
- return;
- }
-
- const HTMLBlock::Ptr aBlock(attachmentBlock());
- writer->queue(quotedHTML(text(), decorate));
-}
-
void MessagePart::parseInternal(KMime::Content *node, bool onlyOneMimePart)
{
mSubOtp = new ObjectTreeParser(mOtp, onlyOneMimePart);
@@ -458,73 +144,6 @@ void MessagePart::parseInternal(KMime::Content *node, bool onlyOneMimePart)
}
}
-HTMLBlock::Ptr MessagePart::internalRootBlock() const
-{
- if (htmlWriter() && mIsInternalRoot) {
- return HTMLBlock::Ptr(new RootBlock(htmlWriter()));
- }
- return HTMLBlock::Ptr();
-}
-
-void MessagePart::renderInternalHtml(bool decorate) const
-{
- const HTMLBlock::Ptr rBlock(internalRootBlock());
-
- foreach (const auto &mp, subParts()) {
- mp->html(decorate);
- }
-}
-
-class TestHtmlWriter : public MimeTreeParser::HtmlWriter
-{
-public:
- explicit TestHtmlWriter(MimeTreeParser::HtmlWriter *baseWriter)
- : mBaseWriter(baseWriter)
- {}
- virtual ~TestHtmlWriter() {}
-
- void begin(const QString &text) Q_DECL_OVERRIDE {mBaseWriter->begin(text);}
- void write(const QString &str) Q_DECL_OVERRIDE
- {
- html.append(str);
- }
- void end() Q_DECL_OVERRIDE {mBaseWriter->end();}
- void reset() Q_DECL_OVERRIDE {mBaseWriter->reset();}
- void queue(const QString &str) Q_DECL_OVERRIDE
- {
- html.append(str);
- }
- void flush() Q_DECL_OVERRIDE {mBaseWriter->flush();}
- void embedPart(const QByteArray &contentId, const QString &url) Q_DECL_OVERRIDE {mBaseWriter->embedPart(contentId, url);}
- void extraHead(const QString &extra) Q_DECL_OVERRIDE {mBaseWriter->extraHead(extra);}
-
- QString html;
- MimeTreeParser::HtmlWriter *mBaseWriter;
-};
-
-QString MessagePart::internalContent() const
-{
- const auto oldWriter = htmlWriter();
- TestHtmlWriter htmlWriter(oldWriter);
-
- if (oldWriter) {
- setHtmlWriter(&htmlWriter);
-
- const HTMLBlock::Ptr rBlock(internalRootBlock());
-
- foreach (const auto &mp, subParts()) {
- const auto m = mp.dynamicCast<MessagePart>();
- if (m) {
- m->setHtmlWriter(&htmlWriter);
- m->html(false);
- m->setHtmlWriter(oldWriter);
- }
- }
- setHtmlWriter(oldWriter);
- }
- return htmlWriter.html;
-}
-
QString MessagePart::renderInternalText() const
{
QString text;
diff --git a/mimetreeparser/src/viewer/messagepart.h b/mimetreeparser/src/viewer/messagepart.h
index b125939..dd8bccc 100644
--- a/mimetreeparser/src/viewer/messagepart.h
+++ b/mimetreeparser/src/viewer/messagepart.h
@@ -70,7 +70,6 @@ public:
virtual QString text() const Q_DECL_OVERRIDE;
void setText(const QString &text);
- virtual void html(bool decorate) Q_DECL_OVERRIDE;
void setAttachmentFlag(KMime::Content *node);
bool isAttachment() const;
@@ -88,18 +87,9 @@ public:
bool hasSubParts() const;
protected:
- /** Change the string to `quoted' html (meaning, that the quoted
- part of the message get italized */
- QString quotedHTML(const QString &s, bool decorate);
-
void parseInternal(KMime::Content *node, bool onlyOneMimePart);
- void renderInternalHtml(bool decorate) const;
- QString internalContent() const;
QString renderInternalText() const;
- HTMLBlockPtr attachmentBlock() const;
- HTMLBlockPtr rootBlock() const;
-
HtmlWriter* htmlWriter() const;
void setHtmlWriter(HtmlWriter *htmlWriter) const;
@@ -114,11 +104,7 @@ protected:
private:
CSSHelperBase *cssHelper() const;
- QString mCollapseIcon;
- QString mExpandIcon;
-
KMime::Content *attachmentNode() const;
- HTMLBlockPtr internalRootBlock() const;
QVector<Interface::MessagePart::Ptr> mBlocks;
bool mIsInternalRoot;