libkdepim

csshelper.cpp

00001 /*  -*- mode: C++; c-file-style: "gnu" -*-
00002     csshelper.cpp
00003 
00004     This file is part of KMail, the KDE mail client.
00005     Copyright (c) 2003 Marc Mutz <mutz@kde.org>
00006 
00007     KMail is free software; you can redistribute it and/or modify it
00008     under the terms of the GNU General Public License, version 2, as
00009     published by the Free Software Foundation.
00010 
00011     KMail is distributed in the hope that it will be useful, but
00012     WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00019 
00020     In addition, as a special exception, the copyright holders give
00021     permission to link the code of this program with any edition of
00022     the Qt library by Trolltech AS, Norway (or with modified versions
00023     of Qt that use the same license as Qt), and distribute linked
00024     combinations including the two.  You must obey the GNU General
00025     Public License in all respects for all of the code used other than
00026     Qt.  If you modify this file, you may extend this exception to
00027     your version of the file, but you are not obligated to do so.  If
00028     you do not wish to do so, delete this exception statement from
00029     your version.
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     // some QColor manipulators that hide the ugly QColor API w.r.t. HSV:
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     // initialize with defaults - should match the corresponding application defaults
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 ); // warning frame color: light red
00081 
00082     cPgpEncrH = QColor( 0x00, 0x80, 0xFF ); // light blue
00083     cPgpOk1H  = QColor( 0x40, 0xFF, 0x40 ); // light green
00084     cPgpOk0H  = QColor( 0xFF, 0xFF, 0x40 ); // light yellow
00085     cPgpWarnH = QColor( 0xFF, 0xFF, 0x40 ); // light yellow
00086     cPgpErrH  = Qt::red;
00087 
00088     for ( int i = 0 ; i < 3 ; ++i )
00089       mQuoteColor[i] = QColor( 0x00, 0x80 - i * 0x10, 0x00 ); // shades of green
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     // determine the frame and body color for PGP messages from the header color
00107     // if the header color equals the background color then the other colors are
00108     // also set to the background color (-> old style PGP message viewing)
00109     // else
00110     // the brightness of the frame is set to 4/5 of the brightness of the header
00111     // and in case of a light background color
00112     // the saturation of the body is set to 1/8 of the saturation of the header
00113     // while in case of a dark background color
00114     // the value of the body is set to the value of the background color
00115 
00116     // Check whether the user uses a light color scheme
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 /*fixed*/ ) 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 /* print */ );
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.rfc822H,\n"
00242                "tr.encrH,\n"
00243                "tr.signOkKeyOkH,\n"
00244                "tr.signOkKeyBadH,\n"
00245                "tr.signWarnH,\n"
00246                "tr.signErrH,\n"
00247                "div.header {\n"
00248                "%1"
00249                "}\n\n"
00250 
00251                "div.fancy.header > div {\n"
00252                "  background-color: %2 ! important;\n"
00253                "  color: %3 ! important;\n"
00254                "  padding: 4px ! important;\n"
00255                "  border: solid %3 1px ! important;\n"
00256                "}\n\n"
00257 
00258                "div.fancy.header > div a[href] { color: %3 ! important; }\n\n"
00259 
00260                "div.fancy.header > table.outer{\n"
00261                "  background-color: %2 ! important;\n"
00262                "  color: %3 ! important;\n"
00263                "  border-bottom: solid %3 1px ! important;\n"
00264                "  border-left: solid %3 1px ! important;\n"
00265                "  border-right: solid %3 1px ! important;\n"
00266                "}\n\n"
00267 
00268                "div.spamheader {\n"
00269                "  display:none ! important;\n"
00270                "}\n\n"
00271 
00272                "div.htmlWarn {\n"
00273                "  border: 2px solid #ffffff ! important;\n"
00274                "}\n\n"
00275 
00276                "div.senderpic{\n"
00277                "  font-size:0.8em ! important;\n"
00278                "  border:1px solid black ! important;\n"
00279                "  background-color:%2 ! important;\n"
00280                "}\n\n"
00281 
00282                "div.senderstatus{\n"
00283                "  text-align:center ! important;\n"
00284                "}\n\n"
00285             )
00286       .arg( headerFont,
00287             cg.background().name(),
00288             cg.foreground().name() )
00289       + quoteCSS;
00290   }
00291 
00292   QString CSSHelper::screenCssDefinitions( const CSSHelper * helper, bool fixed ) const {
00293     const QString fgColor = mForegroundColor.name();
00294     const QString bgColor = mBackgroundColor.name();
00295     const QString linkColor = mLinkColor.name();
00296     const QString headerFont = QString("  font-family: \"%1\" ! important;\n"
00297                                        "  font-size: %2px ! important;\n")
00298       .arg( mBodyFont.family() )
00299       .arg( pointsToPixel( helper->mMetrics, mBodyFont.pointSize() ) );
00300     const QString background = ( mBackingPixmapOn
00301                          ? QString( "  background-image:url(file://%1) ! important;\n" )
00302                            .arg( mBackingPixmapStr )
00303                          : QString( "  background-color: %1 ! important;\n" )
00304                            .arg( bgColor ) );
00305     const QString bodyFontSize = QString::number( pointsToPixel( helper->mMetrics, fontSize( fixed ) ) ) + "px" ;
00306     const QColorGroup & cg = QApplication::palette().active();
00307 
00308     QString quoteCSS;
00309     if ( bodyFont( fixed ).italic() )
00310       quoteCSS += "  font-style: italic ! important;\n";
00311     if ( bodyFont( fixed ).bold() )
00312       quoteCSS += "  font-weight: bold ! important;\n";
00313     if ( !quoteCSS.isEmpty() )
00314       quoteCSS = "div.noquote {\n" + quoteCSS + "}\n\n";
00315 
00316     // CSS definitions for quote levels 1-3
00317     for ( int i = 0 ; i < 3 ; ++i ) {
00318       quoteCSS += QString( "div.quotelevel%1 {\n"
00319                            "  color: %2 ! important;\n" )
00320         .arg( QString::number(i+1), mQuoteColor[i].name() );
00321       if ( mQuoteFont[i].italic() )
00322         quoteCSS += "  font-style: italic ! important;\n";
00323       if ( mQuoteFont[i].bold() )
00324         quoteCSS += "  font-weight: bold ! important;\n";
00325       if ( mShrinkQuotes )
00326         quoteCSS += "  font-size: " + QString::fromLatin1( quoteFontSizes[i] )
00327           + "% ! important;\n";
00328       quoteCSS += "}\n\n";
00329     }
00330 
00331     // CSS definitions for quote levels 4+
00332     for ( int i = 0 ; i < 3 ; ++i ) {
00333       quoteCSS += QString( "div.deepquotelevel%1 {\n"
00334                            "  color: %2 ! important;\n" )
00335         .arg( QString::number(i+1), mQuoteColor[i].name() );
00336       if ( mQuoteFont[i].italic() )
00337         quoteCSS += "  font-style: italic ! important;\n";
00338       if ( mQuoteFont[i].bold() )
00339         quoteCSS += "  font-weight: bold ! important;\n";
00340       if ( mShrinkQuotes )
00341         quoteCSS += "  font-size: 70% ! important;\n";
00342       quoteCSS += "}\n\n";
00343     }
00344 
00345     return
00346       QString( "body {\n"
00347                "  font-family: \"%1\" ! important;\n"
00348                "  font-size: %2 ! important;\n"
00349                "  color: %3 ! important;\n"
00350                "%4"
00351                "}\n\n" )
00352       .arg( bodyFont( fixed ).family(),
00353             bodyFontSize,
00354             fgColor,
00355             background )
00356       +
00357       QString( "a {\n"
00358                "  color: %1 ! important;\n"
00359                "  text-decoration: none ! important;\n"
00360                "}\n\n"
00361 
00362                "table.textAtm { background-color: %2 ! important; }\n\n"
00363 
00364                "tr.textAtmH {\n"
00365                "  background-color: %3 ! important;\n"
00366                "%4"
00367                "}\n\n"
00368 
00369                "tr.textAtmB {\n"
00370                "  background-color: %3 ! important;\n"
00371                "}\n\n"
00372 
00373                "table.rfc822 {\n"
00374                "  background-color: %3 ! important;\n"
00375                "}\n\n"
00376 
00377                "tr.rfc822H {\n"
00378                "%4"
00379                "}\n\n" )
00380       .arg( linkColor, fgColor, bgColor, headerFont )
00381       +
00382       QString( "table.encr {\n"
00383                "  background-color: %1 ! important;\n"
00384                "}\n\n"
00385 
00386                "tr.encrH {\n"
00387                "  background-color: %2 ! important;\n"
00388                "%3"
00389                "}\n\n"
00390 
00391                "tr.encrB { background-color: %4 ! important; }\n\n" )
00392       .arg( cPgpEncrF.name(),
00393             cPgpEncrH.name(),
00394             headerFont,
00395             cPgpEncrB.name() )
00396       +
00397       QString( "table.signOkKeyOk {\n"
00398                "  background-color: %1 ! important;\n"
00399                "}\n\n"
00400 
00401                "tr.signOkKeyOkH {\n"
00402                "  background-color: %2 ! important;\n"
00403                "%3"
00404                "}\n\n"
00405 
00406                "tr.signOkKeyOkB { background-color: %4 ! important; }\n\n" )
00407       .arg( cPgpOk1F.name(),
00408             cPgpOk1H.name(),
00409             headerFont,
00410             cPgpOk1B.name() )
00411       +
00412       QString( "table.signOkKeyBad {\n"
00413                "  background-color: %1 ! important;\n"
00414                "}\n\n"
00415 
00416                "tr.signOkKeyBadH {\n"
00417                "  background-color: %2 ! important;\n"
00418                "%3"
00419                "}\n\n"
00420 
00421                "tr.signOkKeyBadB { background-color: %4 ! important; }\n\n" )
00422       .arg( cPgpOk0F.name(),
00423             cPgpOk0H.name(),
00424             headerFont,
00425             cPgpOk0B.name() )
00426       +
00427       QString( "table.signWarn {\n"
00428                "  background-color: %1 ! important;\n"
00429                "}\n\n"
00430 
00431                "tr.signWarnH {\n"
00432                "  background-color: %2 ! important;\n"
00433                "%3"
00434                "}\n\n"
00435 
00436                "tr.signWarnB { background-color: %4 ! important; }\n\n" )
00437       .arg( cPgpWarnF.name(),
00438             cPgpWarnH.name(),
00439             headerFont,
00440             cPgpWarnB.name() )
00441       +
00442       QString( "table.signErr {\n"
00443                "  background-color: %1 ! important;\n"
00444                "}\n\n"
00445 
00446                "tr.signErrH {\n"
00447                "  background-color: %2 ! important;\n"
00448                "%3"
00449                "}\n\n"
00450 
00451                "tr.signErrB { background-color: %4 ! important; }\n\n" )
00452       .arg( cPgpErrF.name(),
00453             cPgpErrH.name(),
00454             headerFont,
00455             cPgpErrB.name() )
00456       +
00457       QString( "div.htmlWarn {\n"
00458                "  border: 2px solid %1 ! important;\n"
00459                "}\n\n" )
00460       .arg( cHtmlWarning.name() )
00461       +
00462       QString( "div.header {\n"
00463                "%1"
00464                "}\n\n"
00465 
00466                "div.fancy.header > div {\n"
00467                "  background-color: %2 ! important;\n"
00468                "  color: %3 ! important;\n"
00469                "  border: solid %4 1px ! important;\n"
00470                "}\n\n"
00471 
00472                "div.fancy.header > div a[href] { color: %3 ! important; }\n\n"
00473 
00474                "div.fancy.header > div a[href]:hover { text-decoration: underline ! important; }\n\n"
00475 
00476                "div.fancy.header > div.spamheader {\n"
00477                "  background-color: #cdcdcd ! important;\n"
00478                "  border-top: 0px ! important;\n"
00479                "  padding: 3px ! important;\n"
00480                "  color: black ! important;\n"
00481                "  font-weight: bold ! important;\n"
00482                "  font-size: smaller ! important;\n"
00483                "}\n\n"
00484 
00485                "div.fancy.header > table.outer {\n"
00486                "  background-color: %5 ! important;\n"
00487                "  color: %4 ! important;\n"
00488                "  border-bottom: solid %4 1px ! important;\n"
00489                "  border-left: solid %4 1px ! important;\n"
00490                "  border-right: solid %4 1px ! important;\n"
00491                "}\n\n"
00492 
00493                "div.senderpic{\n"
00494                "  padding: 0px ! important;\n"
00495                "  font-size:0.8em ! important;\n"
00496                "  border:1px solid %6 ! important;\n"
00497                // FIXME: InfoBackground crashes KHTML
00498                //"  background-color:InfoBackground ! important;\n"
00499                "  background-color:%5 ! important;\n"
00500                "}\n\n"
00501 
00502                "div.senderstatus{\n"
00503                "  text-align:center ! important;\n"
00504                "}\n\n"
00505                )
00506 
00507       .arg( headerFont )
00508       .arg( cg.highlight().name(),
00509             cg.highlightedText().name(),
00510             cg.foreground().name(),
00511             cg.background().name() )
00512       .arg( cg.mid().name() )
00513       + quoteCSS;
00514   }
00515 
00516   QString CSSHelper::commonCssDefinitions() const {
00517     return
00518       "div.header {\n"
00519       "  margin-bottom: 10pt ! important;\n"
00520       "}\n\n"
00521 
00522       "table.textAtm {\n"
00523       "  margin-top: 10pt ! important;\n"
00524       "  margin-bottom: 10pt ! important;\n"
00525       "}\n\n"
00526 
00527       "tr.textAtmH,\n"
00528       "tr.textAtmB,\n"
00529       "tr.rfc822B {\n"
00530       "  font-weight: normal ! important;\n"
00531       "}\n\n"
00532 
00533       "tr.rfc822H,\n"
00534       "tr.encrH,\n"
00535       "tr.signOkKeyOkH,\n"
00536       "tr.signOkKeyBadH,\n"
00537       "tr.signWarnH,\n"
00538       "tr.signErrH {\n"
00539       "  font-weight: bold ! important;\n"
00540       "}\n\n"
00541 
00542       "tr.textAtmH td,\n"
00543       "tr.textAtmB td {\n"
00544       "  padding: 3px ! important;\n"
00545       "}\n\n"
00546 
00547       "table.rfc822 {\n"
00548       "  width: 100% ! important;\n"
00549       "  border: solid 1px black ! important;\n"
00550       "  margin-top: 10pt ! important;\n"
00551       "  margin-bottom: 10pt ! important;\n"
00552       "}\n\n"
00553 
00554       "table.textAtm,\n"
00555       "table.encr,\n"
00556       "table.signWarn,\n"
00557       "table.signErr,\n"
00558       "table.signOkKeyBad,\n"
00559       "table.signOkKeyOk,\n"
00560       "div.fancy.header table {\n"
00561       "  width: 100% ! important;\n"
00562       "  border-width: 0px ! important;\n"
00563       "}\n\n"
00564 
00565       "div.htmlWarn {\n"
00566       "  margin: 0px 5% ! important;\n"
00567       "  padding: 10px ! important;\n"
00568       "  text-align: left ! important;\n"
00569       "}\n\n"
00570 
00571       "div.fancy.header > div {\n"
00572       "  font-weight: bold ! important;\n"
00573       "  padding: 4px ! important;\n"
00574       "}\n\n"
00575 
00576       "div.fancy.header table {\n"
00577       "  padding: 2px ! important;\n" // ### khtml bug: this is ignored
00578       "  text-align: left ! important\n"
00579       "}\n\n"
00580 
00581       "div.fancy.header table th {\n"
00582       "  padding: 0px ! important;\n"
00583       "  white-space: nowrap ! important;\n"
00584       "  border-spacing: 0px ! important;\n"
00585       "  text-align: left ! important;\n"
00586       "  vertical-align: top ! important;\n"
00587       "}\n\n"
00588 
00589       "div.fancy.header table td {\n"
00590       "  padding: 0px ! important;\n"
00591       "  border-spacing: 0px ! important;\n"
00592       "  text-align: left ! important;\n"
00593       "  vertical-align: top ! important;\n"
00594       "  width: 100% ! important;\n"
00595       "}\n\n"
00596 
00597       "span.pimsmileytext {\n"
00598       "  position: absolute;\n"
00599       "  top: 0px;\n"
00600       "  left: 0px;\n"
00601       "  visibility: hidden;\n"
00602       "}\n\n"
00603 
00604       "img.pimsmileyimg {\n"
00605       "}\n\n"
00606 
00607       "div.quotelevelmark {\n"
00608       "  position: absolute;\n"
00609       "  margin-left:-10px;\n"
00610       "}\n\n"
00611       ;
00612   }
00613 
00614 } // namespace KPIM
KDE Home | KDE Accessibility Home | Description of Access Keys