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