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 
00042 
00043 #include <mimelib/string.h>
00044 #include <mimelib/field.h>
00045 #include <mimelib/headers.h>
00046 
00047 #include <kdebug.h>
00048 #include <klocale.h>
00049 #include <kglobal.h>
00050 
00051 #include <qdatetime.h>
00052 #include <qapplication.h>
00053 #include <qregexp.h>
00054 
00055 namespace KMail {
00056 
00057   //
00058   // Convenience functions:
00059   //
00060   static inline QString directionOf( const QString & str ) {
00061     return str.isRightToLeft() ? "rtl" : "ltr" ;
00062   }
00063 
00064 #if 0
00065   // Converts to html. Changes URLs into href's, escapes HTML special
00066   // chars and inserts the result into an <div> or <span> tag with
00067   // "dir" set to "rtl" or "ltr" depending on the direction of @p str.
00068   static QString convertToHtmlBlock( const QString & str, bool useSpan=false ) {
00069     QString dir = directionOf( str );
00070     QString format = "<%1 dir=\"%3\">%4</%2>";
00071     return format.arg( useSpan ? "span" : "div" )
00072                  .arg( useSpan ? "span" : "div" )
00073                  .arg( dir )
00074                  .arg( LinkLocator::convertToHtml( str ) );
00075   }
00076 #endif
00077 
00078   // ### tmp wrapper to make kmreaderwin code working:
00079   static QString strToHtml( const QString & str, bool preserveBlanks=true ) {
00080     return LinkLocator::convertToHtml( str, preserveBlanks );
00081   }
00082 
00083   //
00084   // BriefHeaderStyle
00085   //   Show everything in a single line, don't show header field names.
00086   //
00087 
00088   class BriefHeaderStyle : public HeaderStyle {
00089     friend class HeaderStyle;
00090   protected:
00091     BriefHeaderStyle() : HeaderStyle() {}
00092     virtual ~BriefHeaderStyle() {}
00093     
00094   public:
00095     const char * name() const { return "brief"; }
00096     const HeaderStyle * next() const { return plain(); }
00097     const HeaderStyle * prev() const { return fancy(); }
00098 
00099     QString format( const KMMessage * message, const HeaderStrategy * strategy,
00100             const QString & vCardName, bool printing ) const;
00101   };
00102 
00103   QString BriefHeaderStyle::format( const KMMessage * message,
00104                     const HeaderStrategy * strategy,
00105                     const QString & vCardName, bool printing ) const {
00106     if ( !message ) return QString::null;
00107     if ( !strategy )
00108       strategy = HeaderStrategy::brief();
00109 
00110     // The direction of the header is determined according to the direction
00111     // of the application layout.
00112 
00113     QString dir = QApplication::reverseLayout() ? "rtl" : "ltr" ;
00114 
00115     // However, the direction of the message subject within the header is
00116     // determined according to the contents of the subject itself. Since
00117     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00118     // considered left-to-right, they are ignored when determining its
00119     // direction.
00120 
00121     QString subjectDir;
00122     if (!message->subject().isEmpty())
00123       subjectDir = directionOf( message->cleanSubject() );
00124     else
00125       subjectDir = directionOf( i18n("No Subject") );
00126 
00127     // Prepare the date string (when printing always use the localized date)
00128     QString dateString;
00129     if( printing ) {
00130       QDateTime dateTime;
00131       KLocale * locale = KGlobal::locale();
00132       dateTime.setTime_t( message->date() );
00133       dateString = locale->formatDateTime( dateTime );
00134     } else {
00135       dateString = message->dateStr();
00136     }
00137 
00138     QString headerStr = "<div class=\"header\" dir=\"" + dir + "\">\n";
00139 
00140     if ( strategy->showHeader( "subject" ) )
00141       headerStr += "<div dir=\"" + subjectDir + "\">\n"
00142                "<b style=\"font-size:130%\">" +
00143                strToHtml( message->subject() ) +
00144                "</b></div>\n";
00145 
00146     QStringList headerParts;
00147 
00148     if ( strategy->showHeader( "from" ) ) {
00149       QString fromPart = KMMessage::emailAddrAsAnchor( message->from(), true );
00150       if ( !vCardName.isEmpty() )
00151     fromPart += "&nbsp;&nbsp;<a href=\"" + vCardName + "\">" + i18n("[vCard]") + "</a>";
00152       headerParts << fromPart;
00153     }
00154 
00155     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
00156       headerParts << i18n("CC: ") + KMMessage::emailAddrAsAnchor( message->cc(), true );
00157 
00158     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
00159       headerParts << i18n("BCC: ") + KMMessage::emailAddrAsAnchor( message->bcc(), true );
00160 
00161     if ( strategy->showHeader( "date" ) )
00162       headerParts << strToHtml(message->dateShortStr());
00163 
00164     // remove all empty (modulo whitespace) entries and joins them via ", \n"
00165     headerStr += " (" + headerParts.grep( QRegExp( "\\S" ) ).join( ",\n" ) + ')';
00166 
00167     headerStr += "</div>\n";
00168 
00169     // ### iterate over the rest of strategy->headerToDisplay() (or
00170     // ### all headers if DefaultPolicy == Display) (elsewhere, too)
00171     return headerStr;
00172   }
00173 
00174   //
00175   // PlainHeaderStyle:
00176   //   show every header field on a line by itself,
00177   //   show subject larger
00178   //
00179 
00180   class PlainHeaderStyle : public HeaderStyle {
00181     friend class HeaderStyle;
00182   protected:
00183     PlainHeaderStyle() : HeaderStyle() {}
00184     virtual ~PlainHeaderStyle() {}
00185     
00186   public:
00187     const char * name() const { return "plain"; }
00188     const HeaderStyle * next() const { return fancy(); }
00189     const HeaderStyle * prev() const { return brief(); }
00190 
00191     QString format( const KMMessage * message, const HeaderStrategy * strategy,
00192             const QString & vCardName, bool printing ) const;
00193 
00194   private:
00195     QString formatAllMessageHeaders( const KMMessage * message ) const;
00196   };
00197 
00198   QString PlainHeaderStyle::format( const KMMessage * message,
00199                     const HeaderStrategy * strategy,
00200                     const QString & vCardName, bool printing ) const {
00201     if ( !message ) return QString::null;
00202     if ( !strategy )
00203       strategy = HeaderStrategy::rich();
00204 
00205     // The direction of the header is determined according to the direction
00206     // of the application layout.
00207 
00208     QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00209 
00210     // However, the direction of the message subject within the header is
00211     // determined according to the contents of the subject itself. Since
00212     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00213     // considered left-to-right, they are ignored when determining its
00214     // direction.
00215 
00216     QString subjectDir;
00217     if (!message->subject().isEmpty())
00218       subjectDir = directionOf( message->cleanSubject() );
00219     else
00220       subjectDir = directionOf( i18n("No Subject") );
00221 
00222     // Prepare the date string (when printing always use the localized date)
00223     QString dateString;
00224     if( printing ) {
00225       QDateTime dateTime;
00226       KLocale* locale = KGlobal::locale();
00227       dateTime.setTime_t( message->date() );
00228       dateString = locale->formatDateTime( dateTime );
00229     }
00230     else {
00231       dateString = message->dateStr();
00232     }
00233 
00234     QString headerStr = QString("<div class=\"header\" dir=\"%1\">").arg(dir);
00235 
00236     if ( strategy->headersToDisplay().isEmpty()
00237      && strategy->defaultPolicy() == HeaderStrategy::Display ) {
00238       // crude way to emulate "all" headers:
00239       headerStr += formatAllMessageHeaders( message );
00240       return headerStr + "</div>";
00241     }
00242 
00243     //case HdrLong:
00244     if ( strategy->showHeader( "subject" ) )
00245       headerStr += QString("<div dir=\"%1\"><b style=\"font-size:130%\">" +
00246                strToHtml(message->subject()) + "</b></div>\n")
00247                         .arg(subjectDir);
00248 
00249     if ( strategy->showHeader( "date" ) )
00250       headerStr.append(i18n("Date: ") + strToHtml(dateString)+"<br>\n");
00251 
00252     if ( strategy->showHeader( "from" ) ) {
00253       headerStr.append(i18n("From: ") +
00254                KMMessage::emailAddrAsAnchor(message->from(),FALSE));
00255       if ( !vCardName.isEmpty() )
00256     headerStr.append("&nbsp;&nbsp;<a href=\"" + vCardName +
00257              "\">" + i18n("[vCard]") + "</a>" );
00258       if ( strategy->showHeader( "organization" )
00259        && !message->headerField("Organization").isEmpty())
00260     headerStr.append("&nbsp;&nbsp;(" +
00261              strToHtml(message->headerField("Organization")) + ")");
00262       headerStr.append("<br>\n");
00263     }
00264 
00265     if ( strategy->showHeader( "to" ) )
00266       headerStr.append(i18n("To: ")+
00267                KMMessage::emailAddrAsAnchor(message->to(),FALSE) + "<br>\n");
00268 
00269     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
00270       headerStr.append(i18n("CC: ")+
00271                        KMMessage::emailAddrAsAnchor(message->cc(),FALSE) + "<br>\n");
00272 
00273     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
00274       headerStr.append(i18n("BCC: ")+
00275                        KMMessage::emailAddrAsAnchor(message->bcc(),FALSE) + "<br>\n");
00276 
00277     if ( strategy->showHeader( "reply-to" ) && !message->replyTo().isEmpty())
00278       headerStr.append(i18n("Reply to: ")+
00279                      KMMessage::emailAddrAsAnchor(message->replyTo(),FALSE) + "<br>\n");
00280 
00281     headerStr += "</div>\n";
00282 
00283     return headerStr;
00284   }
00285 
00286   QString PlainHeaderStyle::formatAllMessageHeaders( const KMMessage * message ) const {
00287     const DwHeaders & headers = message->headers();
00288     QString result;
00289 
00290     for ( const DwField * field = headers.FirstField() ; field ; field = field->Next() ) {
00291       result += ( field->FieldNameStr() + ": " ).c_str();
00292       result += strToHtml( field->FieldBodyStr().c_str() );
00293       result += "<br>\n";
00294     }
00295 
00296     return result;
00297   }
00298 
00299   //
00300   // FancyHeaderStyle:
00301   //   Like PlainHeaderStyle, but with slick frames and background colours.
00302   //
00303 
00304   class FancyHeaderStyle : public HeaderStyle {
00305     friend class HeaderStyle;
00306   protected:
00307     FancyHeaderStyle() : HeaderStyle() {}
00308     virtual ~FancyHeaderStyle() {}
00309     
00310   public:
00311     const char * name() const { return "fancy"; }
00312     const HeaderStyle * next() const { return brief(); }
00313     const HeaderStyle * prev() const { return plain(); }
00314 
00315     QString format( const KMMessage * message, const HeaderStrategy * strategy,
00316             const QString & vCardName, bool printing ) const;
00317   };
00318 
00319   QString FancyHeaderStyle::format( const KMMessage * message,
00320                     const HeaderStrategy * strategy,
00321                     const QString & vCardName, bool printing ) const {
00322     if ( !message ) return QString::null;
00323     if ( !strategy )
00324       strategy = HeaderStrategy::rich();
00325 
00326     // ### from kmreaderwin begin
00327     // The direction of the header is determined according to the direction
00328     // of the application layout.
00329 
00330     QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00331     QString headerStr = QString("<div class=\"fancy header\" dir=\"%1\">\n").arg(dir);
00332 
00333     // However, the direction of the message subject within the header is
00334     // determined according to the contents of the subject itself. Since
00335     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00336     // considered left-to-right, they are ignored when determining its
00337     // direction.
00338 
00339     QString subjectDir;
00340     if ( !message->subject().isEmpty() )
00341       subjectDir = directionOf( message->cleanSubject() );
00342     else
00343       subjectDir = directionOf( i18n("No Subject") );
00344 
00345     // Prepare the date string (when printing always use the localized date)
00346     QString dateString;
00347     if( printing ) {
00348       QDateTime dateTime;
00349       KLocale* locale = KGlobal::locale();
00350       dateTime.setTime_t( message->date() );
00351       dateString = locale->formatDateTime( dateTime );
00352     }
00353     else {
00354       dateString = message->dateStr();
00355     }
00356 
00357     //case HdrFancy:
00358     // the subject line and box below for details
00359     if ( strategy->showHeader( "subject" ) )
00360       headerStr += QString("<div dir=\"%1\">%2</div>\n")
00361                         .arg(subjectDir)
00362                 .arg(message->subject().isEmpty()?
00363                  i18n("No Subject") :
00364                  strToHtml(message->subject()));
00365     headerStr += "<table>\n";
00366 
00367     // from line
00368     // the mailto: URLs can contain %3 etc., therefore usage of multiple
00369     // QString::arg is not possible
00370     if ( strategy->showHeader( "from" ) )
00371       headerStr += QString("<tr><th>%1</th>\n"
00372                "<td>")
00373                          .arg(i18n("From: "))
00374                  + KMMessage::emailAddrAsAnchor(message->from(),FALSE)
00375                  + ( !vCardName.isEmpty() ? "&nbsp;&nbsp;<a href=\"" + vCardName + "\">"
00376                                 + i18n("[vCard]") + "</a>"
00377                               : QString("") )
00378                  + ( message->headerField("Organization").isEmpty()
00379                               ? QString("")
00380                               : "&nbsp;&nbsp;("
00381                                 + strToHtml(message->headerField("Organization"))
00382                                 + ")")
00383                  + "</td></tr>\n";
00384     // to line
00385     if ( strategy->showHeader( "to" ) )
00386       headerStr.append(QString("<tr><th>%1</th>\n"
00387                    "<td>%2</td></tr>\n")
00388                             .arg(i18n("To: "))
00389                             .arg(KMMessage::emailAddrAsAnchor(message->to(),FALSE)));
00390 
00391     // cc line, if any
00392     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty())
00393       headerStr.append(QString("<tr><th>%1</th>\n"
00394                    "<td>%2</td></tr>\n")
00395                               .arg(i18n("CC: "))
00396                               .arg(KMMessage::emailAddrAsAnchor(message->cc(),FALSE)));
00397 
00398     // Bcc line, if any
00399     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty())
00400       headerStr.append(QString("<tr><th>%1</th>\n"
00401                    "<td>%2</td></tr>\n")
00402                               .arg(i18n("BCC: "))
00403                               .arg(KMMessage::emailAddrAsAnchor(message->bcc(),FALSE)));
00404 
00405     if ( strategy->showHeader( "date" ) )
00406       headerStr.append(QString("<tr><th>%1</th>\n"
00407                    "<td dir=\"%2\">%3</td></tr>\n")
00408                             .arg(i18n("Date: "))
00409                     .arg( directionOf( message->dateStr() ) )
00410                             .arg(strToHtml(dateString)));
00411     headerStr.append("</table>\n");
00412 
00413     headerStr += "</div>\n\n";
00414 
00415     return headerStr;
00416   }
00417 
00418   //
00419   // HeaderStyle abstract base:
00420   //
00421 
00422   HeaderStyle::HeaderStyle() {
00423 
00424   }
00425 
00426   HeaderStyle::~HeaderStyle() {
00427 
00428   }
00429 
00430   const HeaderStyle * HeaderStyle::create( Type type ) {
00431     switch ( type ) {
00432     case Brief:  return brief();
00433     case Plain:  return plain();
00434     case Fancy:   return fancy();
00435     }
00436     kdFatal( 5006 ) << "HeaderStyle::create(): Unknown header style ( type == "
00437             << (int)type << " ) requested!" << endl;
00438     return 0; // make compiler happy
00439   }
00440 
00441   const HeaderStyle * HeaderStyle::create( const QString & type ) {
00442     QString lowerType = type.lower();
00443     if ( lowerType == "brief" ) return brief();
00444     if ( lowerType == "plain" )  return plain();
00445     //if ( lowerType == "fancy" ) return fancy(); // not needed, see below
00446     // don't kdFatal here, b/c the strings are user-provided
00447     // (KConfig), so fail gracefully to the default:
00448     return fancy();
00449   }
00450 
00451   static const HeaderStyle * briefStyle = 0;
00452   static const HeaderStyle * plainStyle = 0;
00453   static const HeaderStyle * fancyStyle = 0;
00454 
00455   const HeaderStyle * HeaderStyle::brief() {
00456     if ( !briefStyle )
00457       briefStyle = new BriefHeaderStyle();
00458     return briefStyle;
00459   }
00460 
00461   const HeaderStyle * HeaderStyle::plain() {
00462     if ( !plainStyle )
00463       plainStyle = new PlainHeaderStyle();
00464     return plainStyle;
00465   }
00466 
00467   const HeaderStyle * HeaderStyle::fancy() {
00468     if ( !fancyStyle )
00469       fancyStyle = new FancyHeaderStyle();
00470     return fancyStyle;
00471   }
00472 
00473 } // namespace KMail
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:37:18 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003