libtdepim

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"