kfoldertree.cpp
00001 // -*- c-basic-offset: 2 -*- 00002 00003 #include "kfoldertree.h" 00004 #include <tdelocale.h> 00005 #include <tdeio/global.h> 00006 #include <kiconloader.h> 00007 #include <kdebug.h> 00008 #include <kstringhandler.h> 00009 #include <tqpainter.h> 00010 #include <tqapplication.h> 00011 #include <tqheader.h> 00012 #include <tqstyle.h> 00013 00014 //----------------------------------------------------------------------------- 00015 KFolderTreeItem::KFolderTreeItem( KFolderTree *parent, const TQString & label, 00016 Protocol protocol, Type type ) 00017 : TDEListViewItem( parent, label ), mProtocol( protocol ), mType( type ), 00018 mUnread(-1), mTotal(0), mSize(0), mFolderIsCloseToQuota( false ) 00019 { 00020 } 00021 00022 //----------------------------------------------------------------------------- 00023 KFolderTreeItem::KFolderTreeItem( KFolderTreeItem *parent, 00024 const TQString & label, Protocol protocol, Type type, 00025 int unread, int total ) 00026 : TDEListViewItem( parent, label ), mProtocol( protocol ), mType( type ), 00027 mUnread( unread ), mTotal( total ), mSize(0), mFolderIsCloseToQuota( false ) 00028 { 00029 } 00030 00031 //----------------------------------------------------------------------------- 00032 int KFolderTreeItem::protocolSortingKey() const 00033 { 00034 // protocol dependant sorting order: 00035 // local < imap < news < search < other 00036 switch ( mProtocol ) { 00037 case Local: 00038 return 1; 00039 case CachedImap: 00040 case Imap: 00041 return 2; 00042 case News: 00043 return 3; 00044 case Search: 00045 return 4; 00046 default: 00047 return 42; 00048 } 00049 } 00050 00051 //----------------------------------------------------------------------------- 00052 int KFolderTreeItem::typeSortingKey() const 00053 { 00054 // type dependant sorting order: 00055 // inbox < outbox < sent-mail < trash < drafts 00056 // < calendar < contacts < notes < tasks 00057 // < normal folders 00058 switch ( mType ) { 00059 case Inbox: 00060 return 1; 00061 case Outbox: 00062 return 2; 00063 case SentMail: 00064 return 3; 00065 case Trash: 00066 return 4; 00067 case Drafts: 00068 return 5; 00069 case Templates: 00070 return 6; 00071 case Calendar: 00072 return 7; 00073 case Contacts: 00074 return 8; 00075 case Notes: 00076 return 9; 00077 case Tasks: 00078 return 10; 00079 default: 00080 return 42; 00081 } 00082 } 00083 00084 //----------------------------------------------------------------------------- 00085 int KFolderTreeItem::compare( TQListViewItem * i, int col, bool ) const 00086 { 00087 KFolderTreeItem* other = static_cast<KFolderTreeItem*>( i ); 00088 00089 if (col == 0) 00090 { 00091 // sort by folder 00092 00093 // local root-folder 00094 if ( depth() == 0 && mProtocol == NONE ) 00095 return -1; 00096 if ( other->depth() == 0 && other->protocol() == NONE ) 00097 return 1; 00098 00099 // first compare by protocol 00100 int thisKey = protocolSortingKey(); 00101 int thatKey = other->protocolSortingKey(); 00102 if ( thisKey < thatKey ) 00103 return -1; 00104 if ( thisKey > thatKey ) 00105 return 1; 00106 00107 // then compare by type 00108 thisKey = typeSortingKey(); 00109 thatKey = other->typeSortingKey(); 00110 if ( thisKey < thatKey ) 00111 return -1; 00112 if ( thisKey > thatKey ) 00113 return 1; 00114 00115 // and finally compare by name 00116 return text( 0 ).localeAwareCompare( other->text( 0 ) ); 00117 } 00118 else 00119 { 00120 // sort by unread or total-column 00121 TQ_INT64 a = 0, b = 0; 00122 if (col == static_cast<KFolderTree*>(listView())->unreadIndex()) 00123 { 00124 a = mUnread; 00125 b = other->unreadCount(); 00126 } 00127 else if (col == static_cast<KFolderTree*>(listView())->totalIndex()) 00128 { 00129 a = mTotal; 00130 b = other->totalCount(); 00131 } 00132 else if (col == static_cast<KFolderTree*>(listView())->sizeIndex()) 00133 { 00134 a = mSize; 00135 b = other->folderSize(); 00136 } 00137 00138 if ( a == b ) 00139 return 0; 00140 else 00141 return (a < b ? -1 : 1); 00142 } 00143 } 00144 00145 //----------------------------------------------------------------------------- 00146 void KFolderTreeItem::setUnreadCount( int aUnread ) 00147 { 00148 if ( aUnread < 0 ) return; 00149 00150 mUnread = aUnread; 00151 00152 TQString unread = TQString(); 00153 if (mUnread == 0) 00154 unread = "- "; 00155 else { 00156 unread.setNum(mUnread); 00157 unread += " "; 00158 } 00159 00160 setText( static_cast<KFolderTree*>(listView())->unreadIndex(), 00161 unread ); 00162 } 00163 00164 //----------------------------------------------------------------------------- 00165 void KFolderTreeItem::setTotalCount( int aTotal ) 00166 { 00167 if ( aTotal < 0 ) return; 00168 00169 mTotal = aTotal; 00170 00171 TQString total = TQString(); 00172 if (mTotal == 0) 00173 total = "- "; 00174 else { 00175 total.setNum(mTotal); 00176 total += " "; 00177 } 00178 00179 setText( static_cast<KFolderTree*>(listView())->totalIndex(), 00180 total ); 00181 } 00182 00183 //----------------------------------------------------------------------------- 00184 void KFolderTreeItem::setFolderSize( TQ_INT64 aSize ) 00185 { 00186 if ( aSize < 0 ) return; // we need to update even if nothing changed, kids ... 00187 00188 mSize = aSize; 00189 00190 TQString size; 00191 if (mType != Root) { 00192 if (mSize == 0 && (childCount() == 0 || isOpen() ) ) 00193 size = "- "; 00194 else 00195 size = TDEIO::convertSize(mSize); 00196 } 00197 if ( childCount() > 0 && !isOpen() ) { 00198 TQ_INT64 recursiveSize = recursiveFolderSize(); 00199 if ( recursiveSize != mSize ) { 00200 if ( mType != Root ) 00201 size += TQString::fromLatin1(" + %1").arg( TDEIO::convertSize( recursiveSize - mSize ) ); 00202 else 00203 size = TDEIO::convertSize( recursiveSize ); 00204 } 00205 } 00206 size += " "; 00207 00208 setText( static_cast<KFolderTree*>(listView())->sizeIndex(), size ); 00209 } 00210 00211 //----------------------------------------------------------------------------- 00212 TQ_INT64 KFolderTreeItem::recursiveFolderSize() const 00213 { 00214 TQ_INT64 size = mSize; 00215 00216 for ( TQListViewItem *item = firstChild() ; 00217 item ; item = item->nextSibling() ) 00218 { 00219 size += static_cast<KFolderTreeItem*>(item)->recursiveFolderSize(); 00220 } 00221 return size; 00222 } 00223 00224 00225 00226 //----------------------------------------------------------------------------- 00227 int KFolderTreeItem::countUnreadRecursive() 00228 { 00229 int count = (mUnread > 0) ? mUnread : 0; 00230 00231 for ( TQListViewItem *item = firstChild() ; 00232 item ; item = item->nextSibling() ) 00233 { 00234 count += static_cast<KFolderTreeItem*>(item)->countUnreadRecursive(); 00235 } 00236 00237 return count; 00238 } 00239 00240 //----------------------------------------------------------------------------- 00241 void KFolderTreeItem::paintCell( TQPainter * p, const TQColorGroup & cg, 00242 int column, int width, int align ) 00243 { 00244 KFolderTree *ft = static_cast<KFolderTree*>(listView()); 00245 00246 const int unreadRecursiveCount = countUnreadRecursive(); 00247 const int unreadCount = ( mUnread > 0 ) ? mUnread : 0; 00248 00249 00250 // use a special color for folders which are close to their quota 00251 TQColorGroup mycg = cg; 00252 if ( ( column == 0 || column == ft->sizeIndex() ) && folderIsCloseToQuota() ) 00253 { 00254 mycg.setColor( TQColorGroup::Text, ft->paintInfo().colCloseToQuota ); 00255 } 00256 00257 // use a bold-font for the folder- and the unread-columns 00258 if ( (column == 0 || column == ft->unreadIndex()) 00259 && ( unreadCount > 0 00260 || ( !isOpen() && unreadRecursiveCount > 0 ) ) ) 00261 { 00262 TQFont f = p->font(); 00263 f.setWeight(TQFont::Bold); 00264 p->setFont(f); 00265 } 00266 00267 00268 // most cells can be handled by TDEListView::paintCell, we only need to 00269 // deal with the folder column if the unread column is not shown 00270 00271 /* The below is exceedingly silly, but Ingo insists that the unread 00272 * count that is shown in parenthesis after the folder name must 00273 * be configurable in color. That means that paintCell needs to do 00274 * two painting passes which flickers. Since that flicker is not 00275 * needed when there is the unread column, special case that. */ 00276 if ( ft->isUnreadActive() || column != 0 ) { 00277 TDEListViewItem::paintCell( p, mycg, column, width, align ); 00278 } else { 00279 TQListView *lv = listView(); 00280 TQString oldText = text(column); 00281 00282 // set an empty text so that we can have our own implementation (see further down) 00283 // but still benefit from TDEListView::paintCell 00284 setText( column, "" ); 00285 00286 TDEListViewItem::paintCell( p, mycg, column, width, align ); 00287 00288 const TQPixmap *icon = pixmap( column ); 00289 int marg = lv ? lv->itemMargin() : 1; 00290 int r = marg; 00291 00292 setText( column, oldText ); 00293 if ( isSelected() ) 00294 p->setPen( mycg.highlightedText() ); 00295 else 00296 p->setPen( mycg.color( TQColorGroup::Text ) ); 00297 00298 if ( icon ) { 00299 r += icon->width() + marg; 00300 } 00301 TQString t = text( column ); 00302 if (t.isEmpty()) 00303 return; 00304 00305 // draw the unread-count if the unread-column is not active 00306 TQString unread; 00307 00308 if ( unreadCount > 0 || ( !isOpen() && unreadRecursiveCount > 0 ) ) { 00309 if ( isOpen() ) 00310 unread = " (" + TQString::number( unreadCount ) + ")"; 00311 else if ( unreadRecursiveCount == unreadCount || mType == Root ) 00312 unread = " (" + TQString::number( unreadRecursiveCount ) + ")"; 00313 else 00314 unread = " (" + TQString::number( unreadCount ) + " + " + 00315 TQString::number( unreadRecursiveCount-unreadCount ) + ")"; 00316 } 00317 00318 // check if the text needs to be squeezed 00319 TQFontMetrics fm( p->fontMetrics() ); 00320 int unreadWidth = fm.width( unread ); 00321 if ( fm.width( t ) + marg + r + unreadWidth > width ) 00322 t = squeezeFolderName( t, fm, width - marg - r - unreadWidth ); 00323 00324 TQRect br; 00325 p->drawText( r, 0, width-marg-r, height(), 00326 align | AlignVCenter, t, -1, &br ); 00327 00328 if ( !unread.isEmpty() ) { 00329 if (!isSelected()) 00330 p->setPen( ft->paintInfo().colUnread ); 00331 p->drawText( br.right(), 0, width-marg-br.right(), height(), 00332 align | AlignVCenter, unread ); 00333 } 00334 } 00335 } 00336 00337 00338 TQString KFolderTreeItem::squeezeFolderName( const TQString &text, 00339 const TQFontMetrics &fm, 00340 uint width ) const 00341 { 00342 return KStringHandler::rPixelSqueeze( text, fm, width ); 00343 } 00344 00345 bool KFolderTreeItem::folderIsCloseToQuota() const 00346 { 00347 return mFolderIsCloseToQuota; 00348 } 00349 00350 void KFolderTreeItem::setFolderIsCloseToQuota( bool v ) 00351 { 00352 if ( mFolderIsCloseToQuota != v) { 00353 mFolderIsCloseToQuota = v; 00354 repaint(); 00355 } 00356 } 00357 00358 00359 //============================================================================= 00360 00361 00362 KFolderTree::KFolderTree( TQWidget *parent, const char* name ) 00363 : TDEListView( parent, name ), mUnreadIndex(-1), mTotalIndex(-1), mSizeIndex(-1) 00364 { 00365 // GUI-options 00366 setStyleDependantFrameWidth(); 00367 setAcceptDrops(true); 00368 setDropVisualizer(false); 00369 setAllColumnsShowFocus(true); 00370 setShowSortIndicator(true); 00371 setUpdatesEnabled(true); 00372 setItemsRenameable(false); 00373 setRootIsDecorated(true); 00374 setSelectionModeExt(Extended); 00375 setAlternateBackground(TQColor()); 00376 #if KDE_IS_VERSION( 3, 3, 90 ) 00377 setShadeSortColumn ( false ); 00378 #endif 00379 setFullWidth(true); 00380 disableAutoSelection(); 00381 setColumnWidth( 0, 120 ); //reasonable default size 00382 00383 disconnect( header(), TQT_SIGNAL( sizeChange( int, int, int ) ) ); 00384 connect( header(), TQT_SIGNAL( sizeChange( int, int, int ) ), 00385 TQT_SLOT( slotSizeChanged( int, int, int ) ) ); 00386 } 00387 00388 //----------------------------------------------------------------------------- 00389 void KFolderTree::setStyleDependantFrameWidth() 00390 { 00391 // set the width of the frame to a reasonable value for the current GUI style 00392 int frameWidth; 00393 if( style().isA("KeramikStyle") ) 00394 frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth ) - 1; 00395 else 00396 frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth ); 00397 if ( frameWidth < 0 ) 00398 frameWidth = 0; 00399 if ( frameWidth != lineWidth() ) 00400 setLineWidth( frameWidth ); 00401 } 00402 00403 //----------------------------------------------------------------------------- 00404 void KFolderTree::styleChange( TQStyle& oldStyle ) 00405 { 00406 setStyleDependantFrameWidth(); 00407 TDEListView::styleChange( oldStyle ); 00408 } 00409 00410 //----------------------------------------------------------------------------- 00411 void KFolderTree::drawContentsOffset( TQPainter * p, int ox, int oy, 00412 int cx, int cy, int cw, int ch ) 00413 { 00414 bool oldUpdatesEnabled = isUpdatesEnabled(); 00415 setUpdatesEnabled(false); 00416 TDEListView::drawContentsOffset( p, ox, oy, cx, cy, cw, ch ); 00417 setUpdatesEnabled(oldUpdatesEnabled); 00418 } 00419 00420 //----------------------------------------------------------------------------- 00421 void KFolderTree::contentsMousePressEvent( TQMouseEvent *e ) 00422 { 00423 setSelectionModeExt(Single); 00424 TDEListView::contentsMousePressEvent(e); 00425 } 00426 00427 //----------------------------------------------------------------------------- 00428 void KFolderTree::contentsMouseReleaseEvent( TQMouseEvent *e ) 00429 { 00430 TDEListView::contentsMouseReleaseEvent(e); 00431 setSelectionModeExt(Extended); 00432 } 00433 00434 //----------------------------------------------------------------------------- 00435 void KFolderTree::addAcceptableDropMimetype( const char *mimeType, bool outsideOk ) 00436 { 00437 int oldSize = mAcceptableDropMimetypes.size(); 00438 mAcceptableDropMimetypes.resize(oldSize+1); 00439 mAcceptOutside.resize(oldSize+1); 00440 00441 mAcceptableDropMimetypes.at(oldSize) = mimeType; 00442 mAcceptOutside.setBit(oldSize, outsideOk); 00443 } 00444 00445 //----------------------------------------------------------------------------- 00446 bool KFolderTree::acceptDrag( TQDropEvent* event ) const 00447 { 00448 TQListViewItem* item = itemAt(contentsToViewport(event->pos())); 00449 00450 for (uint i = 0; i < mAcceptableDropMimetypes.size(); i++) 00451 { 00452 if (event->provides(mAcceptableDropMimetypes[i])) 00453 { 00454 if (item) 00455 return (static_cast<KFolderTreeItem*>(item))->acceptDrag(event); 00456 else 00457 return mAcceptOutside[i]; 00458 } 00459 } 00460 return false; 00461 } 00462 00463 //----------------------------------------------------------------------------- 00464 void KFolderTree::addUnreadColumn( const TQString & name, int width ) 00465 { 00466 mUnreadIndex = addColumn( name, width ); 00467 setColumnAlignment( mUnreadIndex, tqApp->reverseLayout() ? TQt::AlignLeft : TQt::AlignRight ); 00468 header()->adjustHeaderSize(); 00469 } 00470 00471 //----------------------------------------------------------------------------- 00472 void KFolderTree::addTotalColumn( const TQString & name, int width ) 00473 { 00474 mTotalIndex = addColumn( name, width ); 00475 setColumnAlignment( mTotalIndex, tqApp->reverseLayout() ? TQt::AlignLeft : TQt::AlignRight ); 00476 header()->adjustHeaderSize(); 00477 } 00478 00479 //----------------------------------------------------------------------------- 00480 void KFolderTree::removeUnreadColumn() 00481 { 00482 if ( !isUnreadActive() ) return; 00483 removeColumn( mUnreadIndex ); 00484 if ( isTotalActive() && mTotalIndex > mUnreadIndex ) 00485 mTotalIndex--; 00486 if ( isSizeActive() && mSizeIndex > mUnreadIndex ) 00487 mSizeIndex--; 00488 00489 mUnreadIndex = -1; 00490 header()->adjustHeaderSize(); 00491 } 00492 00493 //----------------------------------------------------------------------------- 00494 void KFolderTree::removeTotalColumn() 00495 { 00496 if ( !isTotalActive() ) return; 00497 removeColumn( mTotalIndex ); 00498 if ( isUnreadActive() && mTotalIndex < mUnreadIndex ) 00499 mUnreadIndex--; 00500 if ( isSizeActive() && mTotalIndex < mSizeIndex ) 00501 mSizeIndex--; 00502 mTotalIndex = -1; 00503 header()->adjustHeaderSize(); 00504 } 00505 00506 //----------------------------------------------------------------------------- 00507 void KFolderTree::addSizeColumn( const TQString & name, int width ) 00508 { 00509 mSizeIndex = addColumn( name, width ); 00510 setColumnAlignment( mSizeIndex, tqApp->reverseLayout() ? TQt::AlignLeft : TQt::AlignRight ); 00511 header()->adjustHeaderSize(); 00512 } 00513 00514 //----------------------------------------------------------------------------- 00515 void KFolderTree::removeSizeColumn() 00516 { 00517 if ( !isSizeActive() ) return; 00518 removeColumn( mSizeIndex ); 00519 if ( isUnreadActive() && mSizeIndex < mUnreadIndex ) 00520 mUnreadIndex--; 00521 if ( isTotalActive() && mSizeIndex < mTotalIndex ) 00522 mTotalIndex--; 00523 mSizeIndex = -1; 00524 header()->adjustHeaderSize(); 00525 } 00526 00527 00528 //----------------------------------------------------------------------------- 00529 void KFolderTree::setFullWidth( bool fullWidth ) 00530 { 00531 if (fullWidth) 00532 header()->setStretchEnabled( true, 0 ); 00533 } 00534 00535 //----------------------------------------------------------------------------- 00536 void KFolderTree::slotSizeChanged( int section, int, int newSize ) 00537 { 00538 viewport()->repaint( 00539 header()->sectionPos(section), 0, newSize, visibleHeight(), false ); 00540 } 00541 00542 #include "kfoldertree.moc"