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