summaryrefslogtreecommitdiffstats
path: root/libtdepim/csshelper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libtdepim/csshelper.cpp')
-rw-r--r--libtdepim/csshelper.cpp647
1 files changed, 647 insertions, 0 deletions
diff --git a/libtdepim/csshelper.cpp b/libtdepim/csshelper.cpp
new file mode 100644
index 000000000..05f20e390
--- /dev/null
+++ b/libtdepim/csshelper.cpp
@@ -0,0 +1,647 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ csshelper.cpp
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2003 Marc Mutz <mutz@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ TQt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "csshelper.h"
+
+#include <kconfig.h>
+#include <kglobalsettings.h>
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include <tqstring.h>
+#include <tqapplication.h>
+
+namespace KPIM {
+
+ namespace {
+ // some TQColor manipulators that hide the ugly TQColor API w.r.t. HSV:
+ inline TQColor darker( const TQColor & c ) {
+ int h, s, v;
+ c.hsv( &h, &s, &v );
+ return TQColor( h, s, v*4/5, TQColor::Hsv );
+ }
+
+ inline TQColor desaturate( const TQColor & c ) {
+ int h, s, v;
+ c.hsv( &h, &s, &v );
+ return TQColor( h, s/8, v, TQColor::Hsv );
+ }
+
+ inline TQColor fixValue( const TQColor & c, int newV ) {
+ int h, s, v;
+ c.hsv( &h, &s, &v );
+ return TQColor( h, s, newV, TQColor::Hsv );
+ }
+
+ inline int getValueOf( const TQColor & c ) {
+ int h, s, v;
+ c.hsv( &h, &s, &v );
+ return v;
+ }
+ }
+
+ CSSHelper::CSSHelper( const TQPaintDeviceMetrics &pdm ) :
+ mShrinkQuotes( false ),
+ mMetrics( pdm )
+ {
+ // initialize with defaults - should match the corresponding application defaults
+ mForegroundColor = TQApplication::tqpalette().active().text();
+ mLinkColor = KGlobalSettings::linkColor();
+ mVisitedLinkColor = KGlobalSettings::visitedLinkColor();
+ mBackgroundColor = TQApplication::tqpalette().active().base();
+ cHtmlWarning = TQColor( 0xFF, 0x40, 0x40 ); // warning frame color: light red
+
+ cPgpEncrH = TQColor( 0x00, 0x80, 0xFF ); // light blue
+ cPgpOk1H = TQColor( 0x40, 0xFF, 0x40 ); // light green
+ cPgpOk0H = TQColor( 0xFF, 0xFF, 0x40 ); // light yellow
+ cPgpWarnH = TQColor( 0xFF, 0xFF, 0x40 ); // light yellow
+ cPgpErrH = TQt::red;
+
+ for ( int i = 0 ; i < 3 ; ++i )
+ mQuoteColor[i] = TQColor( 0x00, 0x80 - i * 0x10, 0x00 ); // shades of green
+ mRecycleQuoteColors = false;
+
+ TQFont defaultFont = KGlobalSettings::generalFont();
+ TQFont defaultFixedFont = KGlobalSettings::fixedFont();
+ mBodyFont = mPrintFont = defaultFont;
+ mFixedFont = mFixedPrintFont = defaultFixedFont;
+ defaultFont.setItalic( true );
+ for ( int i = 0 ; i < 3 ; ++i )
+ mQuoteFont[i] = defaultFont;
+
+ mBackingPixmapOn = false;
+
+ recalculatePGPColors();
+ }
+
+ void CSSHelper::recalculatePGPColors() {
+ // determine the frame and body color for PGP messages from the header color
+ // if the header color equals the background color then the other colors are
+ // also set to the background color (-> old style PGP message viewing)
+ // else
+ // the brightness of the frame is set to 4/5 of the brightness of the header
+ // and in case of a light background color
+ // the saturation of the body is set to 1/8 of the saturation of the header
+ // while in case of a dark background color
+ // the value of the body is set to the value of the background color
+
+ // Check whether the user uses a light color scheme
+ const int vBG = getValueOf( mBackgroundColor );
+ const bool lightBG = vBG >= 128;
+ if ( cPgpOk1H == mBackgroundColor ) {
+ cPgpOk1F = mBackgroundColor;
+ cPgpOk1B = mBackgroundColor;
+ } else {
+ cPgpOk1F= darker( cPgpOk1H );
+ cPgpOk1B = lightBG ? desaturate( cPgpOk1H ) : fixValue( cPgpOk1H, vBG );
+ }
+ if ( cPgpOk0H == mBackgroundColor ) {
+ cPgpOk0F = mBackgroundColor;
+ cPgpOk0B = mBackgroundColor;
+ } else {
+ cPgpOk0F = darker( cPgpOk0H );
+ cPgpOk0B = lightBG ? desaturate( cPgpOk0H ) : fixValue( cPgpOk0H, vBG );
+ }
+ if ( cPgpWarnH == mBackgroundColor ) {
+ cPgpWarnF = mBackgroundColor;
+ cPgpWarnB = mBackgroundColor;
+ } else {
+ cPgpWarnF = darker( cPgpWarnH );
+ cPgpWarnB = lightBG ? desaturate( cPgpWarnH ) : fixValue( cPgpWarnH, vBG );
+ }
+ if ( cPgpErrH == mBackgroundColor ) {
+ cPgpErrF = mBackgroundColor;
+ cPgpErrB = mBackgroundColor;
+ } else {
+ cPgpErrF = darker( cPgpErrH );
+ cPgpErrB = lightBG ? desaturate( cPgpErrH ) : fixValue( cPgpErrH, vBG );
+ }
+ if ( cPgpEncrH == mBackgroundColor ) {
+ cPgpEncrF = mBackgroundColor;
+ cPgpEncrB = mBackgroundColor;
+ } else {
+ cPgpEncrF = darker( cPgpEncrH );
+ cPgpEncrB = lightBG ? desaturate( cPgpEncrH ) : fixValue( cPgpEncrH, vBG );
+ }
+ }
+
+ TQString CSSHelper::cssDefinitions( bool fixed ) const {
+ return
+ commonCssDefinitions()
+ +
+ "@media screen {\n\n"
+ +
+ screenCssDefinitions( this, fixed )
+ +
+ "}\n"
+ "@media print {\n\n"
+ +
+ printCssDefinitions( fixed )
+ +
+ "}\n";
+ }
+
+ TQString CSSHelper::htmlHead( bool /*fixed*/ ) const {
+ return
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
+ "<html><head><title></title></head>\n"
+ "<body>\n";
+ }
+
+ TQString CSSHelper::quoteFontTag( int level ) const {
+ if ( level < 0 )
+ level = 0;
+ static const int numQuoteLevels = sizeof mQuoteFont / sizeof *mQuoteFont;
+ const int effectiveLevel = mRecycleQuoteColors
+ ? level % numQuoteLevels + 1
+ : kMin( level + 1, numQuoteLevels ) ;
+ if ( level >= numQuoteLevels )
+ return TQString( "<div class=\"deepquotelevel%1\">" ).tqarg( effectiveLevel );
+ else
+ return TQString( "<div class=\"quotelevel%1\">" ).tqarg( effectiveLevel );
+ }
+
+ TQString CSSHelper::nonQuotedFontTag() const {
+ return "<div class=\"noquote\">";
+ }
+
+ TQFont CSSHelper::bodyFont( bool fixed, bool print ) const {
+ return fixed ? ( print ? mFixedPrintFont : mFixedFont )
+ : ( print ? mPrintFont : mBodyFont );
+ }
+
+ int CSSHelper::fontSize( bool fixed, bool print ) const {
+ return bodyFont( fixed, print ).pointSize();
+ }
+
+
+ namespace {
+ int pointsToPixel( const TQPaintDeviceMetrics & metrics, int pointSize ) {
+ return ( pointSize * metrics.logicalDpiY() + 36 ) / 72 ;
+ }
+ }
+
+ static const char * const quoteFontSizes[] = { "85", "80", "75" };
+
+ TQString CSSHelper::printCssDefinitions( bool fixed ) const {
+ const TQString headerFont = TQString( " font-family: \"%1\" ! important;\n"
+ " font-size: %2pt ! important;\n" )
+ .tqarg( mPrintFont.family() )
+ .tqarg( mPrintFont.pointSize() );
+ const TQColorGroup & cg = TQApplication::tqpalette().active();
+
+ const TQFont printFont = bodyFont( fixed, true /* print */ );
+ TQString quoteCSS;
+ if ( printFont.italic() )
+ quoteCSS += " font-style: italic ! important;\n";
+ if ( printFont.bold() )
+ quoteCSS += " font-weight: bold ! important;\n";
+ if ( !quoteCSS.isEmpty() )
+ quoteCSS = "div.noquote {\n" + quoteCSS + "}\n\n";
+
+ return
+ TQString( "body {\n"
+ " font-family: \"%1\" ! important;\n"
+ " font-size: %2pt ! important;\n"
+ " color: #000000 ! important;\n"
+ " background-color: #ffffff ! important\n"
+ "}\n\n" )
+ .tqarg( printFont.family(),
+ TQString::number( printFont.pointSize() ) )
+ +
+ TQString( "tr.textAtmH,\n"
+ "tr.signInProgressH,\n"
+ "tr.rfc822H,\n"
+ "tr.encrH,\n"
+ "tr.signOkKeyOkH,\n"
+ "tr.signOkKeyBadH,\n"
+ "tr.signWarnH,\n"
+ "tr.signErrH,\n"
+ "div.header {\n"
+ "%1"
+ "}\n\n"
+
+ "div.fancy.header > div {\n"
+ " background-color: %2 ! important;\n"
+ " color: %3 ! important;\n"
+ " padding: 4px ! important;\n"
+ " border: solid %3 1px ! important;\n"
+ "}\n\n"
+
+ "div.fancy.header > div a[href] { color: %3 ! important; }\n\n"
+
+ "div.fancy.header > table.outer{\n"
+ " background-color: %2 ! important;\n"
+ " color: %3 ! important;\n"
+ " border-bottom: solid %3 1px ! important;\n"
+ " border-left: solid %3 1px ! important;\n"
+ " border-right: solid %3 1px ! important;\n"
+ "}\n\n"
+
+ "div.spamheader {\n"
+ " display:none ! important;\n"
+ "}\n\n"
+
+ "div.htmlWarn {\n"
+ " border: 2px solid #ffffff ! important;\n"
+ "}\n\n"
+
+ "div.senderpic{\n"
+ " font-size:0.8em ! important;\n"
+ " border:1px solid black ! important;\n"
+ " background-color:%2 ! important;\n"
+ "}\n\n"
+
+ "div.senderstatus{\n"
+ " text-align:center ! important;\n"
+ "}\n\n"
+
+ "div.noprint {\n"
+ " display:none ! important;\n"
+ "}\n\n"
+ )
+ .tqarg( headerFont,
+ cg.background().name(),
+ cg.foreground().name() )
+ + quoteCSS;
+ }
+
+ TQString CSSHelper::screenCssDefinitions( const CSSHelper * helper, bool fixed ) const {
+ const TQString fgColor = mForegroundColor.name();
+ const TQString bgColor = mBackgroundColor.name();
+ const TQString linkColor = mLinkColor.name();
+ const TQString headerFont = TQString(" font-family: \"%1\" ! important;\n"
+ " font-size: %2px ! important;\n")
+ .tqarg( mBodyFont.family() )
+ .tqarg( pointsToPixel( helper->mMetrics, mBodyFont.pointSize() ) );
+ const TQString background = ( mBackingPixmapOn
+ ? TQString( " background-image:url(file://%1) ! important;\n" )
+ .tqarg( mBackingPixmapStr )
+ : TQString( " background-color: %1 ! important;\n" )
+ .tqarg( bgColor ) );
+ const TQString bodyFontSize = TQString::number( pointsToPixel( helper->mMetrics, fontSize( fixed ) ) ) + "px" ;
+ const TQColorGroup & cg = TQApplication::tqpalette().active();
+
+ TQString quoteCSS;
+ if ( bodyFont( fixed ).italic() )
+ quoteCSS += " font-style: italic ! important;\n";
+ if ( bodyFont( fixed ).bold() )
+ quoteCSS += " font-weight: bold ! important;\n";
+ if ( !quoteCSS.isEmpty() )
+ quoteCSS = "div.noquote {\n" + quoteCSS + "}\n\n";
+
+ // CSS definitions for quote levels 1-3
+ for ( int i = 0 ; i < 3 ; ++i ) {
+ quoteCSS += TQString( "div.quotelevel%1 {\n"
+ " color: %2 ! important;\n" )
+ .tqarg( TQString::number(i+1), mQuoteColor[i].name() );
+ if ( mQuoteFont[i].italic() )
+ quoteCSS += " font-style: italic ! important;\n";
+ if ( mQuoteFont[i].bold() )
+ quoteCSS += " font-weight: bold ! important;\n";
+ if ( mShrinkQuotes )
+ quoteCSS += " font-size: " + TQString::tqfromLatin1( quoteFontSizes[i] )
+ + "% ! important;\n";
+ quoteCSS += "}\n\n";
+ }
+
+ // CSS definitions for quote levels 4+
+ for ( int i = 0 ; i < 3 ; ++i ) {
+ quoteCSS += TQString( "div.deepquotelevel%1 {\n"
+ " color: %2 ! important;\n" )
+ .tqarg( TQString::number(i+1), mQuoteColor[i].name() );
+ if ( mQuoteFont[i].italic() )
+ quoteCSS += " font-style: italic ! important;\n";
+ if ( mQuoteFont[i].bold() )
+ quoteCSS += " font-weight: bold ! important;\n";
+ if ( mShrinkQuotes )
+ quoteCSS += " font-size: 70% ! important;\n";
+ quoteCSS += "}\n\n";
+ }
+
+ return
+ TQString( "body {\n"
+ " font-family: \"%1\" ! important;\n"
+ " font-size: %2 ! important;\n"
+ " color: %3 ! important;\n"
+ "%4"
+ "}\n\n" )
+ .tqarg( bodyFont( fixed ).family(),
+ bodyFontSize,
+ fgColor,
+ background )
+ +
+ TQString( "a {\n"
+ " color: %1 ! important;\n"
+ " text-decoration: none ! important;\n"
+ "}\n\n"
+
+ "a.white {\n"
+ " color: white ! important;\n"
+ "}\n\n"
+
+ "a.black {\n"
+ " color: black ! important;\n"
+ "}\n\n"
+
+ "table.textAtm { background-color: %2 ! important; }\n\n"
+
+ "tr.textAtmH {\n"
+ " background-color: %3 ! important;\n"
+ "%4"
+ "}\n\n"
+
+ "tr.textAtmB {\n"
+ " background-color: %3 ! important;\n"
+ "}\n\n"
+
+ "table.signInProgress,\n"
+ "table.rfc822 {\n"
+ " background-color: %3 ! important;\n"
+ "}\n\n"
+
+ "tr.signInProgressH,\n"
+ "tr.rfc822H {\n"
+ "%4"
+ "}\n\n" )
+ .tqarg( linkColor, fgColor, bgColor, headerFont )
+ +
+ TQString( "table.encr {\n"
+ " background-color: %1 ! important;\n"
+ "}\n\n"
+
+ "tr.encrH {\n"
+ " background-color: %2 ! important;\n"
+ "%3"
+ "}\n\n"
+
+ "tr.encrB { background-color: %4 ! important; }\n\n" )
+ .tqarg( cPgpEncrF.name(),
+ cPgpEncrH.name(),
+ headerFont,
+ cPgpEncrB.name() )
+ +
+ TQString( "table.signOkKeyOk {\n"
+ " background-color: %1 ! important;\n"
+ "}\n\n"
+
+ "tr.signOkKeyOkH {\n"
+ " background-color: %2 ! important;\n"
+ "%3"
+ "}\n\n"
+
+ "tr.signOkKeyOkB { background-color: %4 ! important; }\n\n" )
+ .tqarg( cPgpOk1F.name(),
+ cPgpOk1H.name(),
+ headerFont,
+ cPgpOk1B.name() )
+ +
+ TQString( "table.signOkKeyBad {\n"
+ " background-color: %1 ! important;\n"
+ "}\n\n"
+
+ "tr.signOkKeyBadH {\n"
+ " background-color: %2 ! important;\n"
+ "%3"
+ "}\n\n"
+
+ "tr.signOkKeyBadB { background-color: %4 ! important; }\n\n" )
+ .tqarg( cPgpOk0F.name(),
+ cPgpOk0H.name(),
+ headerFont,
+ cPgpOk0B.name() )
+ +
+ TQString( "table.signWarn {\n"
+ " background-color: %1 ! important;\n"
+ "}\n\n"
+
+ "tr.signWarnH {\n"
+ " background-color: %2 ! important;\n"
+ "%3"
+ "}\n\n"
+
+ "tr.signWarnB { background-color: %4 ! important; }\n\n" )
+ .tqarg( cPgpWarnF.name(),
+ cPgpWarnH.name(),
+ headerFont,
+ cPgpWarnB.name() )
+ +
+ TQString( "table.signErr {\n"
+ " background-color: %1 ! important;\n"
+ "}\n\n"
+
+ "tr.signErrH {\n"
+ " background-color: %2 ! important;\n"
+ "%3"
+ "}\n\n"
+
+ "tr.signErrB { background-color: %4 ! important; }\n\n" )
+ .tqarg( cPgpErrF.name(),
+ cPgpErrH.name(),
+ headerFont,
+ cPgpErrB.name() )
+ +
+ TQString( "div.htmlWarn {\n"
+ " border: 2px solid %1 ! important;\n"
+ "}\n\n" )
+ .tqarg( cHtmlWarning.name() )
+ +
+ TQString( "div.header {\n"
+ "%1"
+ "}\n\n"
+
+ "div.fancy.header > div {\n"
+ " background-color: %2 ! important;\n"
+ " color: %3 ! important;\n"
+ " border: solid %4 1px ! important;\n"
+ "}\n\n"
+
+ "div.fancy.header > div a[href] { color: %3 ! important; }\n\n"
+
+ "div.fancy.header > div a[href]:hover { text-decoration: underline ! important; }\n\n"
+
+ "div.fancy.header > div.spamheader {\n"
+ " background-color: #cdcdcd ! important;\n"
+ " border-top: 0px ! important;\n"
+ " padding: 3px ! important;\n"
+ " color: black ! important;\n"
+ " font-weight: bold ! important;\n"
+ " font-size: smaller ! important;\n"
+ "}\n\n"
+
+ "div.fancy.header > table.outer {\n"
+ " background-color: %5 ! important;\n"
+ " color: %4 ! important;\n"
+ " border-bottom: solid %4 1px ! important;\n"
+ " border-left: solid %4 1px ! important;\n"
+ " border-right: solid %4 1px ! important;\n"
+ "}\n\n"
+
+ "div.senderpic{\n"
+ " padding: 0px ! important;\n"
+ " font-size:0.8em ! important;\n"
+ " border:1px solid %6 ! important;\n"
+ // FIXME: InfoBackground crashes KHTML
+ //" background-color:InfoBackground ! important;\n"
+ " background-color:%5 ! important;\n"
+ "}\n\n"
+
+ "div.senderstatus{\n"
+ " text-align:center ! important;\n"
+ "}\n\n"
+ )
+
+ .tqarg( headerFont )
+ .tqarg( cg.highlight().name(),
+ cg.highlightedText().name(),
+ cg.foreground().name(),
+ cg.background().name() )
+ .tqarg( cg.mid().name() )
+ + quoteCSS;
+ }
+
+ TQString CSSHelper::commonCssDefinitions() const {
+ return
+ "div.header {\n"
+ " margin-bottom: 10pt ! important;\n"
+ "}\n\n"
+
+ "table.textAtm {\n"
+ " margin-top: 10pt ! important;\n"
+ " margin-bottom: 10pt ! important;\n"
+ "}\n\n"
+
+ "tr.textAtmH,\n"
+ "tr.textAtmB,\n"
+ "tr.rfc822B {\n"
+ " font-weight: normal ! important;\n"
+ "}\n\n"
+
+ "tr.signInProgressH,\n"
+ "tr.rfc822H,\n"
+ "tr.encrH,\n"
+ "tr.signOkKeyOkH,\n"
+ "tr.signOkKeyBadH,\n"
+ "tr.signWarnH,\n"
+ "tr.signErrH {\n"
+ " font-weight: bold ! important;\n"
+ "}\n\n"
+
+ "tr.textAtmH td,\n"
+ "tr.textAtmB td {\n"
+ " padding: 3px ! important;\n"
+ "}\n\n"
+
+ "table.rfc822 {\n"
+ " width: 100% ! important;\n"
+ " border: solid 1px black ! important;\n"
+ " margin-top: 10pt ! important;\n"
+ " margin-bottom: 10pt ! important;\n"
+ "}\n\n"
+
+ "table.textAtm,\n"
+ "table.encr,\n"
+ "table.signWarn,\n"
+ "table.signErr,\n"
+ "table.signOkKeyBad,\n"
+ "table.signOkKeyOk,\n"
+ "table.signInProgress,\n"
+ "div.fancy.header table {\n"
+ " width: 100% ! important;\n"
+ " border-width: 0px ! important;\n"
+ "}\n\n"
+
+ "div.htmlWarn {\n"
+ " margin: 0px 5% ! important;\n"
+ " padding: 10px ! important;\n"
+ " text-align: left ! important;\n"
+ "}\n\n"
+
+ "div.fancy.header > div {\n"
+ " font-weight: bold ! important;\n"
+ " padding: 4px ! important;\n"
+ "}\n\n"
+
+ "div.fancy.header table {\n"
+ " padding: 2px ! important;\n" // ### khtml bug: this is ignored
+ " text-align: left ! important\n"
+ "}\n\n"
+
+ "div.fancy.header table th {\n"
+ " padding: 0px ! important;\n"
+ " white-space: nowrap ! important;\n"
+ " border-spacing: 0px ! important;\n"
+ " text-align: left ! important;\n"
+ " vertical-align: top ! important;\n"
+ "}\n\n"
+
+ "div.fancy.header table td {\n"
+ " padding: 0px ! important;\n"
+ " border-spacing: 0px ! important;\n"
+ " text-align: left ! important;\n"
+ " vertical-align: top ! important;\n"
+ " width: 100% ! important;\n"
+ "}\n\n"
+
+ "span.pimsmileytext {\n"
+ " position: absolute;\n"
+ " top: 0px;\n"
+ " left: 0px;\n"
+ " visibility: hidden;\n"
+ "}\n\n"
+
+ "img.pimsmileyimg {\n"
+ "}\n\n"
+
+ "div.quotelevelmark {\n"
+ " position: absolute;\n"
+ " margin-left:-10px;\n"
+ "}\n\n"
+ ;
+ }
+
+
+ void CSSHelper::setBodyFont( const TQFont& font )
+ {
+ mBodyFont = font;
+ }
+
+ void CSSHelper::setPrintFont( const TQFont& font )
+ {
+ mPrintFont = font;
+ }
+
+ TQColor CSSHelper::pgpWarnColor() const
+ {
+ return cPgpWarnH;
+ }
+
+} // namespace KPIM