diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a8ec5a88..1da675151 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -245,6 +245,7 @@ set(kmailprivate_LIB_SRCS stringutil.cpp iconnamecache.cpp mdnadvicedialog.cpp + htmlquotecolorer.cpp messagelistview/messageset.cpp messagelistview/pane.cpp messagelistview/storagemodel.cpp diff --git a/htmlquotecolorer.cpp b/htmlquotecolorer.cpp new file mode 100644 index 000000000..fcef2e31c --- /dev/null +++ b/htmlquotecolorer.cpp @@ -0,0 +1,111 @@ +/* Copyright 2009 Thomas McGuire + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License or + ( at your option ) version 3 or, at the discretion of KDE e.V. + ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include "htmlquotecolorer.h" + +#include "csshelper.h" + +#include +#include + +namespace KMail { + +HTMLQuoteColorer::HTMLQuoteColorer( KPIM::CSSHelper *cssHelper ) + : mCSSHelper( cssHelper ) +{ +} + +QString HTMLQuoteColorer::process( const QString &htmlSource ) +{ + // Create a DOM Document from the HTML source + DOM::HTMLDocument doc; + doc.open(); + doc.write( htmlSource ); + doc.close(); + + mIsQuotedLine = false; + mIsFirstTextNodeInLine = true; + processNode( doc.documentElement() ); + return doc.toString().string(); +} + +DOM::Node HTMLQuoteColorer::processNode( DOM::Node node ) +{ + // Below, we determine if the current text node should be quote colored by keeping track of + // linebreaks and wether this text node is the first one. + const QString textContent = node.textContent().string(); + const bool isTextNode = !textContent.isEmpty() && !node.hasChildNodes(); + if ( isTextNode ) { + if ( mIsFirstTextNodeInLine ) { + if ( textContent.simplified().startsWith( '>' ) || + textContent.simplified().startsWith( '|' ) ) { + mIsQuotedLine = true; + currentQuoteLength = quoteLength( textContent ) - 1; + } + else { + mIsQuotedLine = false; + } + } + + // All subsequent text nodes are not the first ones anymore + mIsFirstTextNodeInLine = false; + } + + const QString nodeName = node.nodeName().string().toLower(); + if ( nodeName == "br" || nodeName == "p" ) { // FIXME: Are there more newline nodes? + mIsFirstTextNodeInLine = true; + } + + DOM::Node returnNode = node; + bool fontTagAdded = false; + if ( mIsQuotedLine && isTextNode ) { + + // Ok, we are in a line that should be quoted, so create a font node for the color and replace + // the current node with it. + DOM::Element font = node.ownerDocument().createElement( QString( "font" ) ); + font.setAttribute( QString( "color" ), mCSSHelper->quoteColor( currentQuoteLength ).name() ); + node.parentNode().replaceChild( font, node ); + font.appendChild( node ); + returnNode = font; + fontTagAdded = true; + } + + // Process all child nodes, but only if we are didn't add those child nodes itself, as otherwise + // we'll go into an infinite recursion. + if ( !fontTagAdded ) { + DOM::Node childNode = node.firstChild(); + while ( !childNode.isNull() ) { + childNode = processNode( childNode ); + childNode = childNode.nextSibling(); + } + } + return returnNode; +} + +int HTMLQuoteColorer::quoteLength( const QString &line ) const +{ + QString simplified = line.simplified(); + simplified = simplified.replace( QRegExp( QLatin1String( "\\s" ) ), QString() ) + .replace( QLatin1Char( '|' ), QLatin1Char( '>' ) ); + if ( simplified.startsWith( ">>>" ) ) return 3; + if ( simplified.startsWith( ">>" ) ) return 2; + if ( simplified.startsWith( ">" ) ) return 1; + return 0; +} + +} diff --git a/htmlquotecolorer.h b/htmlquotecolorer.h new file mode 100644 index 000000000..ad3458ce9 --- /dev/null +++ b/htmlquotecolorer.h @@ -0,0 +1,64 @@ +/* Copyright 2009 Thomas McGuire + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License or + ( at your option ) version 3 or, at the discretion of KDE e.V. + ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef _HTMLQUOTECOLERER_H +#define _HTMLQUOTECOLERER_H + +#include + +namespace KPIM +{ + class CSSHelper; +} + +namespace KMail +{ + +/** + * Little helper class that takes a HTML source as input and finds all + * lines that are quoted with '>' or '|'. The HTML text is then modified so + * that the quoted lines appear in the defined quote colors. + */ +class HTMLQuoteColorer +{ + public: + + /** @param cssHelper the CSSHelper used for rendering, we get the quote colors from it */ + explicit HTMLQuoteColorer( KPIM::CSSHelper *cssHelper ); + + /** + * Do the work and add nice colors to the HTML. + * @param htmlSource the input HTML code + * @return the modified HTML code + */ + QString process( const QString &htmlSource ); + + private: + + DOM::Node processNode( DOM::Node node ); + int quoteLength( const QString &line ) const; + + KPIM::CSSHelper *mCSSHelper; + bool mIsQuotedLine; + bool mIsFirstTextNodeInLine; + int currentQuoteLength; +}; + +} + +#endif diff --git a/objecttreeparser.cpp b/objecttreeparser.cpp index 13142ced2..ed6bca685 100644 --- a/objecttreeparser.cpp +++ b/objecttreeparser.cpp @@ -54,6 +54,7 @@ #include "stringutil.h" #include "iconnamecache.h" #include "autoqpointer.h" +#include "htmlquotecolorer.h" // other module headers #include @@ -985,6 +986,9 @@ bool ObjectTreeParser::okDecryptMIME( partNode& data, { if ( mReader->htmlMail() ) { + HTMLQuoteColorer colorer( cssHelper() ); + bodyText = colorer.process( bodyText ); + // Strip , , and , so we don't end up having those tags // twice, which confuses KHTML (especially with a signed // multipart/alternative message, the signature bars get rendered at the