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 #ifdef HAVE_CONFIG_H
00033 #include <config.h>
00034 #endif
00035
00036 #include "headerstyle.h"
00037
00038 #include "headerstrategy.h"
00039 #include "kmkernel.h"
00040 #include "linklocator.h"
00041 #include "kmmessage.h"
00042 #include "spamheaderanalyzer.h"
00043 #include "globalsettings.h"
00044
00045 #include <libemailfunctions/email.h>
00046 #include <libkdepim/kxface.h>
00047 using namespace KPIM;
00048
00049 #include <mimelib/string.h>
00050 #include <mimelib/field.h>
00051 #include <mimelib/headers.h>
00052
00053 #include <kdebug.h>
00054 #include <klocale.h>
00055 #include <kglobal.h>
00056 #include <kimproxy.h>
00057 #include <kabc/stdaddressbook.h>
00058 #include <kabc/addresseelist.h>
00059 #include <kmdcodec.h>
00060 #include <qdatetime.h>
00061 #include <qbuffer.h>
00062 #include <qbitmap.h>
00063 #include <qimage.h>
00064 #include <qapplication.h>
00065 #include <qregexp.h>
00066
00067 namespace KMail {
00068
00069
00070
00071
00072 static inline QString directionOf( const QString & str ) {
00073 return str.isRightToLeft() ? "rtl" : "ltr" ;
00074 }
00075
00076 #if 0
00077
00078
00079
00080 static QString convertToHtmlBlock( const QString & str, bool useSpan=false ) {
00081 QString dir = directionOf( str );
00082 QString format = "<%1 dir=\"%3\">%4</%2>";
00083 return format.arg( useSpan ? "span" : "div" )
00084 .arg( useSpan ? "span" : "div" )
00085 .arg( dir )
00086 .arg( LinkLocator::convertToHtml( str ) );
00087 }
00088 #endif
00089
00090
00091 static QString strToHtml( const QString & str,
00092 int flags = LinkLocator::PreserveSpaces ) {
00093 return LinkLocator::convertToHtml( str, flags );
00094 }
00095
00096
00097
00098
00099
00100
00101 class BriefHeaderStyle : public HeaderStyle {
00102 friend class ::KMail::HeaderStyle;
00103 protected:
00104 BriefHeaderStyle() : HeaderStyle() {}
00105 virtual ~BriefHeaderStyle() {}
00106
00107 public:
00108 const char * name() const { return "brief"; }
00109 const HeaderStyle * next() const { return plain(); }
00110 const HeaderStyle * prev() const { return fancy(); }
00111
00112 QString format( const KMMessage * message, const HeaderStrategy * strategy,
00113 const QString & vCardName, bool printing ) const;
00114 };
00115
00116 QString BriefHeaderStyle::format( const KMMessage * message,
00117 const HeaderStrategy * strategy,
00118 const QString & vCardName, bool printing ) const {
00119 if ( !message ) return QString::null;
00120 if ( !strategy )
00121 strategy = HeaderStrategy::brief();
00122
00123
00124
00125
00126 QString dir = QApplication::reverseLayout() ? "rtl" : "ltr" ;
00127
00128
00129
00130
00131
00132
00133
00134 QString subjectDir;
00135 if (!message->subject().isEmpty())
00136 subjectDir = directionOf( message->cleanSubject() );
00137 else
00138 subjectDir = directionOf( i18n("No Subject") );
00139
00140
00141 QString dateString;
00142 if( printing ) {
00143 QDateTime dateTime;
00144 KLocale * locale = KGlobal::locale();
00145 dateTime.setTime_t( message->date() );
00146 dateString = locale->formatDateTime( dateTime );
00147 } else {
00148 dateString = message->dateStr();
00149 }
00150
00151 QString headerStr = "<div class=\"header\" dir=\"" + dir + "\">\n";
00152
00153 if ( strategy->showHeader( "subject" ) )
00154 headerStr += "<div dir=\"" + subjectDir + "\">\n"
00155 "<b style=\"font-size:130%\">" +
00156 strToHtml( message->subject() ) +
00157 "</b></div>\n";
00158
00159 QStringList headerParts;
00160
00161 if ( strategy->showHeader( "from" ) ) {
00162 QString fromStr = message->from();
00163 if ( fromStr.isEmpty() )
00164 fromStr = message->fromStrip();
00165 QString fromPart = KMMessage::emailAddrAsAnchor( fromStr, true );
00166 if ( !vCardName.isEmpty() )
00167 fromPart += " <a href=\"" + vCardName + "\">" + i18n("[vCard]") + "</a>";
00168 headerParts << fromPart;
00169 }
00170
00171 if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
00172 headerParts << i18n("CC: ") + KMMessage::emailAddrAsAnchor( message->cc(), true );
00173
00174 if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
00175 headerParts << i18n("BCC: ") + KMMessage::emailAddrAsAnchor( message->bcc(), true );
00176
00177 if ( strategy->showHeader( "date" ) )
00178 headerParts << strToHtml(message->dateShortStr());
00179
00180
00181 headerStr += " (" + headerParts.grep( QRegExp( "\\S" ) ).join( ",\n" ) + ')';
00182
00183 headerStr += "</div>\n";
00184
00185
00186
00187 return headerStr;
00188 }
00189
00190
00191
00192
00193
00194
00195
00196 class PlainHeaderStyle : public HeaderStyle {
00197 friend class ::KMail::HeaderStyle;
00198 protected:
00199 PlainHeaderStyle() : HeaderStyle() {}
00200 virtual ~PlainHeaderStyle() {}
00201
00202 public:
00203 const char * name() const { return "plain"; }
00204 const HeaderStyle * next() const { return fancy(); }
00205 const HeaderStyle * prev() const { return brief(); }
00206
00207 QString format( const KMMessage * message, const HeaderStrategy * strategy,
00208 const QString & vCardName, bool printing ) const;
00209
00210 private:
00211 QString formatAllMessageHeaders( const KMMessage * message ) const;
00212 };
00213
00214 QString PlainHeaderStyle::format( const KMMessage * message,
00215 const HeaderStrategy * strategy,
00216 const QString & vCardName, bool printing ) const {
00217 if ( !message ) return QString::null;
00218 if ( !strategy )
00219 strategy = HeaderStrategy::rich();
00220
00221
00222
00223
00224 QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00225
00226
00227
00228
00229
00230
00231
00232 QString subjectDir;
00233 if (!message->subject().isEmpty())
00234 subjectDir = directionOf( message->cleanSubject() );
00235 else
00236 subjectDir = directionOf( i18n("No Subject") );
00237
00238
00239 QString dateString;
00240 if( printing ) {
00241 QDateTime dateTime;
00242 KLocale* locale = KGlobal::locale();
00243 dateTime.setTime_t( message->date() );
00244 dateString = locale->formatDateTime( dateTime );
00245 }
00246 else {
00247 dateString = message->dateStr();
00248 }
00249
00250 QString headerStr;
00251
00252 if ( strategy->headersToDisplay().isEmpty()
00253 && strategy->defaultPolicy() == HeaderStrategy::Display ) {
00254
00255
00256 headerStr= QString("<div class=\"header\" dir=\"ltr\">");
00257 headerStr += formatAllMessageHeaders( message );
00258 return headerStr + "</div>";
00259 }
00260
00261 headerStr = QString("<div class=\"header\" dir=\"%1\">").arg(dir);
00262
00263
00264 if ( strategy->showHeader( "subject" ) )
00265 headerStr += QString("<div dir=\"%1\"><b style=\"font-size:130%\">" +
00266 strToHtml(message->subject()) + "</b></div>\n")
00267 .arg(subjectDir);
00268
00269 if ( strategy->showHeader( "date" ) )
00270 headerStr.append(i18n("Date: ") + strToHtml(dateString)+"<br>\n");
00271
00272 #if 0
00273
00274 QString presence;
00275 QString kabcUid;
00276 if ( strategy->showHeader( "status" ) )
00277 {
00278 KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00279 KABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getFirstEmailAddress( message->from() ) );
00280 ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00281 kabcUid = addresses[0].uid();
00282 presence = imProxy->presenceString( kabcUid );
00283 }
00284 #endif
00285
00286 if ( strategy->showHeader( "from" ) ) {
00287 QString fromStr = message->from();
00288 if ( fromStr.isEmpty() )
00289 fromStr = message->fromStrip();
00290 headerStr.append(i18n("From: ") +
00291 KMMessage::emailAddrAsAnchor( fromStr, false) );
00292 if ( !vCardName.isEmpty() )
00293 headerStr.append(" <a href=\"" + vCardName +
00294 "\">" + i18n("[vCard]") + "</a>" );
00295 #if 0
00296 if ( !presence.isEmpty() && strategy->showHeader( "status" ) )
00297 headerStr.append(" (<span name=\"presence-" + kabcUid + "\">" + presence + "</span>)" );
00298 #endif
00299
00300 if ( strategy->showHeader( "organization" )
00301 && !message->headerField("Organization").isEmpty())
00302 headerStr.append(" (" +
00303 strToHtml(message->headerField("Organization")) + ")");
00304 headerStr.append("<br>\n");
00305 }
00306
00307 if ( strategy->showHeader( "to" ) )
00308 headerStr.append(i18n("To: ")+
00309 KMMessage::emailAddrAsAnchor(message->to(),FALSE) + "<br>\n");
00310
00311 if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
00312 headerStr.append(i18n("CC: ")+
00313 KMMessage::emailAddrAsAnchor(message->cc(),FALSE) + "<br>\n");
00314
00315 if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
00316 headerStr.append(i18n("BCC: ")+
00317 KMMessage::emailAddrAsAnchor(message->bcc(),FALSE) + "<br>\n");
00318
00319 if ( strategy->showHeader( "reply-to" ) && !message->replyTo().isEmpty())
00320 headerStr.append(i18n("Reply to: ")+
00321 KMMessage::emailAddrAsAnchor(message->replyTo(),FALSE) + "<br>\n");
00322
00323 headerStr += "</div>\n";
00324
00325 return headerStr;
00326 }
00327
00328 QString PlainHeaderStyle::formatAllMessageHeaders( const KMMessage * message ) const {
00329 const DwHeaders & headers = message->headers();
00330 QString result;
00331
00332 for ( const DwField * field = headers.FirstField() ; field ; field = field->Next() ) {
00333 result += ( field->FieldNameStr() + ": " ).c_str();
00334 result += strToHtml( field->FieldBodyStr().c_str() );
00335 result += "<br>\n";
00336 }
00337
00338 return result;
00339 }
00340
00341
00342
00343
00344
00345
00346 class FancyHeaderStyle : public HeaderStyle {
00347 friend class ::KMail::HeaderStyle;
00348 protected:
00349 FancyHeaderStyle() : HeaderStyle() {}
00350 virtual ~FancyHeaderStyle() {}
00351
00352 public:
00353 const char * name() const { return "fancy"; }
00354 const HeaderStyle * next() const { return brief(); }
00355 const HeaderStyle * prev() const { return plain(); }
00356
00357 QString format( const KMMessage * message, const HeaderStrategy * strategy,
00358 const QString & vCardName, bool printing ) const;
00359 static QString imgToDataUrl( const QImage & image,
00360 const char *fmt = "PNG" );
00361
00362 private:
00363 static QString drawSpamMeter( double percent, const QString & filterHeader );
00364
00365 };
00366
00367 QString FancyHeaderStyle::drawSpamMeter( double percent,
00368 const QString & filterHeader )
00369 {
00370 QImage meterBar( 20, 1, 8, 24 );
00371 const unsigned short gradient[20][3] = {
00372 { 0, 255, 0 },
00373 { 27, 254, 0 },
00374 { 54, 252, 0 },
00375 { 80, 250, 0 },
00376 { 107, 249, 0 },
00377 { 135, 247, 0 },
00378 { 161, 246, 0 },
00379 { 187, 244, 0 },
00380 { 214, 242, 0 },
00381 { 241, 241, 0 },
00382 { 255, 228, 0 },
00383 { 255, 202, 0 },
00384 { 255, 177, 0 },
00385 { 255, 151, 0 },
00386 { 255, 126, 0 },
00387 { 255, 101, 0 },
00388 { 255, 76, 0 },
00389 { 255, 51, 0 },
00390 { 255, 25, 0 },
00391 { 255, 0, 0 }
00392 };
00393 meterBar.setColor( 21, qRgb( 255, 255, 255 ) );
00394 meterBar.setColor( 22, qRgb( 170, 170, 170 ) );
00395 if ( percent < 0 )
00396 meterBar.fill( 22 );
00397 else {
00398 meterBar.fill( 21 );
00399 int max = QMIN( 20, static_cast<int>( percent ) / 5 );
00400 for ( int i = 0; i < max; ++i ) {
00401 meterBar.setColor( i+1, qRgb( gradient[i][0], gradient[i][1],
00402 gradient[i][2] ) );
00403 meterBar.setPixel( i, 0, i+1 );
00404 }
00405 }
00406 QString titleText = i18n("%1% probability of being spam.\n\nFull report:\n%2")
00407 .arg( QString::number( percent ), filterHeader );
00408 return QString("<img src=\"%1\" width=\"%2\" height=\"%3\" style=\"border: 1px solid black;\" title=\"%4\"> ")
00409 .arg( imgToDataUrl( meterBar, "PPM" ), QString::number( 20 ),
00410 QString::number( 5 ), titleText );
00411 }
00412
00413
00414 QString FancyHeaderStyle::format( const KMMessage * message,
00415 const HeaderStrategy * strategy,
00416 const QString & vCardName, bool printing ) const {
00417 if ( !message ) return QString::null;
00418 if ( !strategy )
00419 strategy = HeaderStrategy::rich();
00420
00421 KConfigGroup configReader( KMKernel::config(), "Reader" );
00422
00423
00424
00425
00426
00427 QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00428 QString headerStr = QString("<div class=\"fancy header\" dir=\"%1\">\n").arg(dir);
00429
00430
00431
00432
00433
00434
00435
00436 QString subjectDir;
00437 if ( !message->subject().isEmpty() )
00438 subjectDir = directionOf( message->cleanSubject() );
00439 else
00440 subjectDir = directionOf( i18n("No Subject") );
00441
00442
00443 QString dateString;
00444 if( printing ) {
00445 QDateTime dateTime;
00446 KLocale* locale = KGlobal::locale();
00447 dateTime.setTime_t( message->date() );
00448 dateString = locale->formatDateTime( dateTime );
00449 }
00450 else {
00451 dateString = message->dateStr();
00452 }
00453
00454
00455
00456
00457
00458
00459 QString spamHTML;
00460
00461 if ( configReader.readBoolEntry( "showSpamStatus", true ) ) {
00462 SpamScores scores = SpamHeaderAnalyzer::getSpamScores( message );
00463 for ( SpamScoresIterator it = scores.begin(); it != scores.end(); ++it )
00464 spamHTML += (*it).agent() + " " +
00465 drawSpamMeter( (*it).score(), (*it).spamHeader() );
00466 }
00467
00468 QString userHTML;
00469 QString presence;
00470
00471
00472
00473 ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00474 QString kabcUid;
00475 KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00476 KABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getFirstEmailAddress( message->from() ) );
00477
00478 QString photoURL;
00479 int photoWidth = 60;
00480 int photoHeight = 60;
00481 if( addresses.count() == 1 )
00482 {
00483
00484 kabcUid = addresses[0].uid();
00485
00486 if ( imProxy->initialize() ) {
00487
00488 presence = imProxy->presenceString( kabcUid );
00489 if ( !presence.isEmpty() )
00490 {
00491 QString presenceIcon = QString::fromLatin1( " <img src=\"%1\"/>" )
00492 .arg( imgToDataUrl( imProxy->presenceIcon( kabcUid ).convertToImage() ) );
00493 presence += presenceIcon;
00494 }
00495 }
00496
00497 if ( addresses[0].photo().isIntern() )
00498 {
00499
00500
00501 QImage photo = addresses[0].photo().data();
00502 if ( !photo.isNull() )
00503 {
00504 photoWidth = photo.width();
00505 photoHeight = photo.height();
00506
00507 if ( photoHeight > 60 ) {
00508 double ratio = ( double )photoHeight / ( double )photoWidth;
00509 photoHeight = 60;
00510 photoWidth = (int)( 60 / ratio );
00511 photo = photo.smoothScale( photoWidth, photoHeight );
00512 }
00513 photoURL = imgToDataUrl( photo );
00514 }
00515 }
00516 else
00517 {
00518
00519 photoURL = addresses[0].photo().url();
00520 if ( photoURL.startsWith("/") )
00521 photoURL.prepend( "file:" );
00522 }
00523 }
00524 else
00525 {
00526 kdDebug( 5006 ) << "Multiple / No addressees matched email address; Count is " << addresses.count() << endl;
00527 userHTML = " ";
00528 }
00529
00530 if( photoURL.isEmpty() )
00531 {
00532
00533 QString xfaceURL;
00534 QString xfhead = message->headerField( "X-Face" );
00535 if ( !xfhead.isEmpty() )
00536 {
00537 KXFace xf;
00538 photoURL = imgToDataUrl( xf.toImage( xfhead ) );
00539 photoWidth = 48;
00540 photoHeight = 48;
00541
00542 }
00543 }
00544
00545 if( !photoURL.isEmpty() )
00546 {
00547
00548 userHTML = QString("<img src=\"%1\" width=\"%2\" height=\"%3\">")
00549 .arg( photoURL ).arg( photoWidth ).arg( photoHeight );
00550 if ( presence.isEmpty() ) {
00551 userHTML = QString("<div class=\"senderpic\">") + userHTML + "</div>";
00552 } else {
00553 userHTML = QString( "<div class=\"senderpic\">"
00554 "<a href=\"im:%1\">%2<div class=\"senderstatus\">"
00555 "<span name=\"presence-%3\">%4</span></div></a>"
00556 "</div>" ).arg( kabcUid )
00557 .arg( userHTML )
00558 .arg( kabcUid )
00559 .arg( presence );
00560 }
00561 } else {
00562
00563 if ( !presence.isEmpty() )
00564 userHTML = QString( "<a href=\"im:%1\"><div class=\"senderstatus\">"
00565 "<span name=\"presence-%2\">%3</span></div></a>" )
00566 .arg( kabcUid )
00567 .arg( kabcUid )
00568 .arg( presence );
00569 }
00570 #if 0
00571
00572 if ( imProxy->imAppsAvailable() )
00573 presence = "<a name=\"launchim\" href=\"kmail:startIMApp\">" + i18n("Launch IM") + "</a></span>";
00574
00575
00576 kdDebug( 5006 ) << "final presence: '" << presence << "'" << endl;
00577 #endif
00578
00579
00580
00581
00582 if ( strategy->showHeader( "subject" ) ) {
00583 const int flags = LinkLocator::PreserveSpaces |
00584 ( GlobalSettings::self()->showEmoticons() ?
00585 LinkLocator::ReplaceSmileys : 0 );
00586 headerStr += QString("<div dir=\"%1\">%2</div>\n")
00587 .arg(subjectDir)
00588 .arg(message->subject().isEmpty()?
00589 i18n("No Subject") :
00590 strToHtml( message->subject(), flags ));
00591 }
00592 headerStr += "<table class=\"outer\"><tr><td width=\"100%\"><table>\n";
00593
00594
00595
00596
00597 if ( strategy->showHeader( "from" ) ) {
00598 QString fromStr = message->from();
00599 if ( fromStr.isEmpty() )
00600 fromStr = message->fromStrip();
00601 headerStr += QString("<tr><th>%1</th>\n"
00602 "<td>")
00603 .arg(i18n("From: "))
00604 + KMMessage::emailAddrAsAnchor( fromStr, false )
00605 + ( !message->headerField( "Resent-From" ).isEmpty() ? " "
00606 + i18n("(resent from %1)")
00607 .arg( KMMessage::emailAddrAsAnchor(
00608 message->headerField( "Resent-From" ),FALSE) )
00609 : QString("") )
00610 + ( !vCardName.isEmpty() ? " <a href=\"" + vCardName + "\">"
00611 + i18n("[vCard]") + "</a>"
00612 : QString("") )
00613 #if 0
00614 + ( ( !presence.isEmpty() )
00615 ? " (<span name=\"presence-" + kabcUid + "\">" + presence + "</span>)"
00616 : QString("") )
00617 #endif
00618 + ( message->headerField("Organization").isEmpty()
00619 ? QString("")
00620 : " ("
00621 + strToHtml(message->headerField("Organization"))
00622 + ")")
00623 + "</td></tr>\n";
00624 }
00625
00626 if ( strategy->showHeader( "to" ) )
00627 headerStr.append(QString("<tr><th>%1</th>\n"
00628 "<td>%2</td></tr>\n")
00629 .arg(i18n("To: "))
00630 .arg(KMMessage::emailAddrAsAnchor(message->to(),FALSE)));
00631
00632
00633 if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty())
00634 headerStr.append(QString("<tr><th>%1</th>\n"
00635 "<td>%2</td></tr>\n")
00636 .arg(i18n("CC: "))
00637 .arg(KMMessage::emailAddrAsAnchor(message->cc(),FALSE)));
00638
00639
00640 if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty())
00641 headerStr.append(QString("<tr><th>%1</th>\n"
00642 "<td>%2</td></tr>\n")
00643 .arg(i18n("BCC: "))
00644 .arg(KMMessage::emailAddrAsAnchor(message->bcc(),FALSE)));
00645
00646 if ( strategy->showHeader( "date" ) )
00647 headerStr.append(QString("<tr><th>%1</th>\n"
00648 "<td dir=\"%2\">%3</td></tr>\n")
00649 .arg(i18n("Date: "))
00650 .arg( directionOf( message->dateStr() ) )
00651 .arg(strToHtml(dateString)));
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661 headerStr.append(
00662 QString( "</table></td><td align=\"center\">%1</td></tr></table>\n" ).arg(userHTML) );
00663
00664 if ( !spamHTML.isEmpty() )
00665 headerStr.append( QString( "<div class=\"spamheader\" dir=\"%1\"><b>%2</b> <span style=\"padding-left: 20px;\">%3</span></div>\n")
00666 .arg( subjectDir, i18n("Spam Status:"), spamHTML ) );
00667
00668 headerStr += "</div>\n\n";
00669 return headerStr;
00670 }
00671
00672 QString FancyHeaderStyle::imgToDataUrl( const QImage &image, const char* fmt )
00673 {
00674 QByteArray ba;
00675 QBuffer buffer( ba );
00676 buffer.open( IO_WriteOnly );
00677 image.save( &buffer, fmt );
00678 return QString::fromLatin1("data:image/%1;base64,%2")
00679 .arg( fmt, KCodecs::base64Encode( ba ) );
00680 }
00681
00682
00683
00684
00685
00686 HeaderStyle::HeaderStyle() {
00687
00688 }
00689
00690 HeaderStyle::~HeaderStyle() {
00691
00692 }
00693
00694 const HeaderStyle * HeaderStyle::create( Type type ) {
00695 switch ( type ) {
00696 case Brief: return brief();
00697 case Plain: return plain();
00698 case Fancy: return fancy();
00699 }
00700 kdFatal( 5006 ) << "HeaderStyle::create(): Unknown header style ( type == "
00701 << (int)type << " ) requested!" << endl;
00702 return 0;
00703 }
00704
00705 const HeaderStyle * HeaderStyle::create( const QString & type ) {
00706 QString lowerType = type.lower();
00707 if ( lowerType == "brief" ) return brief();
00708 if ( lowerType == "plain" ) return plain();
00709
00710
00711
00712 return fancy();
00713 }
00714
00715 static const HeaderStyle * briefStyle = 0;
00716 static const HeaderStyle * plainStyle = 0;
00717 static const HeaderStyle * fancyStyle = 0;
00718
00719 const HeaderStyle * HeaderStyle::brief() {
00720 if ( !briefStyle )
00721 briefStyle = new BriefHeaderStyle();
00722 return briefStyle;
00723 }
00724
00725 const HeaderStyle * HeaderStyle::plain() {
00726 if ( !plainStyle )
00727 plainStyle = new PlainHeaderStyle();
00728 return plainStyle;
00729 }
00730
00731 const HeaderStyle * HeaderStyle::fancy() {
00732 if ( !fancyStyle )
00733 fancyStyle = new FancyHeaderStyle();
00734 return fancyStyle;
00735 }
00736
00737 }