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()->showCryptoIcons ) {
00303 const QPixmap *pix;
00304
00305 if ( !headers->paintInfo()->showCrypto )
00306 if ( (pix = cryptoIcon(msgBase)) ) pixmaps << *pix;
00307
00308 if ( !headers->paintInfo()->showSigned )
00309 if ( (pix = signatureIcon(msgBase)) ) pixmaps << *pix;
00310 }
00311
00312 if ( !headers->mPaintInfo.showImportant )
00313 if ( msgBase->isImportant() ) pixmaps << *KMHeaders::pixFlag;
00314
00315 if ( !headers->mPaintInfo.showTodo )
00316 if ( msgBase->isTodo() ) pixmaps << *KMHeaders::pixTodo;
00317
00318 static QPixmap mergedpix;
00319 mergedpix = pixmapMerge( pixmaps );
00320 return &mergedpix;
00321 }
00322 else if ( col == headers->paintInfo()->statusCol ) {
00323 return statusIcon(msgBase);
00324 }
00325 else if ( col == headers->paintInfo()->attachmentCol ) {
00326 if ( msgBase->attachmentState() == KMMsgHasAttachment )
00327 return KMHeaders::pixAttachment;
00328 }
00329 else if ( col == headers->paintInfo()->importantCol ) {
00330 if ( msgBase->isImportant() )
00331 return KMHeaders::pixFlag;
00332 }
00333 else if ( col == headers->paintInfo()->todoCol ) {
00334 if ( msgBase->isTodo() )
00335 return KMHeaders::pixTodo;
00336 }
00337 else if ( col == headers->paintInfo()->spamHamCol ) {
00338 if ( msgBase->isSpam() ) return KMHeaders::pixSpam;
00339 if ( msgBase->isHam() ) return KMHeaders::pixHam;
00340 }
00341 else if ( col == headers->paintInfo()->watchedIgnoredCol ) {
00342 if ( msgBase->isWatched() ) return KMHeaders::pixWatched;
00343 if ( msgBase->isIgnored() ) return KMHeaders::pixIgnored;
00344 }
00345 else if ( col == headers->paintInfo()->signedCol ) {
00346 return signatureIcon(msgBase);
00347 }
00348 else if ( col == headers->paintInfo()->cryptoCol ) {
00349 return cryptoIcon(msgBase);
00350 }
00351 return 0;
00352 }
00353
00354 void HeaderItem::paintCell( QPainter * p, const QColorGroup & cg,
00355 int column, int width, int align )
00356 {
00357 KMHeaders *headers = static_cast<KMHeaders*>(listView());
00358 if (headers->noRepaint) return;
00359 if (!headers->folder()) return;
00360 KMMsgBase *mMsgBase = headers->folder()->getMsgBase( mMsgId );
00361 if (!mMsgBase) return;
00362
00363 QColorGroup _cg( cg );
00364 QColor c = _cg.text();
00365 QColor *color = const_cast<QColor *>( &headers->paintInfo()->colFore );
00366 QFont font = p->font();
00367 int weight = font.weight();
00368
00369
00370
00371 if ( mMsgBase->isTodo() ) {
00372 color = const_cast<QColor*>( &headers->paintInfo()->colTodo );
00373 font = headers->todoFont();
00374 weight = QMAX( weight, font.weight() );
00375 }
00376 if ( mMsgBase->isUnread() ) {
00377 color = const_cast<QColor*>( &headers->paintInfo()->colUnread );
00378 font = headers->unreadFont();
00379 weight = QMAX( weight, font.weight() );
00380 }
00381 if ( mMsgBase->isNew() ) {
00382 color = const_cast<QColor*>( &headers->paintInfo()->colNew );
00383 font = headers->newFont();
00384 weight = QMAX( weight, font.weight() );
00385 }
00386
00387 if ( mMsgBase->isImportant() ) {
00388 color = const_cast<QColor*>( &headers->paintInfo()->colFlag );
00389 font = headers->importantFont();
00390 weight = QMAX( weight, font.weight() );
00391 }
00392 if ( column == headers->paintInfo()->dateCol ) {
00393 font = headers->dateFont();
00394 }
00395
00396 QColor cdisabled = KGlobalSettings::inactiveTextColor();
00397 if ( headers->isMessageCut( msgSerNum() ) ) {
00398 font.setItalic( true );
00399 color = &cdisabled;
00400 }
00401
00402
00403 _cg.setColor( QColorGroup::Text, *color );
00404 font.setWeight( weight );
00405 p->setFont( font );
00406
00407 KListViewItem::paintCell( p, _cg, column, width, align );
00408
00409 if (aboutToBeDeleted()) {
00410
00411 p->drawLine( 0, height()/2, width, height()/2);
00412 }
00413
00414
00415 _cg.setColor( QColorGroup::Text, c );
00416 }
00417
00418 QString HeaderItem::generate_key( KMHeaders *headers,
00419 KMMsgBase *msg,
00420 const KPaintInfo *paintInfo,
00421 int sortOrder )
00422 {
00423
00424
00425
00426 if (!msg) return QString::null;
00427
00428 int column = sortOrder & ((1 << 5) - 1);
00429 QString ret = QChar( (char)sortOrder );
00430 QString sortArrival = QString( "%1" ).arg( msg->getMsgSerNum(), 0, 36 );
00431 while (sortArrival.length() < 7) sortArrival = '0' + sortArrival;
00432
00433 if (column == paintInfo->dateCol) {
00434 if (paintInfo->orderOfArrival)
00435 return ret + sortArrival;
00436 else {
00437 QString d = QString::number(msg->date());
00438 while (d.length() <= 10) d = '0' + d;
00439 return ret + d + sortArrival;
00440 }
00441 } else if (column == paintInfo->senderCol) {
00442 QString tmp;
00443 if ( (headers->folder()->whoField().lower() == "to") && !headers->paintInfo()->showReceiver )
00444 tmp = msg->toStrip();
00445 else
00446 tmp = msg->fromStrip();
00447 return ret + tmp.lower() + ' ' + sortArrival;
00448 } else if (column == paintInfo->receiverCol) {
00449 QString tmp = msg->toStrip();
00450 return ret + tmp.lower() + ' ' + sortArrival;
00451 } else if (column == paintInfo->subCol) {
00452 QString tmp;
00453 tmp = ret;
00454 if (paintInfo->status) {
00455 tmp += msg->statusToSortRank() + ' ';
00456 }
00457 tmp += KMMessage::stripOffPrefixes( msg->subject().lower() ) + ' ' + sortArrival;
00458 return tmp;
00459 }
00460 else if (column == paintInfo->sizeCol) {
00461 QString len;
00462 if ( msg->parent()->folderType() == KMFolderTypeImap )
00463 {
00464 len = QString::number( msg->msgSizeServer() );
00465 } else {
00466 len = QString::number( msg->msgSize() );
00467 }
00468 while (len.length() < 9) len = '0' + len;
00469 return ret + len + sortArrival;
00470 }
00471 else if (column == paintInfo->statusCol) {
00472 QString s;
00473 if ( msg->isNew() ) s = "1";
00474 else if ( msg->isUnread() ) s = "2";
00475 else if (!msg->isForwarded() && msg->isReplied() ) s = "3";
00476 else if ( msg->isForwarded() && msg->isReplied() ) s = "4";
00477 else if ( msg->isForwarded() && !msg->isReplied() ) s = "5";
00478 else if ( msg->isRead() || msg->isOld() ) s = "6";
00479 else if ( msg->isQueued() ) s = "7";
00480 else if ( msg->isSent() ) s = "8";
00481 else if ( msg->isDeleted() ) s = "9";
00482 return ret + s + sortArrival;
00483 }
00484 else if (column == paintInfo->attachmentCol) {
00485 QString s(msg->attachmentState() == KMMsgHasAttachment ? "1" : "0");
00486 return ret + s + sortArrival;
00487 }
00488 else if (column == paintInfo->importantCol) {
00489 QString s(msg->isImportant() ? "1" : "0");
00490 return ret + s + sortArrival;
00491 }
00492 else if ( column == paintInfo->todoCol ) {
00493 QString s( msg->isTodo() ? "1": "0" );
00494 return ret + s + sortArrival;
00495 }
00496 else if (column == paintInfo->spamHamCol) {
00497 QString s((msg->isSpam() || msg->isHam()) ? "1" : "0");
00498 return ret + s + sortArrival;
00499 }
00500 else if (column == paintInfo->watchedIgnoredCol) {
00501 QString s((msg->isWatched() || msg->isIgnored()) ? "1" : "0");
00502 return ret + s + sortArrival;
00503 }
00504 else if (column == paintInfo->signedCol) {
00505 QString s;
00506 switch ( msg->signatureState() )
00507 {
00508 case KMMsgFullySigned : s = "1"; break;
00509 case KMMsgPartiallySigned : s = "2"; break;
00510 case KMMsgSignatureStateUnknown: s = "3"; break;
00511 case KMMsgSignatureProblematic : s = "4"; break;
00512 default : s = "5"; break;
00513 }
00514 return ret + s + sortArrival;
00515 }
00516 else if (column == paintInfo->cryptoCol) {
00517 QString s;
00518 switch ( msg->encryptionState() )
00519 {
00520 case KMMsgFullyEncrypted : s = "1"; break;
00521 case KMMsgPartiallyEncrypted : s = "2"; break;
00522 case KMMsgEncryptionStateUnknown: s = "3"; break;
00523 case KMMsgEncryptionProblematic : s = "4"; break;
00524 default : s = "5"; break;
00525 }
00526 return ret + s + sortArrival;
00527 }
00528 return ret + "missing key";
00529 }
00530
00531 QString HeaderItem::key( int column, bool ) const
00532 {
00533 KMHeaders *headers = static_cast<KMHeaders*>(listView());
00534 int sortOrder = column;
00535 if (headers->mPaintInfo.orderOfArrival)
00536 sortOrder |= (1 << 6);
00537 if (headers->mPaintInfo.status)
00538 sortOrder |= (1 << 5);
00539
00540
00541 if(mKey.isEmpty() || mKey[0] != (char)sortOrder) {
00542 KMHeaders *headers = static_cast<KMHeaders*>(listView());
00543 KMMsgBase *msgBase = headers->folder()->getMsgBase( mMsgId );
00544 return ((HeaderItem *)this)->mKey =
00545 generate_key( headers, msgBase, headers->paintInfo(), sortOrder );
00546 }
00547 return mKey;
00548 }
00549
00550 void HeaderItem::setTempKey( QString key ) {
00551 mKey = key;
00552 }
00553
00554 int HeaderItem::compare( QListViewItem *i, int col, bool ascending ) const
00555 {
00556 int res = 0;
00557 KMHeaders *headers = static_cast<KMHeaders*>(listView());
00558 if ( ( col == headers->paintInfo()->statusCol ) ||
00559 ( col == headers->paintInfo()->sizeCol ) ||
00560 ( col == headers->paintInfo()->attachmentCol ) ||
00561 ( col == headers->paintInfo()->importantCol ) ||
00562 ( col == headers->paintInfo()->todoCol ) ||
00563 ( col == headers->paintInfo()->spamHamCol ) ||
00564 ( col == headers->paintInfo()->signedCol ) ||
00565 ( col == headers->paintInfo()->cryptoCol ) ||
00566 ( col == headers->paintInfo()->watchedIgnoredCol ) ) {
00567 res = key( col, ascending ).compare( i->key( col, ascending ) );
00568 } else if ( col == headers->paintInfo()->dateCol ) {
00569 res = key( col, ascending ).compare( i->key( col, ascending ) );
00570 if (i->parent() && !ascending)
00571 res = -res;
00572 } else if ( col == headers->paintInfo()->subCol ||
00573 col == headers->paintInfo()->senderCol ||
00574 col == headers->paintInfo()->receiverCol ) {
00575 res = key( col, ascending ).localeAwareCompare( i->key( col, ascending ) );
00576 }
00577 return res;
00578 }
00579
00580 QListViewItem* HeaderItem::firstChildNonConst()
00581 {
00582 enforceSortOrder();
00583 return firstChild();
00584 }
00585