00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "csshelper.h"
00033
00034 #include <kconfig.h>
00035 #include <kglobalsettings.h>
00036 #include <kdebug.h>
00037 #include <kglobal.h>
00038
00039 #include <qstring.h>
00040 #include <qapplication.h>
00041
00042 namespace KPIM {
00043
00044 namespace {
00045
00046 inline QColor darker( const QColor & c ) {
00047 int h, s, v;
00048 c.hsv( &h, &s, &v );
00049 return QColor( h, s, v*4/5, QColor::Hsv );
00050 }
00051
00052 inline QColor desaturate( const QColor & c ) {
00053 int h, s, v;
00054 c.hsv( &h, &s, &v );
00055 return QColor( h, s/8, v, QColor::Hsv );
00056 }
00057
00058 inline QColor fixValue( const QColor & c, int newV ) {
00059 int h, s, v;
00060 c.hsv( &h, &s, &v );
00061 return QColor( h, s, newV, QColor::Hsv );
00062 }
00063
00064 inline int getValueOf( const QColor & c ) {
00065 int h, s, v;
00066 c.hsv( &h, &s, &v );
00067 return v;
00068 }
00069 }
00070
00071 CSSHelper::CSSHelper( const QPaintDeviceMetrics &pdm ) :
00072 mShrinkQuotes( false ),
00073 mMetrics( pdm )
00074 {
00075
00076 mForegroundColor = QApplication::palette().active().text();
00077 mLinkColor = KGlobalSettings::linkColor();
00078 mVisitedLinkColor = KGlobalSettings::visitedLinkColor();
00079 mBackgroundColor = QApplication::palette().active().base();
00080 cHtmlWarning = QColor( 0xFF, 0x40, 0x40 );
00081
00082 cPgpEncrH = QColor( 0x00, 0x80, 0xFF );
00083 cPgpOk1H = QColor( 0x40, 0xFF, 0x40 );
00084 cPgpOk0H = QColor( 0xFF, 0xFF, 0x40 );
00085 cPgpWarnH = QColor( 0xFF, 0xFF, 0x40 );
00086 cPgpErrH = Qt::red;
00087
00088 for ( int i = 0 ; i < 3 ; ++i )
00089 mQuoteColor[i] = QColor( 0x00, 0x80 - i * 0x10, 0x00 );
00090 mRecycleQuoteColors = false;
00091
00092 QFont defaultFont = KGlobalSettings::generalFont();
00093 QFont defaultFixedFont = KGlobalSettings::fixedFont();
00094 mBodyFont = mPrintFont = defaultFont;
00095 mFixedFont = mFixedPrintFont = defaultFixedFont;
00096 defaultFont.setItalic( true );
00097 for ( int i = 0 ; i < 3 ; ++i )
00098 mQuoteFont[i] = defaultFont;
00099
00100 mBackingPixmapOn = false;
00101
00102 recalculatePGPColors();
00103 }
00104
00105 void CSSHelper::recalculatePGPColors() {
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 const int vBG = getValueOf( mBackgroundColor );
00118 const bool lightBG = vBG >= 128;
00119 if ( cPgpOk1H == mBackgroundColor ) {
00120 cPgpOk1F = mBackgroundColor;
00121 cPgpOk1B = mBackgroundColor;
00122 } else {
00123 cPgpOk1F= darker( cPgpOk1H );
00124 cPgpOk1B = lightBG ? desaturate( cPgpOk1H ) : fixValue( cPgpOk1H, vBG );
00125 }
00126 if ( cPgpOk0H == mBackgroundColor ) {
00127 cPgpOk0F = mBackgroundColor;
00128 cPgpOk0B = mBackgroundColor;
00129 } else {
00130 cPgpOk0F = darker( cPgpOk0H );
00131 cPgpOk0B = lightBG ? desaturate( cPgpOk0H ) : fixValue( cPgpOk0H, vBG );
00132 }
00133 if ( cPgpWarnH == mBackgroundColor ) {
00134 cPgpWarnF = mBackgroundColor;
00135 cPgpWarnB = mBackgroundColor;
00136 } else {
00137 cPgpWarnF = darker( cPgpWarnH );
00138 cPgpWarnB = lightBG ? desaturate( cPgpWarnH ) : fixValue( cPgpWarnH, vBG );
00139 }
00140 if ( cPgpErrH == mBackgroundColor ) {
00141 cPgpErrF = mBackgroundColor;
00142 cPgpErrB = mBackgroundColor;
00143 } else {
00144 cPgpErrF = darker( cPgpErrH );
00145 cPgpErrB = lightBG ? desaturate( cPgpErrH ) : fixValue( cPgpErrH, vBG );
00146 }
00147 if ( cPgpEncrH == mBackgroundColor ) {
00148 cPgpEncrF = mBackgroundColor;
00149 cPgpEncrB = mBackgroundColor;
00150 } else {
00151 cPgpEncrF = darker( cPgpEncrH );
00152 cPgpEncrB = lightBG ? desaturate( cPgpEncrH ) : fixValue( cPgpEncrH, vBG );
00153 }
00154 }
00155
00156 QString CSSHelper::cssDefinitions( bool fixed ) const {
00157 return
00158 commonCssDefinitions()
00159 +
00160 "@media screen {\n\n"
00161 +
00162 screenCssDefinitions( this, fixed )
00163 +
00164 "}\n"
00165 "@media print {\n\n"
00166 +
00167 printCssDefinitions( fixed )
00168 +
00169 "}\n";
00170 }
00171
00172 QString CSSHelper::htmlHead( bool ) const {
00173 return
00174 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
00175 "<html><head><title></title></head>\n"
00176 "<body>\n";
00177 }
00178
00179 QString CSSHelper::quoteFontTag( int level ) const {
00180 if ( level < 0 )
00181 level = 0;
00182 static const int numQuoteLevels = sizeof mQuoteFont / sizeof *mQuoteFont;
00183 const int effectiveLevel = mRecycleQuoteColors
00184 ? level % numQuoteLevels + 1
00185 : kMin( level + 1, numQuoteLevels ) ;
00186 if ( level >= numQuoteLevels )
00187 return QString( "<div class=\"deepquotelevel%1\">" ).arg( effectiveLevel );
00188 else
00189 return QString( "<div class=\"quotelevel%1\">" ).arg( effectiveLevel );
00190 }
00191
00192 QString CSSHelper::nonQuotedFontTag() const {
00193 return "<div class=\"noquote\">";
00194 }
00195
00196 QFont CSSHelper::bodyFont( bool fixed, bool print ) const {
00197 return fixed ? ( print ? mFixedPrintFont : mFixedFont )
00198 : ( print ? mPrintFont : mBodyFont );
00199 }
00200
00201 int CSSHelper::fontSize( bool fixed, bool print ) const {
00202 return bodyFont( fixed, print ).pointSize();
00203 }
00204
00205
00206 namespace {
00207 int pointsToPixel( const QPaintDeviceMetrics & metrics, int pointSize ) {
00208 return ( pointSize * metrics.logicalDpiY() + 36 ) / 72 ;
00209 }
00210 }
00211
00212 static const char * const quoteFontSizes[] = { "85", "80", "75" };
00213
00214 QString CSSHelper::printCssDefinitions( bool fixed ) const {
00215 const QString headerFont = QString( " font-family: \"%1\" ! important;\n"
00216 " font-size: %2pt ! important;\n" )
00217 .arg( mPrintFont.family() )
00218 .arg( mPrintFont.pointSize() );
00219 const QColorGroup & cg = QApplication::palette().active();
00220
00221 const QFont printFont = bodyFont( fixed, true );
00222 QString quoteCSS;
00223 if ( printFont.italic() )
00224 quoteCSS += " font-style: italic ! important;\n";
00225 if ( printFont.bold() )
00226 quoteCSS += " font-weight: bold ! important;\n";
00227 if ( !quoteCSS.isEmpty() )
00228 quoteCSS = "div.noquote {\n" + quoteCSS + "}\n\n";
00229
00230 return
00231 QString( "body {\n"
00232 " font-family: \"%1\" ! important;\n"
00233 " font-size: %2pt ! important;\n"
00234 " color: #000000 ! important;\n"
00235 " background-color: #ffffff ! important\n"
00236 "}\n\n" )
00237 .arg( printFont.family(),
00238 QString::number( printFont.pointSize() ) )
00239 +
00240 QString( "tr.textAtmH,\n"
00241 "tr.signInProgressH,\n"
00242 "tr.rfc822H,\n"
00243 "tr.encrH,\n"
00244 "tr.signOkKeyOkH,\n"
00245 "tr.signOkKeyBadH,\n"
00246 "tr.signWarnH,\n"
00247 "tr.signErrH,\n"
00248 "div.header {\n"
00249 "%1"
00250 "}\n\n"
00251
00252 "div.fancy.header > div {\n"
00253 " background-color: %2 ! important;\n"
00254 " color: %3 ! important;\n"
00255 " padding: 4px ! important;\n"
00256 " border: solid %3 1px ! important;\n"
00257 "}\n\n"
00258
00259 "div.fancy.header > div a[href] { color: %3 ! important; }\n\n"
00260
00261 "div.fancy.header > table.outer{\n"
00262 " background-color: %2 ! important;\n"
00263 " color: %3 ! important;\n"
00264 " border-bottom: solid %3 1px ! important;\n"
00265 " border-left: solid %3 1px ! important;\n"
00266 " border-right: solid %3 1px ! important;\n"
00267 "}\n\n"
00268
00269 "div.spamheader {\n"
00270 " display:none ! important;\n"
00271 "}\n\n"
00272
00273 "div.htmlWarn {\n"
00274 " border: 2px solid #ffffff ! important;\n"
00275 "}\n\n"
00276
00277 "div.senderpic{\n"
00278 " font-size:0.8em ! important;\n"
00279 " border:1px solid black ! important;\n"
00280 " background-color:%2 ! important;\n"
00281 "}\n\n"
00282
00283 "div.senderstatus{\n"
00284 " text-align:center ! important;\n"
00285 "}\n\n"
00286
00287 "div.noprint {\n"
00288 " display:none ! important;\n"
00289 "}\n\n"
00290 )
00291 .arg( headerFont,
00292 cg.background().name(),
00293 cg.foreground().name() )
00294 + quoteCSS;
00295 }
00296
00297 QString CSSHelper::screenCssDefinitions( const CSSHelper * helper, bool fixed ) const {
00298 const QString fgColor = mForegroundColor.name();
00299 const QString bgColor = mBackgroundColor.name();
00300 const QString linkColor = mLinkColor.name();
00301 const QString headerFont = QString(" font-family: \"%1\" ! important;\n"
00302 " font-size: %2px ! important;\n")
00303 .arg( mBodyFont.family() )
00304 .arg( pointsToPixel( helper->mMetrics, mBodyFont.pointSize() ) );
00305 const QString background = ( mBackingPixmapOn
00306 ? QString( " background-image:url(file://%1) ! important;\n" )
00307 .arg( mBackingPixmapStr )
00308 : QString( " background-color: %1 ! important;\n" )
00309 .arg( bgColor ) );
00310 const QString bodyFontSize = QString::number( pointsToPixel( helper->mMetrics, fontSize( fixed ) ) ) + "px" ;
00311 const QColorGroup & cg = QApplication::palette().active();
00312
00313 QString quoteCSS;
00314 if ( bodyFont( fixed ).italic() )
00315 quoteCSS += " font-style: italic ! important;\n";
00316 if ( bodyFont( fixed ).bold() )
00317 quoteCSS += " font-weight: bold ! important;\n";
00318 if ( !quoteCSS.isEmpty() )
00319 quoteCSS = "div.noquote {\n" + quoteCSS + "}\n\n";
00320
00321
00322 for ( int i = 0 ; i < 3 ; ++i ) {
00323 quoteCSS += QString( "div.quotelevel%1 {\n"
00324 " color: %2 ! important;\n" )
00325 .arg( QString::number(i+1), mQuoteColor[i].name() );
00326 if ( mQuoteFont[i].italic() )
00327 quoteCSS += " font-style: italic ! important;\n";
00328 if ( mQuoteFont[i].bold() )
00329 quoteCSS += " font-weight: bold ! important;\n";
00330 if ( mShrinkQuotes )
00331 quoteCSS += " font-size: " + QString::fromLatin1( quoteFontSizes[i] )
00332 + "% ! important;\n";
00333 quoteCSS += "}\n\n";
00334 }
00335
00336
00337 for ( int i = 0 ; i < 3 ; ++i ) {
00338 quoteCSS += QString( "div.deepquotelevel%1 {\n"
00339 " color: %2 ! important;\n" )
00340 .arg( QString::number(i+1), mQuoteColor[i].name() );
00341 if ( mQuoteFont[i].italic() )
00342 quoteCSS += " font-style: italic ! important;\n";
00343 if ( mQuoteFont[i].bold() )
00344 quoteCSS += " font-weight: bold ! important;\n";
00345 if ( mShrinkQuotes )
00346 quoteCSS += " font-size: 70% ! important;\n";
00347 quoteCSS += "}\n\n";
00348 }
00349
00350 return
00351 QString( "body {\n"
00352 " font-family: \"%1\" ! important;\n"
00353 " font-size: %2 ! important;\n"
00354 " color: %3 ! important;\n"
00355 "%4"
00356 "}\n\n" )
00357 .arg( bodyFont( fixed ).family(),
00358 bodyFontSize,
00359 fgColor,
00360 background )
00361 +
00362 QString( "a {\n"
00363 " color: %1 ! important;\n"
00364 " text-decoration: none ! important;\n"
00365 "}\n\n"
00366
00367 "a.white {\n"
00368 " color: white ! important;\n"
00369 "}\n\n"
00370
00371 "a.black {\n"
00372 " color: black ! important;\n"
00373 "}\n\n"
00374
00375 "table.textAtm { background-color: %2 ! important; }\n\n"
00376
00377 "tr.textAtmH {\n"
00378 " background-color: %3 ! important;\n"
00379 "%4"
00380 "}\n\n"
00381
00382 "tr.textAtmB {\n"
00383 " background-color: %3 ! important;\n"
00384 "}\n\n"
00385
00386 "table.signInProgress,\n"
00387 "table.rfc822 {\n"
00388 " background-color: %3 ! important;\n"
00389 "}\n\n"
00390
00391 "tr.signInProgressH,\n"
00392 "tr.rfc822H {\n"
00393 "%4"
00394 "}\n\n" )
00395 .arg( linkColor, fgColor, bgColor, headerFont )
00396 +
00397 QString( "table.encr {\n"
00398 " background-color: %1 ! important;\n"
00399 "}\n\n"
00400
00401 "tr.encrH {\n"
00402 " background-color: %2 ! important;\n"
00403 "%3"
00404 "}\n\n"
00405
00406 "tr.encrB { background-color: %4 ! important; }\n\n" )
00407 .arg( cPgpEncrF.name(),
00408 cPgpEncrH.name(),
00409 headerFont,
00410 cPgpEncrB.name() )
00411 +
00412 QString( "table.signOkKeyOk {\n"
00413 " background-color: %1 ! important;\n"
00414 "}\n\n"
00415
00416 "tr.signOkKeyOkH {\n"
00417 " background-color: %2 ! important;\n"
00418 "%3"
00419 "}\n\n"
00420
00421 "tr.signOkKeyOkB { background-color: %4 ! important; }\n\n" )
00422 .arg( cPgpOk1F.name(),
00423 cPgpOk1H.name(),
00424 headerFont,
00425 cPgpOk1B.name() )
00426 +
00427 QString( "table.signOkKeyBad {\n"
00428 " background-color: %1 ! important;\n"
00429 "}\n\n"
00430
00431 "tr.signOkKeyBadH {\n"
00432 " background-color: %2 ! important;\n"
00433 "%3"
00434 "}\n\n"
00435
00436 "tr.signOkKeyBadB { background-color: %4 ! important; }\n\n" )
00437 .arg( cPgpOk0F.name(),
00438 cPgpOk0H.name(),
00439 headerFont,
00440 cPgpOk0B.name() )
00441 +
00442 QString( "table.signWarn {\n"
00443 " background-color: %1 ! important;\n"
00444 "}\n\n"
00445
00446 "tr.signWarnH {\n"
00447 " background-color: %2 ! important;\n"
00448 "%3"
00449 "}\n\n"
00450
00451 "tr.signWarnB { background-color: %4 ! important; }\n\n" )
00452 .arg( cPgpWarnF.name(),
00453 cPgpWarnH.name(),
00454 headerFont,
00455 cPgpWarnB.name() )
00456 +
00457 QString( "table.signErr {\n"
00458 " background-color: %1 ! important;\n"
00459 "}\n\n"
00460
00461 "tr.signErrH {\n"
00462 " background-color: %2 ! important;\n"
00463 "%3"
00464 "}\n\n"
00465
00466 "tr.signErrB { background-color: %4 ! important; }\n\n" )
00467 .arg( cPgpErrF.name(),
00468 cPgpErrH.name(),
00469 headerFont,
00470 cPgpErrB.name() )
00471 +
00472 QString( "div.htmlWarn {\n"
00473 " border: 2px solid %1 ! important;\n"
00474 "}\n\n" )
00475 .arg( cHtmlWarning.name() )
00476 +
00477 QString( "div.header {\n"
00478 "%1"
00479 "}\n\n"
00480
00481 "div.fancy.header > div {\n"
00482 " background-color: %2 ! important;\n"
00483 " color: %3 ! important;\n"
00484 " border: solid %4 1px ! important;\n"
00485 "}\n\n"
00486
00487 "div.fancy.header > div a[href] { color: %3 ! important; }\n\n"
00488
00489 "div.fancy.header > div a[href]:hover { text-decoration: underline ! important; }\n\n"
00490
00491 "div.fancy.header > div.spamheader {\n"
00492 " background-color: #cdcdcd ! important;\n"
00493 " border-top: 0px ! important;\n"
00494 " padding: 3px ! important;\n"
00495 " color: black ! important;\n"
00496 " font-weight: bold ! important;\n"
00497 " font-size: smaller ! important;\n"
00498 "}\n\n"
00499
00500 "div.fancy.header > table.outer {\n"
00501 " background-color: %5 ! important;\n"
00502 " color: %4 ! important;\n"
00503 " border-bottom: solid %4 1px ! important;\n"
00504 " border-left: solid %4 1px ! important;\n"
00505 " border-right: solid %4 1px ! important;\n"
00506 "}\n\n"
00507
00508 "div.senderpic{\n"
00509 " padding: 0px ! important;\n"
00510 " font-size:0.8em ! important;\n"
00511 " border:1px solid %6 ! important;\n"
00512
00513
00514 " background-color:%5 ! important;\n"
00515 "}\n\n"
00516
00517 "div.senderstatus{\n"
00518 " text-align:center ! important;\n"
00519 "}\n\n"
00520 )
00521
00522 .arg( headerFont )
00523 .arg( cg.highlight().name(),
00524 cg.highlightedText().name(),
00525 cg.foreground().name(),
00526 cg.background().name() )
00527 .arg( cg.mid().name() )
00528 + quoteCSS;
00529 }
00530
00531 QString CSSHelper::commonCssDefinitions() const {
00532 return
00533 "div.header {\n"
00534 " margin-bottom: 10pt ! important;\n"
00535 "}\n\n"
00536
00537 "table.textAtm {\n"
00538 " margin-top: 10pt ! important;\n"
00539 " margin-bottom: 10pt ! important;\n"
00540 "}\n\n"
00541
00542 "tr.textAtmH,\n"
00543 "tr.textAtmB,\n"
00544 "tr.rfc822B {\n"
00545 " font-weight: normal ! important;\n"
00546 "}\n\n"
00547
00548 "tr.signInProgressH,\n"
00549 "tr.rfc822H,\n"
00550 "tr.encrH,\n"
00551 "tr.signOkKeyOkH,\n"
00552 "tr.signOkKeyBadH,\n"
00553 "tr.signWarnH,\n"
00554 "tr.signErrH {\n"
00555 " font-weight: bold ! important;\n"
00556 "}\n\n"
00557
00558 "tr.textAtmH td,\n"
00559 "tr.textAtmB td {\n"
00560 " padding: 3px ! important;\n"
00561 "}\n\n"
00562
00563 "table.rfc822 {\n"
00564 " width: 100% ! important;\n"
00565 " border: solid 1px black ! important;\n"
00566 " margin-top: 10pt ! important;\n"
00567 " margin-bottom: 10pt ! important;\n"
00568 "}\n\n"
00569
00570 "table.textAtm,\n"
00571 "table.encr,\n"
00572 "table.signWarn,\n"
00573 "table.signErr,\n"
00574 "table.signOkKeyBad,\n"
00575 "table.signOkKeyOk,\n"
00576 "table.signInProgress,\n"
00577 "div.fancy.header table {\n"
00578 " width: 100% ! important;\n"
00579 " border-width: 0px ! important;\n"
00580 "}\n\n"
00581
00582 "div.htmlWarn {\n"
00583 " margin: 0px 5% ! important;\n"
00584 " padding: 10px ! important;\n"
00585 " text-align: left ! important;\n"
00586 "}\n\n"
00587
00588 "div.fancy.header > div {\n"
00589 " font-weight: bold ! important;\n"
00590 " padding: 4px ! important;\n"
00591 "}\n\n"
00592
00593 "div.fancy.header table {\n"
00594 " padding: 2px ! important;\n"
00595 " text-align: left ! important\n"
00596 "}\n\n"
00597
00598 "div.fancy.header table th {\n"
00599 " padding: 0px ! important;\n"
00600 " white-space: nowrap ! important;\n"
00601 " border-spacing: 0px ! important;\n"
00602 " text-align: left ! important;\n"
00603 " vertical-align: top ! important;\n"
00604 "}\n\n"
00605
00606 "div.fancy.header table td {\n"
00607 " padding: 0px ! important;\n"
00608 " border-spacing: 0px ! important;\n"
00609 " text-align: left ! important;\n"
00610 " vertical-align: top ! important;\n"
00611 " width: 100% ! important;\n"
00612 "}\n\n"
00613
00614 "span.pimsmileytext {\n"
00615 " position: absolute;\n"
00616 " top: 0px;\n"
00617 " left: 0px;\n"
00618 " visibility: hidden;\n"
00619 "}\n\n"
00620
00621 "img.pimsmileyimg {\n"
00622 "}\n\n"
00623
00624 "div.quotelevelmark {\n"
00625 " position: absolute;\n"
00626 " margin-left:-10px;\n"
00627 "}\n\n"
00628 ;
00629 }
00630
00631
00632 void CSSHelper::setBodyFont( const QFont& font )
00633 {
00634 mBodyFont = font;
00635 }
00636
00637 void CSSHelper::setPrintFont( const QFont& font )
00638 {
00639 mPrintFont = font;
00640 }
00641
00642 QColor CSSHelper::pgpWarnColor() const
00643 {
00644 return cPgpWarnH;
00645 }
00646
00647 }