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