1
/* -*- mode: C++; c-file-style: "gnu" -*-
4
This file is part of KMail, the KDE mail client.
5
Copyright (c) 2003 Marc Mutz <mutz@kde.org>
7
KMail is free software; you can redistribute it and/or modify it
8
under the terms of the GNU General Public License, version 2, as
9
published by the Free Software Foundation.
11
KMail is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
General Public License for more details.
16
You should have received a copy of the GNU General Public License along
17
with this program; if not, write to the Free Software Foundation, Inc.,
18
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
In addition, as a special exception, the copyright holders give
21
permission to link the code of this program with any edition of
22
the Qt library by Trolltech AS, Norway (or with modified versions
23
of Qt that use the same license as Qt), and distribute linked
24
combinations including the two. You must obey the GNU General
25
Public License in all respects for all of the code used other than
26
Qt. If you modify this file, you may extend this exception to
27
your version of the file, but you are not obligated to do so. If
28
you do not wish to do so, delete this exception statement from
32
#include "csshelper.h"
34
#include <KColorScheme>
38
#include <KGlobalSettings>
41
#include <QApplication>
42
#include <QPaintDevice>
47
// some QColor manipulators that hide the ugly QColor API w.r.t. HSV:
48
inline QColor darker( const QColor & c ) {
50
c.getHsv( &h, &s, &v );
51
return QColor::fromHsv( h, s, v*4/5 );
54
inline QColor desaturate( const QColor & c ) {
56
c.getHsv( &h, &s, &v );
57
return QColor::fromHsv( h, s/8, v );
60
inline QColor fixValue( const QColor & c, int newV ) {
62
c.getHsv( &h, &s, &v );
63
return QColor::fromHsv( h, s, newV );
66
inline int getValueOf( const QColor & c ) {
68
c.getHsv( &h, &s, &v );
73
CSSHelper::CSSHelper( const QPaintDevice *pd ) :
74
mShrinkQuotes( false ),
77
// initialize with defaults - should match the corresponding application defaults
78
mForegroundColor = QApplication::palette().color( QPalette::Text );
79
mLinkColor = KColorScheme( QPalette::Active, KColorScheme::View ).foreground( KColorScheme::LinkText ).color();
80
mVisitedLinkColor = KColorScheme( QPalette::Active, KColorScheme::View ).foreground( KColorScheme::VisitedText ).color();
81
mBackgroundColor = QApplication::palette().color( QPalette::Base );
82
cHtmlWarning = QColor( 0xFF, 0x40, 0x40 ); // warning frame color: light red
84
cPgpEncrH = QColor( 0x00, 0x80, 0xFF ); // light blue
85
cPgpOk1H = QColor( 0x40, 0xFF, 0x40 ); // light green
86
cPgpOk0H = QColor( 0xFF, 0xFF, 0x40 ); // light yellow
87
cPgpWarnH = QColor( 0xFF, 0xFF, 0x40 ); // light yellow
90
for ( int i = 0 ; i < 3 ; ++i )
91
mQuoteColor[i] = QColor( 0x00, 0x80 - i * 0x10, 0x00 ); // shades of green
92
mRecycleQuoteColors = false;
94
QFont defaultFont = KGlobalSettings::generalFont();
95
QFont defaultFixedFont = KGlobalSettings::fixedFont();
96
mBodyFont = mPrintFont = defaultFont;
97
mFixedFont = mFixedPrintFont = defaultFixedFont;
98
defaultFont.setItalic( true );
99
for ( int i = 0 ; i < 3 ; ++i )
100
mQuoteFont[i] = defaultFont;
102
mBackingPixmapOn = false;
104
recalculatePGPColors();
107
void CSSHelper::recalculatePGPColors() {
108
// determine the frame and body color for PGP messages from the header color
109
// if the header color equals the background color then the other colors are
110
// also set to the background color (-> old style PGP message viewing)
112
// the brightness of the frame is set to 4/5 of the brightness of the header
113
// and in case of a light background color
114
// the saturation of the body is set to 1/8 of the saturation of the header
115
// while in case of a dark background color
116
// the value of the body is set to the value of the background color
118
// Check whether the user uses a light color scheme
119
const int vBG = getValueOf( mBackgroundColor );
120
const bool lightBG = vBG >= 128;
121
if ( cPgpOk1H == mBackgroundColor ) {
122
cPgpOk1F = mBackgroundColor;
123
cPgpOk1B = mBackgroundColor;
125
cPgpOk1F= darker( cPgpOk1H );
126
cPgpOk1B = lightBG ? desaturate( cPgpOk1H ) : fixValue( cPgpOk1H, vBG );
128
if ( cPgpOk0H == mBackgroundColor ) {
129
cPgpOk0F = mBackgroundColor;
130
cPgpOk0B = mBackgroundColor;
132
cPgpOk0F = darker( cPgpOk0H );
133
cPgpOk0B = lightBG ? desaturate( cPgpOk0H ) : fixValue( cPgpOk0H, vBG );
135
if ( cPgpWarnH == mBackgroundColor ) {
136
cPgpWarnF = mBackgroundColor;
137
cPgpWarnB = mBackgroundColor;
139
cPgpWarnF = darker( cPgpWarnH );
140
cPgpWarnB = lightBG ? desaturate( cPgpWarnH ) : fixValue( cPgpWarnH, vBG );
142
if ( cPgpErrH == mBackgroundColor ) {
143
cPgpErrF = mBackgroundColor;
144
cPgpErrB = mBackgroundColor;
146
cPgpErrF = darker( cPgpErrH );
147
cPgpErrB = lightBG ? desaturate( cPgpErrH ) : fixValue( cPgpErrH, vBG );
149
if ( cPgpEncrH == mBackgroundColor ) {
150
cPgpEncrF = mBackgroundColor;
151
cPgpEncrB = mBackgroundColor;
153
cPgpEncrF = darker( cPgpEncrH );
154
cPgpEncrB = lightBG ? desaturate( cPgpEncrH ) : fixValue( cPgpEncrH, vBG );
158
QString CSSHelper::cssDefinitions( bool fixed ) const {
160
commonCssDefinitions()
162
"@media screen {\n\n"
164
screenCssDefinitions( this, fixed )
169
printCssDefinitions( fixed )
174
QString CSSHelper::htmlHead( bool /*fixed*/ ) const {
176
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
177
"<html><head><title></title></head>\n"
181
QString CSSHelper::quoteFontTag( int level ) const {
184
static const int numQuoteLevels = sizeof mQuoteFont / sizeof *mQuoteFont;
185
const int effectiveLevel = mRecycleQuoteColors
186
? level % numQuoteLevels + 1
187
: qMin( level + 1, numQuoteLevels ) ;
188
if ( level >= numQuoteLevels )
189
return QString( "<div class=\"deepquotelevel%1\">" ).arg( effectiveLevel );
191
return QString( "<div class=\"quotelevel%1\">" ).arg( effectiveLevel );
194
QString CSSHelper::nonQuotedFontTag() const {
195
return "<div class=\"noquote\">";
198
QFont CSSHelper::bodyFont( bool fixed, bool print ) const {
199
return fixed ? ( print ? mFixedPrintFont : mFixedFont )
200
: ( print ? mPrintFont : mBodyFont );
203
int CSSHelper::fontSize( bool fixed, bool print ) const {
204
return bodyFont( fixed, print ).pointSize();
209
int pointsToPixel( const QPaintDevice *pd, int pointSize ) {
210
return ( pointSize * pd->logicalDpiY() + 36 ) / 72 ;
214
static const char * const quoteFontSizes[] = { "85", "80", "75" };
216
QString CSSHelper::printCssDefinitions( bool fixed ) const {
217
const QString headerFont = QString( " font-family: \"%1\" ! important;\n"
218
" font-size: %2pt ! important;\n" )
219
.arg( mPrintFont.family() )
220
.arg( mPrintFont.pointSize() );
221
const QPalette &pal = QApplication::palette();
223
const QFont printFont = bodyFont( fixed, true /* print */ );
225
if ( printFont.italic() )
226
quoteCSS += " font-style: italic ! important;\n";
227
if ( printFont.bold() )
228
quoteCSS += " font-weight: bold ! important;\n";
229
if ( !quoteCSS.isEmpty() )
230
quoteCSS = "div.noquote {\n" + quoteCSS + "}\n\n";
234
" font-family: \"%1\" ! important;\n"
235
" font-size: %2pt ! important;\n"
236
" color: #000000 ! important;\n"
237
" background-color: #ffffff ! important\n"
239
.arg( printFont.family(),
240
QString::number( printFont.pointSize() ) )
242
QString( "tr.textAtmH,\n"
243
"tr.signInProgressH,\n"
247
"tr.signOkKeyBadH,\n"
254
"div.fancy.header > div {\n"
255
" background-color: %2 ! important;\n"
256
" color: %3 ! important;\n"
257
" padding: 4px ! important;\n"
258
" border: solid %3 1px ! important;\n"
261
"div.fancy.header > div a[href] { color: %3 ! important; }\n\n"
263
"div.fancy.header > table.outer{\n"
264
" background-color: %2 ! important;\n"
265
" color: %3 ! important;\n"
266
" border-bottom: solid %3 1px ! important;\n"
267
" border-left: solid %3 1px ! important;\n"
268
" border-right: solid %3 1px ! important;\n"
272
" display:none ! important;\n"
276
" border: 2px solid #ffffff ! important;\n"
280
" font-size:0.8em ! important;\n"
281
" border:1px solid black ! important;\n"
282
" background-color:%2 ! important;\n"
285
"div.senderstatus{\n"
286
" text-align:center ! important;\n"
290
" display:none ! important;\n"
294
pal.color( QPalette::Background ).name(),
295
pal.color( QPalette::Foreground ).name() )
299
QString CSSHelper::screenCssDefinitions( const CSSHelper * helper, bool fixed ) const {
300
const QString fgColor = mForegroundColor.name();
301
const QString bgColor = mBackgroundColor.name();
302
const QString linkColor = mLinkColor.name();
303
const QString headerFont = QString(" font-family: \"%1\" ! important;\n"
304
" font-size: %2px ! important;\n")
305
.arg( mBodyFont.family() )
306
.arg( pointsToPixel( helper->mPaintDevice, mBodyFont.pointSize() ) );
307
const QString background = ( mBackingPixmapOn
308
? QString( " background-image:url(file://%1) ! important;\n" )
309
.arg( mBackingPixmapStr )
310
: QString( " background-color: %1 ! important;\n" )
312
const QString bodyFontSize = QString::number( pointsToPixel( helper->mPaintDevice, fontSize( fixed ) ) ) + "px" ;
313
const QPalette & pal = QApplication::palette();
316
if ( bodyFont( fixed ).italic() )
317
quoteCSS += " font-style: italic ! important;\n";
318
if ( bodyFont( fixed ).bold() )
319
quoteCSS += " font-weight: bold ! important;\n";
320
if ( !quoteCSS.isEmpty() )
321
quoteCSS = "div.noquote {\n" + quoteCSS + "}\n\n";
323
// CSS definitions for quote levels 1-3
324
for ( int i = 0 ; i < 3 ; ++i ) {
325
quoteCSS += QString( "div.quotelevel%1 {\n"
326
" color: %2 ! important;\n" )
327
.arg( QString::number(i+1), mQuoteColor[i].name() );
328
if ( mQuoteFont[i].italic() )
329
quoteCSS += " font-style: italic ! important;\n";
330
if ( mQuoteFont[i].bold() )
331
quoteCSS += " font-weight: bold ! important;\n";
333
quoteCSS += " font-size: " + QString::fromLatin1( quoteFontSizes[i] )
334
+ "% ! important;\n";
338
// CSS definitions for quote levels 4+
339
for ( int i = 0 ; i < 3 ; ++i ) {
340
quoteCSS += QString( "div.deepquotelevel%1 {\n"
341
" color: %2 ! important;\n" )
342
.arg( QString::number(i+1), mQuoteColor[i].name() );
343
if ( mQuoteFont[i].italic() )
344
quoteCSS += " font-style: italic ! important;\n";
345
if ( mQuoteFont[i].bold() )
346
quoteCSS += " font-weight: bold ! important;\n";
348
quoteCSS += " font-size: 70% ! important;\n";
354
" font-family: \"%1\" ! important;\n"
355
" font-size: %2 ! important;\n"
356
" color: %3 ! important;\n"
359
.arg( bodyFont( fixed ).family(),
365
" color: %1 ! important;\n"
366
" text-decoration: none ! important;\n"
370
" color: white ! important;\n"
374
" color: black ! important;\n"
377
"table.textAtm { background-color: %2 ! important; }\n\n"
380
" background-color: %3 ! important;\n"
385
" background-color: %3 ! important;\n"
388
"table.signInProgress,\n"
390
" background-color: %3 ! important;\n"
393
"tr.signInProgressH,\n"
397
.arg( linkColor, fgColor, bgColor, headerFont )
399
QString( "table.encr {\n"
400
" background-color: %1 ! important;\n"
404
" background-color: %2 ! important;\n"
408
"tr.encrB { background-color: %4 ! important; }\n\n" )
409
.arg( cPgpEncrF.name(),
414
QString( "table.signOkKeyOk {\n"
415
" background-color: %1 ! important;\n"
418
"tr.signOkKeyOkH {\n"
419
" background-color: %2 ! important;\n"
423
"tr.signOkKeyOkB { background-color: %4 ! important; }\n\n" )
424
.arg( cPgpOk1F.name(),
429
QString( "table.signOkKeyBad {\n"
430
" background-color: %1 ! important;\n"
433
"tr.signOkKeyBadH {\n"
434
" background-color: %2 ! important;\n"
438
"tr.signOkKeyBadB { background-color: %4 ! important; }\n\n" )
439
.arg( cPgpOk0F.name(),
444
QString( "table.signWarn {\n"
445
" background-color: %1 ! important;\n"
449
" background-color: %2 ! important;\n"
453
"tr.signWarnB { background-color: %4 ! important; }\n\n" )
454
.arg( cPgpWarnF.name(),
459
QString( "table.signErr {\n"
460
" background-color: %1 ! important;\n"
464
" background-color: %2 ! important;\n"
468
"tr.signErrB { background-color: %4 ! important; }\n\n" )
469
.arg( cPgpErrF.name(),
474
QString( "div.htmlWarn {\n"
475
" border: 2px solid %1 ! important;\n"
477
.arg( cHtmlWarning.name() )
479
QString( "div.header {\n"
483
"div.fancy.header > div {\n"
484
" background-color: %2 ! important;\n"
485
" color: %3 ! important;\n"
486
" border: solid %4 1px ! important;\n"
489
"div.fancy.header > div a[href] { color: %3 ! important; }\n\n"
491
"div.fancy.header > div a[href]:hover { text-decoration: underline ! important; }\n\n"
493
"div.fancy.header > div.spamheader {\n"
494
" background-color: #cdcdcd ! important;\n"
495
" border-top: 0px ! important;\n"
496
" padding: 3px ! important;\n"
497
" color: black ! important;\n"
498
" font-weight: bold ! important;\n"
499
" font-size: smaller ! important;\n"
502
"div.fancy.header > table.outer {\n"
503
" background-color: %5 ! important;\n"
504
" color: %4 ! important;\n"
505
" border-bottom: solid %4 1px ! important;\n"
506
" border-left: solid %4 1px ! important;\n"
507
" border-right: solid %4 1px ! important;\n"
511
" padding: 0px ! important;\n"
512
" font-size:0.8em ! important;\n"
513
" border:1px solid %6 ! important;\n"
514
// FIXME: InfoBackground crashes KHTML
515
//" background-color:InfoBackground ! important;\n"
516
" background-color:%5 ! important;\n"
519
"div.senderstatus{\n"
520
" text-align:center ! important;\n"
525
.arg( pal.color( QPalette::Highlight ).name(),
526
pal.color( QPalette::HighlightedText ).name(),
527
pal.color( QPalette::Foreground ).name(),
528
pal.color( QPalette::Background ).name() )
529
.arg( pal.color( QPalette::Mid ).name() )
533
QString CSSHelper::commonCssDefinitions() const {
536
" margin-bottom: 10pt ! important;\n"
540
" margin-top: 10pt ! important;\n"
541
" margin-bottom: 10pt ! important;\n"
547
" font-weight: normal ! important;\n"
550
"tr.signInProgressH,\n"
554
"tr.signOkKeyBadH,\n"
557
" font-weight: bold ! important;\n"
562
" padding: 3px ! important;\n"
566
" width: 100% ! important;\n"
567
" border: solid 1px black ! important;\n"
568
" margin-top: 10pt ! important;\n"
569
" margin-bottom: 10pt ! important;\n"
576
"table.signOkKeyBad,\n"
577
"table.signOkKeyOk,\n"
578
"table.signInProgress,\n"
579
"div.fancy.header table {\n"
580
" width: 100% ! important;\n"
581
" border-width: 0px ! important;\n"
585
" margin: 0px 5% ! important;\n"
586
" padding: 10px ! important;\n"
587
" text-align: left ! important;\n"
590
"div.fancy.header > div {\n"
591
" font-weight: bold ! important;\n"
592
" padding: 4px ! important;\n"
595
"div.fancy.header table {\n"
596
" padding: 2px ! important;\n" // ### khtml bug: this is ignored
597
" text-align: left ! important\n"
600
"div.fancy.header table th {\n"
601
" padding: 0px ! important;\n"
602
" white-space: nowrap ! important;\n"
603
" border-spacing: 0px ! important;\n"
604
" text-align: left ! important;\n"
605
" vertical-align: top ! important;\n"
608
"div.fancy.header table td {\n"
609
" padding: 0px ! important;\n"
610
" border-spacing: 0px ! important;\n"
611
" text-align: left ! important;\n"
612
" vertical-align: top ! important;\n"
613
" width: 100% ! important;\n"
616
"span.pimsmileytext {\n"
617
" position: absolute;\n"
620
" visibility: hidden;\n"
623
"img.pimsmileyimg {\n"
626
"div.quotelevelmark {\n"
627
" position: absolute;\n"
628
" margin-left:-10px;\n"
634
void CSSHelper::setBodyFont( const QFont& font )
639
void CSSHelper::setPrintFont( const QFont& font )
644
QColor CSSHelper::quoteColor( int level )
646
const int actualLevel = qMin( qMax( level, 0 ), 2 );
647
return mQuoteColor[actualLevel];
650
QColor CSSHelper::pgpWarnColor() const