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 = QString("<div class=\"header\" dir=\"%1\">").arg(dir);
00251
00252 if ( strategy->headersToDisplay().isEmpty()
00253 && strategy->defaultPolicy() == HeaderStrategy::Display ) {
00254
00255 headerStr += formatAllMessageHeaders( message );
00256 return headerStr + "</div>";
00257 }
00258
00259
00260 if ( strategy->showHeader( "subject" ) )
00261 headerStr += QString("<div dir=\"%1\"><b style=\"font-size:130%\">" +
00262 strToHtml(message->subject()) + "</b></div>\n")
00263 .arg(subjectDir);
00264
00265 if ( strategy->showHeader( "date" ) )
00266 headerStr.append(i18n("Date: ") + strToHtml(dateString)+"<br>\n");
00267
00268 #if 0
00269
00270 QString presence;
00271 QString kabcUid;
00272 if ( strategy->showHeader( "status" ) )
00273 {
00274 KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00275 KABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getFirstEmailAddress( message->from() ) );
00276 ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00277 kabcUid = addresses[0].uid();
00278 presence = imProxy->presenceString( kabcUid );
00279 }
00280 #endif
00281
00282 if ( strategy->showHeader( "from" ) ) {
00283 QString fromStr = message->from();
00284 if ( fromStr.isEmpty() )
00285 fromStr = message->fromStrip();
00286 headerStr.append(i18n("From: ") +
00287 KMMessage::emailAddrAsAnchor( fromStr, false) );
00288 if ( !vCardName.isEmpty() )
00289 headerStr.append(" <a href=\"" + vCardName +
00290 "\">" + i18n("[vCard]") + "</a>" );
00291 #if 0
00292 if ( !presence.isEmpty() && strategy->showHeader( "status" ) )
00293 headerStr.append(" (<span name=\"presence-" + kabcUid + "\">" + presence + "</span>)" );
00294 #endif
00295
00296 if ( strategy->showHeader( "organization" )
00297 && !message->headerField("Organization").isEmpty())
00298 headerStr.append(" (" +
00299 strToHtml(message->headerField("Organization")) + ")");
00300 headerStr.append("<br>\n");
00301 }
00302
00303 if ( strategy->showHeader( "to" ) )
00304 headerStr.append(i18n("To: ")+
00305 KMMessage::emailAddrAsAnchor(message->to(),FALSE) + "<br>\n");
00306
00307 if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
00308 headerStr.append(i18n("CC: ")+
00309 KMMessage::emailAddrAsAnchor(message->cc(),FALSE) + "<br>\n");
00310
00311 if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
00312 headerStr.append(i18n("BCC: ")+
00313 KMMessage::emailAddrAsAnchor(message->bcc(),FALSE) + "<br>\n");
00314
00315 if ( strategy->showHeader( "reply-to" ) && !message->replyTo().isEmpty())
00316 headerStr.append(i18n("Reply to: ")+
00317 KMMessage::emailAddrAsAnchor(message->replyTo(),FALSE) + "<br>\n");
00318
00319 headerStr += "</div>\n";
00320
00321 return headerStr;
00322 }
00323
00324 QString PlainHeaderStyle::formatAllMessageHeaders( const KMMessage * message ) const {
00325 const DwHeaders & headers = message->headers();
00326 QString result;
00327
00328 for ( const DwField * field = headers.FirstField() ; field ; field = field->Next() ) {
00329 result += ( field->FieldNameStr() + ": " ).c_str();
00330 result += strToHtml( field->FieldBodyStr().c_str() );
00331 result += "<br>\n";
00332 }
00333
00334 return result;
00335 }
00336
00337
00338
00339
00340
00341
00342 class FancyHeaderStyle : public HeaderStyle {
00343 friend class ::KMail::HeaderStyle;
00344 protected:
00345 FancyHeaderStyle() : HeaderStyle() {}
00346 virtual ~FancyHeaderStyle() {}
00347
00348 public:
00349 const char * name() const { return "fancy"; }
00350 const HeaderStyle * next() const { return brief(); }
00351 const HeaderStyle * prev() const { return plain(); }
00352
00353 QString format( const KMMessage * message, const HeaderStrategy * strategy,
00354 const QString & vCardName, bool printing ) const;
00355 static QString imgToDataUrl( const QImage & image,
00356 const char *fmt = "PNG" );
00357
00358 private:
00359 static QString drawSpamMeter( double percent, const QString & filterHeader );
00360
00361 };
00362
00363 QString FancyHeaderStyle::drawSpamMeter( double percent,
00364 const QString & filterHeader )
00365 {
00366 QImage meterBar( 20, 1, 8, 24 );
00367 const unsigned short gradient[20][3] = {
00368 { 0, 255, 0 },
00369 { 27, 254, 0 },
00370 { 54, 252, 0 },
00371 { 80, 250, 0 },
00372 { 107, 249, 0 },
00373 { 135, 247, 0 },
00374 { 161, 246, 0 },
00375 { 187, 244, 0 },
00376 { 214, 242, 0 },
00377 { 241, 241, 0 },
00378 { 255, 228, 0 },
00379 { 255, 202, 0 },
00380 { 255, 177, 0 },
00381 { 255, 151, 0 },
00382 { 255, 126, 0 },
00383 { 255, 101, 0 },
00384 { 255, 76, 0 },
00385 { 255, 51, 0 },
00386 { 255, 25, 0 },
00387 { 255, 0, 0 }
00388 };
00389 meterBar.setColor( 21, qRgb( 255, 255, 255 ) );
00390 meterBar.setColor( 22, qRgb( 170, 170, 170 ) );
00391 if ( percent < 0 )
00392 meterBar.fill( 22 );
00393 else {
00394 meterBar.fill( 21 );
00395 int max = QMIN( 20, static_cast<int>( percent ) / 5 );
00396 for ( int i = 0; i < max; ++i ) {
00397 meterBar.setColor( i+1, qRgb( gradient[i][0], gradient[i][1],
00398 gradient[i][2] ) );
00399 meterBar.setPixel( i, 0, i+1 );
00400 }
00401 }
00402 QString titleText = i18n("%1% probability of being spam.\n\nFull report:\n%2")
00403 .arg( QString::number( percent ), filterHeader );
00404 return QString("<img src=\"%1\" width=\"%2\" height=\"%3\" style=\"border: 1px solid black;\" title=\"%4\"> ")
00405 .arg( imgToDataUrl( meterBar, "PPM" ), QString::number( 20 ),
00406 QString::number( 5 ), titleText );
00407 }
00408
00409
00410 QString FancyHeaderStyle::format( const KMMessage * message,
00411 const HeaderStrategy * strategy,
00412 const QString & vCardName, bool printing ) const {
00413 if ( !message ) return QString::null;
00414 if ( !strategy )
00415 strategy = HeaderStrategy::rich();
00416
00417 KConfigGroup configReader( KMKernel::config(), "Reader" );
00418
00419
00420
00421
00422
00423 QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00424 QString headerStr = QString("<div class=\"fancy header\" dir=\"%1\">\n").arg(dir);
00425
00426
00427
00428
00429
00430
00431
00432 QString subjectDir;
00433 if ( !message->subject().isEmpty() )
00434 subjectDir = directionOf( message->cleanSubject() );
00435 else
00436 subjectDir = directionOf( i18n("No Subject") );
00437
00438
00439 QString dateString;
00440 if( printing ) {
00441 QDateTime dateTime;
00442 KLocale* locale = KGlobal::locale();
00443 dateTime.setTime_t( message->date() );
00444 dateString = locale->formatDateTime( dateTime );
00445 }
00446 else {
00447 dateString = message->dateStr();
00448 }
00449
00450
00451
00452
00453
00454
00455 QString spamHTML;
00456
00457 if ( configReader.readBoolEntry( "showSpamStatus", true ) ) {
00458 SpamScores scores = SpamHeaderAnalyzer::getSpamScores( message );
00459 for ( SpamScoresIterator it = scores.begin(); it != scores.end(); ++it )
00460 spamHTML += (*it).agent() + " " +
00461 drawSpamMeter( (*it).score(), (*it).spamHeader() );
00462 }
00463
00464 QString userHTML;
00465 QString presence;
00466
00467
00468
00469 ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00470 QString kabcUid;
00471 KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00472 KABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getFirstEmailAddress( message->from() ) );
00473
00474 QString photoURL;
00475 int photoWidth = 60;
00476 int photoHeight = 60;
00477 if( addresses.count() == 1 )
00478 {
00479
00480 kabcUid = addresses[0].uid();
00481
00482 if ( imProxy->initialize() ) {
00483
00484 presence = imProxy->presenceString( kabcUid );
00485 if ( !presence.isEmpty() )
00486 {
00487 QString presenceIcon = QString::fromLatin1( " <img src=\"%1\"/>" )
00488 .arg( imgToDataUrl( imProxy->presenceIcon( kabcUid ).convertToImage() ) );
00489 presence += presenceIcon;
00490 }
00491 }
00492
00493 if ( addresses[0].photo().isIntern() )
00494 {
00495
00496
00497 QImage photo = addresses[0].photo().data();
00498 if ( !photo.isNull() )
00499 {
00500 photoWidth = photo.width();
00501 photoHeight = photo.height();
00502
00503 if ( photoHeight > 60 ) {
00504 double ratio = ( double )photoHeight / ( double )photoWidth;
00505 photoHeight = 60;
00506 photoWidth = (int)( 60 / ratio );
00507 photo = photo.smoothScale( photoWidth, photoHeight );
00508 }
00509 photoURL = imgToDataUrl( photo );
00510 }
00511 }
00512 else
00513 {
00514
00515 photoURL = addresses[0].photo().url();
00516 if ( photoURL.startsWith("/") )
00517 photoURL.prepend( "file:" );
00518 }
00519 }
00520 else
00521 {
00522 kdDebug( 5006 ) << "Multiple / No addressees matched email address; Count is " << addresses.count() << endl;
00523 userHTML = " ";
00524 }
00525
00526 if( photoURL.isEmpty() )
00527 {
00528
00529 QString xfaceURL;
00530 QString xfhead = message->headerField( "X-Face" );
00531 if ( !xfhead.isEmpty() )
00532 {
00533 KXFace xf;
00534 photoURL = imgToDataUrl( xf.toImage( xfhead ) );
00535 photoWidth = 48;
00536 photoHeight = 48;
00537
00538 }
00539 }
00540
00541 if( !photoURL.isEmpty() )
00542 {
00543
00544 userHTML = QString("<img src=\"%1\" width=\"%2\" height=\"%3\">")
00545 .arg( photoURL ).arg( photoWidth ).arg( photoHeight );
00546 if ( presence.isEmpty() ) {
00547 userHTML = QString("<div class=\"senderpic\">") + userHTML + "</div>";
00548 } else {
00549 userHTML = QString( "<div class=\"senderpic\">"
00550 "<a href=\"im:%1\">%2<div class=\"senderstatus\">"
00551 "<span name=\"presence-%3\">%4</span></div></a>"
00552 "</div>" ).arg( kabcUid )
00553 .arg( userHTML )
00554 .arg( kabcUid )
00555 .arg( presence );
00556 }
00557 } else {
00558
00559 if ( !presence.isEmpty() )
00560 userHTML = QString( "<a href=\"im:%1\"><div class=\"senderstatus\">"
00561 "<span name=\"presence-%2\">%3</span></div></a>" )
00562 .arg( kabcUid )
00563 .arg( kabcUid )
00564 .arg( presence );
00565 }
00566 #if 0
00567
00568 if ( imProxy->imAppsAvailable() )
00569 presence = "<a name=\"launchim\" href=\"kmail:startIMApp\">" + i18n("Launch IM") + "</a></span>";
00570
00571
00572 kdDebug( 5006 ) << "final presence: '" << presence << "'" << endl;
00573 #endif
00574
00575
00576
00577
00578 if ( strategy->showHeader( "subject" ) ) {
00579 const int flags = LinkLocator::PreserveSpaces |
00580 ( GlobalSettings::self()->showEmoticons() ?
00581 LinkLocator::ReplaceSmileys : 0 );
00582 headerStr += QString("<div dir=\"%1\">%2</div>\n")
00583 .arg(subjectDir)
00584 .arg(message->subject().isEmpty()?
00585 i18n("No Subject") :
00586 strToHtml( message->subject(), flags ));
00587 }
00588 headerStr += "<table class=\"outer\"><tr><td width=\"100%\"><table>\n";
00589
00590
00591
00592
00593 if ( strategy->showHeader( "from" ) ) {
00594 QString fromStr = message->from();
00595 if ( fromStr.isEmpty() )
00596 fromStr = message->fromStrip();
00597 headerStr += QString("<tr><th>%1</th>\n"
00598 "<td>")
00599 .arg(i18n("From: "))
00600 + KMMessage::emailAddrAsAnchor( fromStr, false )
00601 + ( !message->headerField( "Resent-From" ).isEmpty() ? " "
00602 + i18n("(resent from %1)")
00603 .arg( KMMessage::emailAddrAsAnchor(
00604 message->headerField( "Resent-From" ),FALSE) )
00605 : QString("") )
00606 + ( !vCardName.isEmpty() ? " <a href=\"" + vCardName + "\">"
00607 + i18n("[vCard]") + "</a>"
00608 : QString("") )
00609 #if 0
00610 + ( ( !presence.isEmpty() )
00611 ? " (<span name=\"presence-" + kabcUid + "\">" + presence + "</span>)"
00612 : QString("") )
00613 #endif
00614 + ( message->headerField("Organization").isEmpty()
00615 ? QString("")
00616 : " ("
00617 + strToHtml(message->headerField("Organization"))
00618 + ")")
00619 + "</td></tr>\n";
00620 }
00621
00622 if ( strategy->showHeader( "to" ) )
00623 headerStr.append(QString("<tr><th>%1</th>\n"
00624 "<td>%2</td></tr>\n")
00625 .arg(i18n("To: "))
00626 .arg(KMMessage::emailAddrAsAnchor(message->to(),FALSE)));
00627
00628
00629 if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty())
00630 headerStr.append(QString("<tr><th>%1</th>\n"
00631 "<td>%2</td></tr>\n")
00632 .arg(i18n("CC: "))
00633 .arg(KMMessage::emailAddrAsAnchor(message->cc(),FALSE)));
00634
00635
00636 if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty())
00637 headerStr.append(QString("<tr><th>%1</th>\n"
00638 "<td>%2</td></tr>\n")
00639 .arg(i18n("BCC: "))
00640 .arg(KMMessage::emailAddrAsAnchor(message->bcc(),FALSE)));
00641
00642 if ( strategy->showHeader( "date" ) )
00643 headerStr.append(QString("<tr><th>%1</th>\n"
00644 "<td dir=\"%2\">%3</td></tr>\n")
00645 .arg(i18n("Date: "))
00646 .arg( directionOf( message->dateStr() ) )
00647 .arg(strToHtml(dateString)));
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657 headerStr.append(
00658 QString( "</table></td><td align=\"center\">%1</td></tr></table>\n" ).arg(userHTML) );
00659
00660 if ( !spamHTML.isEmpty() )
00661 headerStr.append( QString( "<div class=\"spamheader\" dir=\"%1\"><b>%2</b> <span style=\"padding-left: 20px;\">%3</span></div>\n")
00662 .arg( subjectDir, i18n("Spam Status:"), spamHTML ) );
00663
00664 headerStr += "</div>\n\n";
00665 return headerStr;
00666 }
00667
00668 QString FancyHeaderStyle::imgToDataUrl( const QImage &image, const char* fmt )
00669 {
00670 QByteArray ba;
00671 QBuffer buffer( ba );
00672 buffer.open( IO_WriteOnly );
00673 image.save( &buffer, fmt );
00674 return QString::fromLatin1("data:image/%1;base64,%2")
00675 .arg( fmt, KCodecs::base64Encode( ba ) );
00676 }
00677
00678
00679
00680
00681
00682 HeaderStyle::HeaderStyle() {
00683
00684 }
00685
00686 HeaderStyle::~HeaderStyle() {
00687
00688 }
00689
00690 const HeaderStyle * HeaderStyle::create( Type type ) {
00691 switch ( type ) {
00692 case Brief: return brief();
00693 case Plain: return plain();
00694 case Fancy: return fancy();
00695 }
00696 kdFatal( 5006 ) << "HeaderStyle::create(): Unknown header style ( type == "
00697 << (int)type << " ) requested!" << endl;
00698 return 0;
00699 }
00700
00701 const HeaderStyle * HeaderStyle::create( const QString & type ) {
00702 QString lowerType = type.lower();
00703 if ( lowerType == "brief" ) return brief();
00704 if ( lowerType == "plain" ) return plain();
00705
00706
00707
00708 return fancy();
00709 }
00710
00711 static const HeaderStyle * briefStyle = 0;
00712 static const HeaderStyle * plainStyle = 0;
00713 static const HeaderStyle * fancyStyle = 0;
00714
00715 const HeaderStyle * HeaderStyle::brief() {
00716 if ( !briefStyle )
00717 briefStyle = new BriefHeaderStyle();
00718 return briefStyle;
00719 }
00720
00721 const HeaderStyle * HeaderStyle::plain() {
00722 if ( !plainStyle )
00723 plainStyle = new PlainHeaderStyle();
00724 return plainStyle;
00725 }
00726
00727 const HeaderStyle * HeaderStyle::fancy() {
00728 if ( !fancyStyle )
00729 fancyStyle = new FancyHeaderStyle();
00730 return fancyStyle;
00731 }
00732
00733 }