kmail Library API Documentation

headerstyle.cpp

00001 /*  -*- c++ -*-
00002     headerstyle.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 #ifdef HAVE_CONFIG_H
00033 #include <config.h>
00034 #endif
00035 
00036 #include "headerstyle.h"
00037 
00038 #include "headerstrategy.h"
00039 #include "linklocator.h"
00040 #include "kmmessage.h"
00041 #include "kmkernel.h"
00042 
00043 #include <libkdepim/email.h>
00044 
00045 #include <mimelib/string.h>
00046 #include <mimelib/field.h>
00047 #include <mimelib/headers.h>
00048 
00049 #include <kdebug.h>
00050 #include <klocale.h>
00051 #include <kglobal.h>
00052 #include "kimproxy.h"
00053 #include <kabc/stdaddressbook.h>
00054 #include <kabc/addresseelist.h>
00055 #include <kmdcodec.h>
00056 #include <qdatetime.h>
00057 #include <qbuffer.h>
00058 #include <qimage.h>
00059 #include <qapplication.h>
00060 #include <qregexp.h>
00061 
00062 namespace KMail {
00063 
00064   //
00065   // Convenience functions:
00066   //
00067   static inline QString directionOf( const QString & str ) {
00068     return str.isRightToLeft() ? "rtl" : "ltr" ;
00069   }
00070 
00071 #if 0
00072   // Converts to html. Changes URLs into href's, escapes HTML special
00073   // chars and inserts the result into an <div> or <span> tag with
00074   // "dir" set to "rtl" or "ltr" depending on the direction of @p str.
00075   static QString convertToHtmlBlock( const QString & str, bool useSpan=false ) {
00076     QString dir = directionOf( str );
00077     QString format = "<%1 dir=\"%3\">%4</%2>";
00078     return format.arg( useSpan ? "span" : "div" )
00079                  .arg( useSpan ? "span" : "div" )
00080                  .arg( dir )
00081                  .arg( LinkLocator::convertToHtml( str ) );
00082   }
00083 #endif
00084 
00085   // ### tmp wrapper to make kmreaderwin code working:
00086   static QString strToHtml( const QString & str, bool preserveBlanks=true ) {
00087     return LinkLocator::convertToHtml( str, preserveBlanks );
00088   }
00089 
00090   //
00091   // BriefHeaderStyle
00092   //   Show everything in a single line, don't show header field names.
00093   //
00094 
00095   class BriefHeaderStyle : public HeaderStyle {
00096     friend class HeaderStyle;
00097   protected:
00098     BriefHeaderStyle() : HeaderStyle() {}
00099     virtual ~BriefHeaderStyle() {}
00100     
00101   public:
00102     const char * name() const { return "brief"; }
00103     const HeaderStyle * next() const { return plain(); }
00104     const HeaderStyle * prev() const { return fancy(); }
00105 
00106     QString format( const KMMessage * message, const HeaderStrategy * strategy,
00107             const QString & vCardName, bool printing ) const;
00108   };
00109 
00110   QString BriefHeaderStyle::format( const KMMessage * message,
00111                     const HeaderStrategy * strategy,
00112                     const QString & vCardName, bool printing ) const {
00113     if ( !message ) return QString::null;
00114     if ( !strategy )
00115       strategy = HeaderStrategy::brief();
00116 
00117     // The direction of the header is determined according to the direction
00118     // of the application layout.
00119 
00120     QString dir = QApplication::reverseLayout() ? "rtl" : "ltr" ;
00121 
00122     // However, the direction of the message subject within the header is
00123     // determined according to the contents of the subject itself. Since
00124     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00125     // considered left-to-right, they are ignored when determining its
00126     // direction.
00127 
00128     QString subjectDir;
00129     if (!message->subject().isEmpty())
00130       subjectDir = directionOf( message->cleanSubject() );
00131     else
00132       subjectDir = directionOf( i18n("No Subject") );
00133 
00134     // Prepare the date string (when printing always use the localized date)
00135     QString dateString;
00136     if( printing ) {
00137       QDateTime dateTime;
00138       KLocale * locale = KGlobal::locale();
00139       dateTime.setTime_t( message->date() );
00140       dateString = locale->formatDateTime( dateTime );
00141     } else {
00142       dateString = message->dateStr();
00143     }
00144 
00145     QString headerStr = "<div class=\"header\" dir=\"" + dir + "\">\n";
00146 
00147     if ( strategy->showHeader( "subject" ) )
00148       headerStr += "<div dir=\"" + subjectDir + "\">\n"
00149                "<b style=\"font-size:130%\">" +
00150                strToHtml( message->subject() ) +
00151                "</b></div>\n";
00152 
00153     QStringList headerParts;
00154 
00155     if ( strategy->showHeader( "from" ) ) {
00156       QString fromPart = KMMessage::emailAddrAsAnchor( message->from(), true );
00157       if ( !vCardName.isEmpty() )
00158     fromPart += "&nbsp;&nbsp;<a href=\"" + vCardName + "\">" + i18n("[vCard]") + "</a>";
00159       headerParts << fromPart;
00160     }
00161 
00162     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
00163       headerParts << i18n("CC: ") + KMMessage::emailAddrAsAnchor( message->cc(), true );
00164 
00165     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
00166       headerParts << i18n("BCC: ") + KMMessage::emailAddrAsAnchor( message->bcc(), true );
00167 
00168     if ( strategy->showHeader( "date" ) )
00169       headerParts << strToHtml(message->dateShortStr());
00170 
00171     // remove all empty (modulo whitespace) entries and joins them via ", \n"
00172     headerStr += " (" + headerParts.grep( QRegExp( "\\S" ) ).join( ",\n" ) + ')';
00173 
00174     headerStr += "</div>\n";
00175 
00176     // ### iterate over the rest of strategy->headerToDisplay() (or
00177     // ### all headers if DefaultPolicy == Display) (elsewhere, too)
00178     return headerStr;
00179   }
00180 
00181   //
00182   // PlainHeaderStyle:
00183   //   show every header field on a line by itself,
00184   //   show subject larger
00185   //
00186 
00187   class PlainHeaderStyle : public HeaderStyle {
00188     friend class HeaderStyle;
00189   protected:
00190     PlainHeaderStyle() : HeaderStyle() {}
00191     virtual ~PlainHeaderStyle() {}
00192     
00193   public:
00194     const char * name() const { return "plain"; }
00195     const HeaderStyle * next() const { return fancy(); }
00196     const HeaderStyle * prev() const { return brief(); }
00197 
00198     QString format( const KMMessage * message, const HeaderStrategy * strategy,
00199             const QString & vCardName, bool printing ) const;
00200 
00201   private:
00202     QString formatAllMessageHeaders( const KMMessage * message ) const;
00203   };
00204 
00205   QString PlainHeaderStyle::format( const KMMessage * message,
00206                     const HeaderStrategy * strategy,
00207                     const QString & vCardName, bool printing ) const {
00208     if ( !message ) return QString::null;
00209     if ( !strategy )
00210       strategy = HeaderStrategy::rich();
00211 
00212     // The direction of the header is determined according to the direction
00213     // of the application layout.
00214 
00215     QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00216 
00217     // However, the direction of the message subject within the header is
00218     // determined according to the contents of the subject itself. Since
00219     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00220     // considered left-to-right, they are ignored when determining its
00221     // direction.
00222 
00223     QString subjectDir;
00224     if (!message->subject().isEmpty())
00225       subjectDir = directionOf( message->cleanSubject() );
00226     else
00227       subjectDir = directionOf( i18n("No Subject") );
00228 
00229     // Prepare the date string (when printing always use the localized date)
00230     QString dateString;
00231     if( printing ) {
00232       QDateTime dateTime;
00233       KLocale* locale = KGlobal::locale();
00234       dateTime.setTime_t( message->date() );
00235       dateString = locale->formatDateTime( dateTime );
00236     }
00237     else {
00238       dateString = message->dateStr();
00239     }
00240 
00241     QString headerStr = QString("<div class=\"header\" dir=\"%1\">").arg(dir);
00242 
00243     if ( strategy->headersToDisplay().isEmpty()
00244      && strategy->defaultPolicy() == HeaderStrategy::Display ) {
00245       // crude way to emulate "all" headers:
00246       headerStr += formatAllMessageHeaders( message );
00247       return headerStr + "</div>";
00248     }
00249 
00250     //case HdrLong:
00251     if ( strategy->showHeader( "subject" ) )
00252       headerStr += QString("<div dir=\"%1\"><b style=\"font-size:130%\">" +
00253                strToHtml(message->subject()) + "</b></div>\n")
00254                         .arg(subjectDir);
00255 
00256     if ( strategy->showHeader( "date" ) )
00257       headerStr.append(i18n("Date: ") + strToHtml(dateString)+"<br>\n");
00258     
00259     // Get Instant Messaging presence
00260     QString presence;
00261     QString kabcUid;
00262     if ( strategy->showHeader( "status" ) )
00263     {
00264       KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
00265       KABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getEmailAddr( message->from() ) );
00266       ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00267       kabcUid = addresses[0].uid();
00268       presence = imProxy->presenceString( kabcUid );
00269     }
00270  
00271     if ( strategy->showHeader( "from" ) ) {
00272       headerStr.append(i18n("From: ") +
00273                KMMessage::emailAddrAsAnchor(message->from(),FALSE));
00274       if ( !vCardName.isEmpty() )
00275         headerStr.append("&nbsp;&nbsp;<a href=\"" + vCardName +
00276               "\">" + i18n("[vCard]") + "</a>" );
00277       if ( !presence.isEmpty() && strategy->showHeader( "status" ) )
00278         headerStr.append("&nbsp;&nbsp;(<span name=\"presence-" + kabcUid + "\">" + presence + "</span>)" );
00279       if ( strategy->showHeader( "organization" )
00280           && !message->headerField("Organization").isEmpty())
00281         headerStr.append("&nbsp;&nbsp;(" +
00282               strToHtml(message->headerField("Organization")) + ")");
00283       headerStr.append("<br>\n");
00284     }
00285 
00286     if ( strategy->showHeader( "to" ) )
00287       headerStr.append(i18n("To: ")+
00288                KMMessage::emailAddrAsAnchor(message->to(),FALSE) + "<br>\n");
00289 
00290     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
00291       headerStr.append(i18n("CC: ")+
00292                        KMMessage::emailAddrAsAnchor(message->cc(),FALSE) + "<br>\n");
00293 
00294     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
00295       headerStr.append(i18n("BCC: ")+
00296                        KMMessage::emailAddrAsAnchor(message->bcc(),FALSE) + "<br>\n");
00297 
00298     if ( strategy->showHeader( "reply-to" ) && !message->replyTo().isEmpty())
00299       headerStr.append(i18n("Reply to: ")+
00300                      KMMessage::emailAddrAsAnchor(message->replyTo(),FALSE) + "<br>\n");
00301 
00302     headerStr += "</div>\n";
00303 
00304     return headerStr;
00305   }
00306 
00307   QString PlainHeaderStyle::formatAllMessageHeaders( const KMMessage * message ) const {
00308     const DwHeaders & headers = message->headers();
00309     QString result;
00310 
00311     for ( const DwField * field = headers.FirstField() ; field ; field = field->Next() ) {
00312       result += ( field->FieldNameStr() + ": " ).c_str();
00313       result += strToHtml( field->FieldBodyStr().c_str() );
00314       result += "<br>\n";
00315     }
00316 
00317     return result;
00318   }
00319 
00320   //
00321   // FancyHeaderStyle:
00322   //   Like PlainHeaderStyle, but with slick frames and background colours.
00323   //
00324 
00325   class FancyHeaderStyle : public HeaderStyle {
00326     friend class HeaderStyle;
00327   protected:
00328     FancyHeaderStyle() : HeaderStyle() {}
00329     virtual ~FancyHeaderStyle() {}
00330     
00331   public:
00332     const char * name() const { return "fancy"; }
00333     const HeaderStyle * next() const { return brief(); }
00334     const HeaderStyle * prev() const { return plain(); }
00335 
00336     QString format( const KMMessage * message, const HeaderStrategy * strategy,
00337             const QString & vCardName, bool printing ) const;
00338     static QString imgToDataUrl( const QImage &image );
00339 
00340   };
00341 
00342   QString FancyHeaderStyle::format( const KMMessage * message,
00343                     const HeaderStrategy * strategy,
00344                     const QString & vCardName, bool printing ) const {
00345     if ( !message ) return QString::null;
00346     if ( !strategy )
00347       strategy = HeaderStrategy::rich();
00348 
00349     // ### from kmreaderwin begin
00350     // The direction of the header is determined according to the direction
00351     // of the application layout.
00352 
00353     QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00354     QString headerStr = QString("<div class=\"fancy header\" dir=\"%1\">\n").arg(dir);
00355 
00356     // However, the direction of the message subject within the header is
00357     // determined according to the contents of the subject itself. Since
00358     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00359     // considered left-to-right, they are ignored when determining its
00360     // direction.
00361 
00362     QString subjectDir;
00363     if ( !message->subject().isEmpty() )
00364       subjectDir = directionOf( message->cleanSubject() );
00365     else
00366       subjectDir = directionOf( i18n("No Subject") );
00367 
00368     // Prepare the date string (when printing always use the localized date)
00369     QString dateString;
00370     if( printing ) {
00371       QDateTime dateTime;
00372       KLocale* locale = KGlobal::locale();
00373       dateTime.setTime_t( message->date() );
00374       dateString = locale->formatDateTime( dateTime );
00375     }
00376     else {
00377       dateString = message->dateStr();
00378     }
00379 
00380     QString userHTML;
00381     QString presence;
00382     
00383     // IM presence and kabc photo
00384     // Check first that KIMProxy has any IM presence data, to save hitting KABC 
00385     // unless really necessary
00386     ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00387     QString kabcUid;
00388     if ( ( strategy->showHeader( "status" ) || strategy->showHeader( "statuspic" ) ) )
00389     {
00390       if ( imProxy->initialize() )
00391       {
00392         KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
00393         KABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getEmailAddr( message->from() ) );
00394     
00395         if( addresses.count() == 1 )
00396         {
00397           // kabcUid is embedded in im: URIs to indicate which IM contact to message
00398           kabcUid = addresses[0].uid();
00399           
00400           // im status
00401           presence = imProxy->presenceString( kabcUid );
00402           if ( !presence.isEmpty() )
00403           {  
00404             QString presenceIcon = QString::fromLatin1( " <img src=\"%1\"/>" )
00405                 .arg( imgToDataUrl( imProxy->presenceIcon( kabcUid ).convertToImage() ) );
00406             presence += presenceIcon;
00407           }
00408           // picture
00409           if ( strategy->showHeader( "statuspic" ) )
00410           {
00411             QString photoURL;
00412             if ( addresses[0].photo().isIntern() )
00413             {
00414               // get photo data and convert to data: url
00415               //kdDebug( 5006 ) << "INTERNAL photo found" << endl;
00416               QImage photo = addresses[0].photo().data();
00417               if ( !photo.isNull() )
00418               {
00419                 photoURL = imgToDataUrl( photo );
00420               }
00421             }
00422             else
00423             {
00424               //kdDebug( 5006 ) << "URL found" << endl;
00425               photoURL = addresses[0].photo().url();
00426               if ( photoURL.startsWith("/") )
00427                 photoURL.prepend( "file:" );
00428             }
00429             if( !photoURL.isEmpty() )
00430             {
00431               //kdDebug( 5006 ) << "Got a photo: " << photoURL << endl;
00432               userHTML = QString("<img src=\"%1\" width=\"60\" height=\"60\">").arg( photoURL );
00433               if ( presence.isEmpty() )
00434               {  
00435                 userHTML = QString("<div class=\"senderpic\">") + userHTML + "</div>";
00436               }
00437               else
00438                 userHTML = QString( "<div class=\"senderpic\">"
00439                                       "<a href=\"im:%1\">%2<div class=\"senderstatus\"><span name=\"presence-%2\">%3</span></div></a>"
00440                                       "</div>" ).arg( kabcUid )
00441                                                 .arg( userHTML )
00442                                                 .arg( presence );
00443             }
00444           }
00445         }
00446         else
00447         {
00448           kdDebug( 5006 ) << "Multiple / No addressees matched email address; Count is " << addresses.count() << endl;
00449           userHTML = "&nbsp;";
00450         }
00451       }
00452 // Disabled 'Launch IM' link in headers - Will
00453 //      else
00454 //        if ( imProxy->imAppsAvailable() )
00455 //          presence = "<a name=\"launchim\" href=\"kmail:startIMApp\">" + i18n("Launch IM") + "</a></span>";
00456     }
00457     // do nothing - no im apps available, leave presence empty
00458     //presence = i18n( "DCOP/InstantMessenger not installed" );
00459     kdDebug( 5006 ) << "final presence: '" << presence << "'" << endl;
00460     //case HdrFancy:
00461     // the subject line and box below for details
00462     if ( strategy->showHeader( "subject" ) )
00463       headerStr += QString("<div dir=\"%1\">%2</div>\n")
00464                         .arg(subjectDir)
00465                 .arg(message->subject().isEmpty()?
00466                  i18n("No Subject") :
00467                  strToHtml(message->subject()));
00468     headerStr += "<table class=\"outer\"><tr><td width=\"100%\"><table>\n";
00469     //headerStr += "<table>\n";
00470     // from line
00471     // the mailto: URLs can contain %3 etc., therefore usage of multiple
00472     // QString::arg is not possible
00473     if ( strategy->showHeader( "from" ) )
00474       headerStr += QString("<tr><th>%1</th>\n"
00475                            "<td>")
00476                            .arg(i18n("From: "))
00477                  + KMMessage::emailAddrAsAnchor(message->from(),FALSE)
00478                  + ( !vCardName.isEmpty() ? "&nbsp;&nbsp;<a href=\"" + vCardName + "\">"
00479                                 + i18n("[vCard]") + "</a>"
00480                               : QString("") )
00481                  + ( ( !presence.isEmpty() && strategy->showHeader( "status" ) ) 
00482                               ? "&nbsp;&nbsp;(<span name=\"presence-" + kabcUid + "\">" + presence + "</span>)"
00483                               : QString("") )
00484                  + ( message->headerField("Organization").isEmpty()
00485                               ? QString("")
00486                               : "&nbsp;&nbsp;("
00487                                 + strToHtml(message->headerField("Organization"))
00488                                 + ")")
00489                  + "</td></tr>\n";
00490     // to line
00491     if ( strategy->showHeader( "to" ) )
00492       headerStr.append(QString("<tr><th>%1</th>\n"
00493                    "<td>%2</td></tr>\n")
00494                             .arg(i18n("To: "))
00495                             .arg(KMMessage::emailAddrAsAnchor(message->to(),FALSE)));
00496 
00497     // cc line, if any
00498     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty())
00499       headerStr.append(QString("<tr><th>%1</th>\n"
00500                    "<td>%2</td></tr>\n")
00501                               .arg(i18n("CC: "))
00502                               .arg(KMMessage::emailAddrAsAnchor(message->cc(),FALSE)));
00503 
00504     // Bcc line, if any
00505     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty())
00506       headerStr.append(QString("<tr><th>%1</th>\n"
00507                    "<td>%2</td></tr>\n")
00508                               .arg(i18n("BCC: "))
00509                               .arg(KMMessage::emailAddrAsAnchor(message->bcc(),FALSE)));
00510 
00511     if ( strategy->showHeader( "date" ) )
00512       headerStr.append(QString("<tr><th>%1</th>\n"
00513                    "<td dir=\"%2\">%3</td></tr>\n")
00514                             .arg(i18n("Date: "))
00515                     .arg( directionOf( message->dateStr() ) )
00516                             .arg(strToHtml(dateString)));
00517 
00518     // FIXME: Show status in synthetic header style field.  Decide whether this or current in brackets style is best and remove one.
00519     /*    if( strategy->showHeader( "status" ) )
00520       headerStr.append( QString( "<tr><th>%1</th>\n"
00521                                  "<td dir=\"%2\">%3</td></tr>\n")
00522                                     .arg(i18n("Sender status: "))
00523                                     .arg( directionOf( onlineStatus ) )
00524                                     .arg(onlineStatus));
00525     */
00526     headerStr.append(
00527           QString("</table></td><td align=\"center\">%1</td></tr></table>\n").arg(userHTML)
00528                      );
00529     
00530     headerStr += "</div>\n\n";
00531     return headerStr;
00532   }
00533 
00534 QString FancyHeaderStyle::imgToDataUrl( const QImage &image )
00535 {
00536   QByteArray ba;
00537   QBuffer buffer( ba );
00538   buffer.open( IO_WriteOnly );
00539   image.save( &buffer, "PNG" );
00540   return QString::fromLatin1("data:image/png;base64,%1").arg( KCodecs::base64Encode( ba ) );
00541 }  
00542   //
00543   // HeaderStyle abstract base:
00544   //
00545 
00546   HeaderStyle::HeaderStyle() {
00547 
00548   }
00549 
00550   HeaderStyle::~HeaderStyle() {
00551 
00552   }
00553 
00554   const HeaderStyle * HeaderStyle::create( Type type ) {
00555     switch ( type ) {
00556     case Brief:  return brief();
00557     case Plain:  return plain();
00558     case Fancy:   return fancy();
00559     }
00560     kdFatal( 5006 ) << "HeaderStyle::create(): Unknown header style ( type == "
00561             << (int)type << " ) requested!" << endl;
00562     return 0; // make compiler happy
00563   }
00564 
00565   const HeaderStyle * HeaderStyle::create( const QString & type ) {
00566     QString lowerType = type.lower();
00567     if ( lowerType == "brief" ) return brief();
00568     if ( lowerType == "plain" )  return plain();
00569     //if ( lowerType == "fancy" ) return fancy(); // not needed, see below
00570     // don't kdFatal here, b/c the strings are user-provided
00571     // (KConfig), so fail gracefully to the default:
00572     return fancy();
00573   }
00574 
00575   static const HeaderStyle * briefStyle = 0;
00576   static const HeaderStyle * plainStyle = 0;
00577   static const HeaderStyle * fancyStyle = 0;
00578 
00579   const HeaderStyle * HeaderStyle::brief() {
00580     if ( !briefStyle )
00581       briefStyle = new BriefHeaderStyle();
00582     return briefStyle;
00583   }
00584 
00585   const HeaderStyle * HeaderStyle::plain() {
00586     if ( !plainStyle )
00587       plainStyle = new PlainHeaderStyle();
00588     return plainStyle;
00589   }
00590 
00591   const HeaderStyle * HeaderStyle::fancy() {
00592     if ( !fancyStyle )
00593       fancyStyle = new FancyHeaderStyle();
00594     return fancyStyle;
00595   }
00596 
00597 } // namespace KMail
KDE Logo
This file is part of the documentation for kmail Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Apr 4 04:48:23 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003