libkdepim

kfoldertree.cpp

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