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 #include "headeritem.h"
00030
00031 #include "kmheaders.h"
00032 #include "kmfolder.h"
00033 #include "kmmessagetag.h"
00034 #include "kmkernel.h"
00035
00036 #include <klocale.h>
00037 #include <kio/netaccess.h>
00038
00039 #include <QApplication>
00040 #include <QBitmap>
00041 #include <QList>
00042 #include <QPainter>
00043 #include <QPixmap>
00044 #include <QRegExp>
00045
00046 using namespace KMail;
00047
00048
00049 HeaderItem::HeaderItem( Q3ListView* parent, int msgId, const QString& key )
00050 : K3ListViewItem( parent ),
00051 mMsgId( msgId ),
00052 mKey( key ),
00053 mAboutToBeDeleted( false ),
00054 mSortCacheItem( 0 )
00055 {
00056 irefresh();
00057 }
00058
00059
00060 HeaderItem::HeaderItem( Q3ListViewItem* parent, int msgId, const QString& key )
00061 : K3ListViewItem( parent ),
00062 mMsgId( msgId ),
00063 mKey( key ),
00064 mAboutToBeDeleted( false ),
00065 mSortCacheItem( 0 )
00066 {
00067 irefresh();
00068 }
00069
00070 HeaderItem::~HeaderItem ()
00071 {
00072 delete mSortCacheItem;
00073 }
00074
00075
00076 void HeaderItem::setMsgId( int aMsgId )
00077 {
00078 mMsgId = aMsgId;
00079 }
00080
00081
00082
00083
00084 void HeaderItem::irefresh()
00085 {
00086 KMHeaders *headers = static_cast<KMHeaders*>(listView());
00087 NestingPolicy threadingPolicy = headers->getNestingPolicy();
00088 if ((threadingPolicy == AlwaysOpen) ||
00089 (threadingPolicy == DefaultOpen)) {
00090
00091 setOpen(true);
00092 return;
00093
00094 }
00095 if (threadingPolicy == DefaultClosed)
00096 return;
00097
00098
00099 if (parent() && parent()->isOpen()) {
00100 setOpen(true);
00101 return;
00102 }
00103
00104 KMMsgBase *mMsgBase = headers->folder()->getMsgBase( mMsgId );
00105 mSerNum = mMsgBase->getMsgSerNum();
00106 MessageStatus status = mMsgBase->status();
00107 if ( status.isNew() || status.isUnread() || status.isImportant()
00108 || status.isToAct() || status.isWatched() ) {
00109 setOpen(true);
00110 HeaderItem * topOfThread = this;
00111 while(topOfThread->parent())
00112 topOfThread = (HeaderItem*)topOfThread->parent();
00113 topOfThread->setOpenRecursive(true);
00114 }
00115 }
00116
00117
00118 int HeaderItem::msgId() const
00119 {
00120 return mMsgId;
00121 }
00122
00123
00124 quint32 HeaderItem::msgSerNum() const
00125 {
00126 return mSerNum;
00127 }
00128
00129
00130
00131
00132 void HeaderItem::setOpenRecursive( bool open )
00133 {
00134 if (open){
00135 Q3ListViewItem * lvchild;
00136 lvchild = firstChild();
00137 while (lvchild){
00138 ((HeaderItem*)lvchild)->setOpenRecursive( true );
00139 lvchild = lvchild->nextSibling();
00140 }
00141 setOpen( true );
00142 } else {
00143 setOpen( false );
00144 }
00145 }
00146
00147 QString HeaderItem::text( int col) const
00148 {
00149 KMHeaders *headers = static_cast<KMHeaders*>(listView());
00150 KMMsgBase *mMsgBase = headers->folder()->getMsgBase( mMsgId );
00151 QString tmp;
00152
00153 if ( !mMsgBase )
00154 return QString();
00155
00156 if ( col == headers->paintInfo()->senderCol ) {
00157 if ( (headers->folder()->whoField().toLower() == "to") && !headers->paintInfo()->showReceiver )
00158 tmp = mMsgBase->toStrip();
00159 else
00160 tmp = mMsgBase->fromStrip();
00161 if (tmp.isEmpty())
00162 tmp = i18nc("Unknown mail header.","Unknown");
00163 else
00164 tmp = tmp.simplified();
00165
00166 } else if ( col == headers->paintInfo()->receiverCol ) {
00167 tmp = mMsgBase->toStrip();
00168 if (tmp.isEmpty())
00169 tmp = i18nc("Unknown mail header.","Unknown");
00170 else
00171 tmp = tmp.simplified();
00172
00173 } else if(col == headers->paintInfo()->subCol) {
00174 tmp = mMsgBase->subject();
00175 if (tmp.isEmpty())
00176 tmp = i18n("No Subject");
00177 else
00178 tmp.remove(QRegExp("[\r\n]"));
00179
00180 } else if(col == headers->paintInfo()->dateCol) {
00181 tmp = headers->mDate.dateString( mMsgBase->date() );
00182 } else if(col == headers->paintInfo()->sizeCol
00183 && headers->paintInfo()->showSize) {
00184 if ( mMsgBase->parent()->folderType() == KMFolderTypeImap ) {
00185 tmp = KIO::convertSize( mMsgBase->msgSizeServer() );
00186 } else {
00187 tmp = KIO::convertSize( mMsgBase->msgSize() );
00188 }
00189 }
00190 return tmp;
00191 }
00192
00193 void HeaderItem::setup()
00194 {
00195 widthChanged();
00196 const int ph = KMHeaders::pixNew->height();
00197 Q3ListView *v = listView();
00198 int h = qMax( v->fontMetrics().height(), ph ) + 2*v->itemMargin();
00199 h = qMax( h, QApplication::globalStrut().height());
00200 if ( h % 2 > 0 )
00201 h++;
00202 setHeight( h );
00203 }
00204
00205 QPixmap HeaderItem::pixmapMerge( PixmapList pixmaps ) const
00206 {
00207
00208 int width = 0;
00209 int height = 0;
00210 for ( PixmapList::ConstIterator it = pixmaps.begin();
00211 it != pixmaps.end(); ++it ) {
00212 width += (*it).width();
00213 height = qMax( height, (*it).height() );
00214 }
00215
00216 QPixmap res( width, height );
00217 res.fill( Qt::transparent );
00218 QPainter resultPainter( &res );
00219
00220
00221 int x = 0;
00222 for ( PixmapList::ConstIterator it = pixmaps.begin();
00223 it != pixmaps.end(); ++it ) {
00224 resultPainter.drawPixmap( x, ( height - (*it).height() ) / 2, *it );
00225 x += (*it).width();
00226 }
00227
00228 resultPainter.end();
00229 return res;
00230 }
00231
00232 const QPixmap *HeaderItem::cryptoIcon(KMMsgBase *msgBase) const
00233 {
00234 switch ( msgBase->encryptionState() )
00235 {
00236 case KMMsgFullyEncrypted : return KMHeaders::pixFullyEncrypted;
00237 case KMMsgPartiallyEncrypted : return KMHeaders::pixPartiallyEncrypted;
00238 case KMMsgEncryptionStateUnknown: return KMHeaders::pixUndefinedEncrypted;
00239 default : return 0;
00240 }
00241 }
00242
00243 const QPixmap *HeaderItem::signatureIcon(KMMsgBase *msgBase) const
00244 {
00245 switch ( msgBase->signatureState() )
00246 {
00247 case KMMsgFullySigned : return KMHeaders::pixFullySigned;
00248 case KMMsgPartiallySigned : return KMHeaders::pixPartiallySigned;
00249 case KMMsgSignatureStateUnknown: return KMHeaders::pixUndefinedSigned;
00250 default : return 0;
00251 }
00252 }
00253
00254 const QPixmap *HeaderItem::statusIcon(KMMsgBase *msgBase) const
00255 {
00256
00257 MessageStatus status = msgBase->status();
00258 if ( status.isForwarded() && !status.isReplied() ) return KMHeaders::pixReadFwd;
00259 if ( !status.isForwarded() && status.isReplied() ) return KMHeaders::pixReadReplied;
00260 if ( status.isForwarded() && status.isReplied() ) return KMHeaders::pixReadFwdReplied;
00261
00262
00263 if ( status.isQueued() ) return KMHeaders::pixQueued;
00264 if ( status.isSent() ) return KMHeaders::pixSent;
00265
00266 if ( status.isNew() ) return KMHeaders::pixNew;
00267 if ( status.isRead() || status.isOld() ) return KMHeaders::pixRead;
00268 if ( status.isUnread() ) return KMHeaders::pixUns;
00269 if ( status.isDeleted() ) return KMHeaders::pixDel;
00270
00271 return 0;
00272 }
00273
00274 K_GLOBAL_STATIC( QPixmap, s_mergedpix )
00275
00276 const QPixmap *HeaderItem::pixmap(int col) const
00277 {
00278 KMHeaders *headers = static_cast<KMHeaders*>(listView());
00279 KMMsgBase *msgBase = headers->folder()->getMsgBase( mMsgId );
00280 MessageStatus status = msgBase->status();
00281
00282 if ( col == headers->paintInfo()->subCol ) {
00283
00284 PixmapList pixmaps;
00285
00286 if ( !headers->mPaintInfo.showSpamHam ) {
00287
00288 if ( status.isSpam() ) pixmaps << *KMHeaders::pixSpam;
00289 if ( status.isHam() ) pixmaps << *KMHeaders::pixHam;
00290 }
00291
00292 if ( !headers->mPaintInfo.showWatchedIgnored ) {
00293 if ( status.isIgnored() ) pixmaps << *KMHeaders::pixIgnored;
00294 if ( status.isWatched() ) pixmaps << *KMHeaders::pixWatched;
00295 }
00296
00297 if ( !headers->mPaintInfo.showStatus ) {
00298 const QPixmap *pix = statusIcon(msgBase);
00299 if ( pix ) pixmaps << *pix;
00300 }
00301
00302
00303 if ( headers->paintInfo()->showAttachmentIcon &&
00304 !headers->paintInfo()->showAttachment &&
00305 msgBase->attachmentState() == KMMsgHasAttachment )
00306 pixmaps << *KMHeaders::pixAttachment;
00307
00308
00309 if ( headers->paintInfo()->showCryptoIcons ) {
00310 const QPixmap *pix;
00311
00312 if ( !headers->paintInfo()->showCrypto )
00313 if ( (pix = cryptoIcon(msgBase)) ) pixmaps << *pix;
00314
00315 if ( !headers->paintInfo()->showSigned )
00316 if ( (pix = signatureIcon(msgBase)) ) pixmaps << *pix;
00317 }
00318
00319 if ( !headers->mPaintInfo.showImportant )
00320 if ( status.isImportant() ) pixmaps << *KMHeaders::pixFlag;
00321
00322 if ( !headers->mPaintInfo.showToAct )
00323 if ( status.isToAct() ) pixmaps << *KMHeaders::pixToAct;
00324
00325 if ( !pixmaps.isEmpty() ) {
00326 *s_mergedpix = pixmapMerge( pixmaps );
00327 return s_mergedpix;
00328 }
00329 else
00330 return 0;
00331 }
00332 else if ( col == headers->paintInfo()->statusCol ) {
00333 return statusIcon(msgBase);
00334 }
00335 else if ( col == headers->paintInfo()->attachmentCol ) {
00336 if ( msgBase->attachmentState() == KMMsgHasAttachment )
00337 return KMHeaders::pixAttachment;
00338 }
00339 else if ( col == headers->paintInfo()->importantCol ) {
00340 if ( status.isImportant() )
00341 return KMHeaders::pixFlag;
00342 }
00343 else if ( col == headers->paintInfo()->toActCol ) {
00344 if ( status.isToAct() )
00345 return KMHeaders::pixToAct;
00346 }
00347 else if ( col == headers->paintInfo()->spamHamCol ) {
00348 if ( status.isSpam() ) return KMHeaders::pixSpam;
00349 if ( status.isHam() ) return KMHeaders::pixHam;
00350 }
00351 else if ( col == headers->paintInfo()->watchedIgnoredCol ) {
00352 if ( status.isWatched() ) return KMHeaders::pixWatched;
00353 if ( status.isIgnored() ) return KMHeaders::pixIgnored;
00354 }
00355 else if ( col == headers->paintInfo()->signedCol ) {
00356 return signatureIcon(msgBase);
00357 }
00358 else if ( col == headers->paintInfo()->cryptoCol ) {
00359 return cryptoIcon(msgBase);
00360 }
00361 return 0;
00362 }
00363
00364 void HeaderItem::paintCell( QPainter * p, const QColorGroup & cg,
00365 int column, int width, int align )
00366 {
00367 KMHeaders *headers = static_cast<KMHeaders*>(listView());
00368 if (headers->noRepaint) return;
00369 if (!headers->folder()) return;
00370 KMMsgBase *mMsgBase = headers->folder()->getMsgBase( mMsgId );
00371 if (!mMsgBase) return;
00372 MessageStatus status = mMsgBase->status();
00373
00374 QColorGroup _cg( cg );
00375 QColor originalColor = _cg.color( QPalette::Text );
00376 QColor color = KColorScheme( QPalette::Active ).foreground().color();
00377 QFont font = p->font();
00378 int weight = font.weight();
00379
00380 QColor tmp_fgcolor;
00381 QFont tmp_font;
00382 KMMessageTagList* tmp_taglist = mMsgBase->tagList();
00383 if ( ( tmp_taglist ) && ( ! tmp_taglist->isEmpty() ) ) {
00384
00385
00386 const KMMessageTagDescription* firstTag = kmkernel->msgTagMgr()->find(
00387 (*tmp_taglist)[0] );
00388 if ( firstTag ) {
00389 tmp_fgcolor = firstTag->textColor();
00390 if ( tmp_fgcolor.isValid() ) {
00391 color = tmp_fgcolor;
00392 }
00393 QFont tmp_font = firstTag->textFont();
00394 if ( tmp_font != QFont() ) {
00395 font = tmp_font;
00396 weight = qMax( weight, font.weight() );
00397 }
00398 }
00399 }
00400
00401
00402
00403 if ( status.isToAct() ) {
00404 color = headers->paintInfo()->colToAct;
00405 font = headers->toActFont();
00406 weight = qMax( weight, font.weight() );
00407 }
00408 if ( status.isUnread() ) {
00409 color = headers->paintInfo()->colUnread;
00410 font = headers->unreadFont();
00411 weight = qMax( weight, font.weight() );
00412 }
00413 if ( status.isNew() ) {
00414 color = headers->paintInfo()->colNew;
00415 font = headers->newFont();
00416 weight = qMax( weight, font.weight() );
00417 }
00418
00419 if ( status.isImportant() ) {
00420 color = headers->paintInfo()->colFlag;
00421 font = headers->importantFont();
00422 weight = qMax( weight, font.weight() );
00423 }
00424 if ( column == headers->paintInfo()->dateCol ) {
00425 font = headers->dateFont();
00426 }
00427
00428 QColor cdisabled = KGlobalSettings::inactiveTextColor();
00429 if ( headers->isMessageCut( msgSerNum() ) ) {
00430 color = cdisabled;
00431 }
00432
00433
00434 _cg.setColor( QPalette::Text, color );
00435 font.setWeight( weight );
00436 p->setFont( font );
00437
00438 K3ListViewItem::paintCell( p, _cg, column, width, align );
00439
00440 if (aboutToBeDeleted()) {
00441
00442 p->drawLine( 0, height()/2, width, height()/2);
00443 }
00444
00445
00446 _cg.setColor( QPalette::Text, originalColor );
00447 }
00448
00449 QString HeaderItem::generate_key( KMHeaders *headers,
00450 KMMsgBase *msg,
00451 const KPaintInfo *paintInfo,
00452 int sortOrder )
00453 {
00454
00455
00456
00457 if (!msg) return QString();
00458 MessageStatus status = msg->status();
00459
00460 int column = sortOrder & ((1 << 5) - 1);
00461 QString ret = QString( (char)sortOrder );
00462 QString sortArrival = QString( "%1" ).arg( msg->getMsgSerNum(), 0, 36 );
00463 while (sortArrival.length() < 7) sortArrival = '0' + sortArrival;
00464
00465 if (column == paintInfo->dateCol) {
00466 if (paintInfo->orderOfArrival)
00467 return ret + sortArrival;
00468 else {
00469 QString d = QString::number(msg->date());
00470 while (d.length() <= 10) d = '0' + d;
00471 return ret + d + sortArrival;
00472 }
00473 } else if (column == paintInfo->senderCol) {
00474 QString tmp;
00475 if ( (headers->folder()->whoField().toLower() == "to") && !headers->paintInfo()->showReceiver )
00476 tmp = msg->toStrip();
00477 else
00478 tmp = msg->fromStrip();
00479 return ret + tmp.toLower() + ' ' + sortArrival;
00480 } else if (column == paintInfo->receiverCol) {
00481 QString tmp = msg->toStrip();
00482 return ret + tmp.toLower() + ' ' + sortArrival;
00483 } else if (column == paintInfo->subCol) {
00484 QString tmp;
00485 tmp = ret;
00486 if (paintInfo->status) {
00487 tmp += msg->status().getSortRank() + ' ';
00488 }
00489 tmp += KMMessage::stripOffPrefixes( msg->subject().toLower() ) + ' ' + sortArrival;
00490 return tmp;
00491 }
00492 else if (column == paintInfo->sizeCol) {
00493 QString len;
00494 if ( msg->parent()->folderType() == KMFolderTypeImap )
00495 {
00496 len = QString::number( msg->msgSizeServer() );
00497 } else {
00498 len = QString::number( msg->msgSize() );
00499 }
00500 while (len.length() < 9) len = '0' + len;
00501 return ret + len + sortArrival;
00502 }
00503 else if (column == paintInfo->statusCol) {
00504 QString s;
00505 if ( status.isNew() ) s = "1";
00506 else if ( status.isUnread() ) s = "2";
00507 else if (!status.isForwarded() && status.isReplied() ) s = "3";
00508 else if ( status.isForwarded() && status.isReplied() ) s = "4";
00509 else if ( status.isForwarded() && !status.isReplied() ) s = "5";
00510 else if ( status.isRead() || status.isOld() ) s = "6";
00511 else if ( status.isQueued() ) s = "7";
00512 else if ( status.isSent() ) s = "8";
00513 else if ( status.isDeleted() ) s = "9";
00514 return ret + s + sortArrival;
00515 }
00516 else if (column == paintInfo->attachmentCol) {
00517 QString s(msg->attachmentState() == KMMsgHasAttachment ? "1" : "0");
00518 return ret + s + sortArrival;
00519 }
00520 else if (column == paintInfo->importantCol) {
00521 QString s( status.isImportant() ? "1" : "0" );
00522 return ret + s + sortArrival;
00523 }
00524 else if ( column == paintInfo->toActCol ) {
00525 QString s( status.isToAct() ? "1": "0" );
00526 return ret + s + sortArrival;
00527 }
00528 else if (column == paintInfo->spamHamCol) {
00529 QString s(( status.isSpam() || status.isHam() ) ? "1" : "0" );
00530 return ret + s + sortArrival;
00531 }
00532 else if (column == paintInfo->watchedIgnoredCol) {
00533 QString s(( status.isWatched() || status.isIgnored() ) ? "1" : "0" );
00534 return ret + s + sortArrival;
00535 }
00536 else if (column == paintInfo->signedCol) {
00537 QString s;
00538 switch ( msg->signatureState() )
00539 {
00540 case KMMsgFullySigned : s = "1"; break;
00541 case KMMsgPartiallySigned : s = "2"; break;
00542 case KMMsgSignatureStateUnknown: s = "3"; break;
00543 case KMMsgSignatureProblematic : s = "4"; break;
00544 default : s = "5"; break;
00545 }
00546 return ret + s + sortArrival;
00547 }
00548 else if (column == paintInfo->cryptoCol) {
00549 QString s;
00550 switch ( msg->encryptionState() )
00551 {
00552 case KMMsgFullyEncrypted : s = "1"; break;
00553 case KMMsgPartiallyEncrypted : s = "2"; break;
00554 case KMMsgEncryptionStateUnknown: s = "3"; break;
00555 case KMMsgEncryptionProblematic : s = "4"; break;
00556 default : s = "5"; break;
00557 }
00558 return ret + s + sortArrival;
00559 }
00560 return ret + "missing key";
00561 }
00562
00563 QString HeaderItem::key( int column, bool ) const
00564 {
00565 KMHeaders *headers = static_cast<KMHeaders*>(listView());
00566 int sortOrder = column;
00567 if (headers->mPaintInfo.orderOfArrival)
00568 sortOrder |= (1 << 6);
00569 if (headers->mPaintInfo.status)
00570 sortOrder |= (1 << 5);
00571
00572
00573 if(mKey.isEmpty() || mKey[0] != (char)sortOrder) {
00574 KMHeaders *headers = static_cast<KMHeaders*>(listView());
00575 KMMsgBase *msgBase = headers->folder()->getMsgBase( mMsgId );
00576 return ((HeaderItem *)this)->mKey =
00577 generate_key( headers, msgBase, headers->paintInfo(), sortOrder );
00578 }
00579 return mKey;
00580 }
00581
00582 void HeaderItem::setTempKey( const QString &key ) {
00583 mKey = key;
00584 }
00585
00586 int HeaderItem::compare( Q3ListViewItem *i, int col, bool ascending ) const
00587 {
00588 int res = 0;
00589 KMHeaders *headers = static_cast<KMHeaders*>(listView());
00590 if ( ( col == headers->paintInfo()->statusCol ) ||
00591 ( col == headers->paintInfo()->sizeCol ) ||
00592 ( col == headers->paintInfo()->attachmentCol ) ||
00593 ( col == headers->paintInfo()->importantCol ) ||
00594 ( col == headers->paintInfo()->toActCol ) ||
00595 ( col == headers->paintInfo()->spamHamCol ) ||
00596 ( col == headers->paintInfo()->signedCol ) ||
00597 ( col == headers->paintInfo()->cryptoCol ) ||
00598 ( col == headers->paintInfo()->watchedIgnoredCol ) ) {
00599 res = key( col, ascending ).compare( i->key( col, ascending ) );
00600 } else if ( col == headers->paintInfo()->dateCol ) {
00601 res = key( col, ascending ).compare( i->key( col, ascending ) );
00602 if (i->parent() && !ascending)
00603 res = -res;
00604 } else if ( col == headers->paintInfo()->subCol ||
00605 col == headers->paintInfo()->senderCol ||
00606 col == headers->paintInfo()->receiverCol ) {
00607 res = key( col, ascending ).localeAwareCompare( i->key( col, ascending ) );
00608 }
00609 return res;
00610 }
00611
00612 Q3ListViewItem* HeaderItem::firstChildNonConst()
00613 {
00614 enforceSortOrder();
00615 return firstChild();
00616 }
00617