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