kmail Library API Documentation

kmfoldertree.cpp

00001 // kmfoldertree.cpp
00002 #ifdef HAVE_CONFIG_H
00003 #include <config.h>
00004 #endif
00005 
00006 #include "kmfoldertree.h"
00007 
00008 #include "kmfoldermgr.h"
00009 #include "kmfolderimap.h"
00010 #include "kmfoldercachedimap.h"
00011 #include "kmfolderdia.h"
00012 #include "kmcomposewin.h"
00013 #include "kmmainwidget.h"
00014 #include "kmailicalifaceimpl.h"
00015 #include "kmacctmgr.h"
00016 #include "kmkernel.h"
00017 #include "globalsettings.h"
00018 #include "kmcommands.h"
00019 
00020 #include <maillistdrag.h>
00021 using namespace KPIM;
00022 
00023 #include <kapplication.h>
00024 #include <kglobalsettings.h>
00025 #include <kiconloader.h>
00026 #include <kmessagebox.h>
00027 #include <kconfig.h>
00028 #include <kdebug.h>
00029 
00030 #include <qpainter.h>
00031 #include <qcursor.h>
00032 #include <qregexp.h>
00033 
00034 #include <unistd.h>
00035 #include <assert.h>
00036 
00037 #include <X11/Xlib.h>
00038 #include <fixx11h.h>
00039 
00040 //=============================================================================
00041 
00042 KMFolderTreeItem::KMFolderTreeItem( KFolderTree *parent, const QString & name,
00043                                     KFolderTreeItem::Protocol protocol )
00044   : QObject( parent, name.latin1() ),
00045     KFolderTreeItem( parent, name, protocol, Root ),
00046     mFolder( 0 ), mNeedsRepaint( true )
00047 {
00048   init();
00049   setPixmap( 0, normalIcon() );
00050 }
00051 
00052 //-----------------------------------------------------------------------------
00053 KMFolderTreeItem::KMFolderTreeItem( KFolderTree *parent, const QString & name,
00054                     KMFolder* folder )
00055   : QObject( parent, name.latin1() ),
00056     KFolderTreeItem( parent, name ),
00057     mFolder( folder ), mNeedsRepaint( true )
00058 {
00059   init();
00060   setPixmap( 0, normalIcon() );
00061 }
00062 
00063 //-----------------------------------------------------------------------------
00064 KMFolderTreeItem::KMFolderTreeItem( KFolderTreeItem *parent, const QString & name,
00065                     KMFolder* folder )
00066   : QObject( 0, name.latin1() ),
00067     KFolderTreeItem( parent, name ),
00068     mFolder( folder ), mNeedsRepaint( true )
00069 {
00070   init();
00071   setPixmap( 0, normalIcon() );
00072 }
00073 
00074 KMFolderTreeItem::~KMFolderTreeItem() 
00075 {
00076 }
00077 
00078 static KFolderTreeItem::Protocol protocolFor( KMFolderType t ) {
00079   switch ( t ) {
00080   case KMFolderTypeImap:
00081     return KFolderTreeItem::Imap;
00082   case KMFolderTypeCachedImap:
00083     return KFolderTreeItem::CachedImap;
00084   case KMFolderTypeMbox:
00085   case KMFolderTypeMaildir:
00086     return KFolderTreeItem::Local;
00087   case KMFolderTypeSearch:
00088     return KFolderTreeItem::Search;
00089   default:
00090     return KFolderTreeItem::NONE;
00091   }
00092 }
00093 
00094 QPixmap KMFolderTreeItem::normalIcon(int size) const
00095 {
00096   QString icon;
00097   if ( (!mFolder && type() == Root) || depth() == 0 ) {
00098     switch ( protocol() ) {
00099       case KFolderTreeItem::Imap:
00100       case KFolderTreeItem::CachedImap:
00101       case KFolderTreeItem::News:
00102         icon = "server"; break;
00103       case KFolderTreeItem::Search:
00104         icon = "viewmag";break;
00105       default:
00106         icon = "folder";break;
00107     }
00108   } else {
00109     // special folders
00110     switch ( type() ) {
00111       case Inbox: icon = "folder_inbox"; break;
00112       case Outbox: icon = "folder_outbox"; break;
00113       case SentMail: icon = "folder_sent_mail"; break;
00114       case Trash: icon = "trashcan_empty"; break;
00115       case Drafts: icon = "edit";break;
00116       default: icon = kmkernel->iCalIface().folderPixmap( type() ); break;
00117     }
00118     // non-root search folders
00119     if ( protocol() == KMFolderTreeItem::Search) {
00120       icon = "mail_find";
00121     }
00122   }
00123 
00124   if ( icon.isEmpty() )
00125     icon = "folder";
00126 
00127   if (mFolder && mFolder->useCustomIcons() ) {
00128     icon = mFolder->normalIconPath();
00129   }
00130   KIconLoader * il = KGlobal::instance()->iconLoader();
00131   QPixmap pm = il->loadIcon( icon, KIcon::Small, size,
00132                              KIcon::DefaultState, 0, true );
00133   if ( pm.isNull() ) {
00134       pm = il->loadIcon( mFolder->normalIconPath(), KIcon::Small, size,
00135                          KIcon::DefaultState, 0, true );
00136   }
00137 
00138   return pm;
00139 }
00140 
00141 QPixmap KMFolderTreeItem::unreadIcon(int size) const
00142 {
00143   QPixmap pm;
00144 
00145   if ( !mFolder || depth() == 0 || mFolder->isSystemFolder()
00146     || kmkernel->folderIsTrash( mFolder )
00147     || kmkernel->folderIsDraftOrOutbox( mFolder ) )
00148     pm = normalIcon( size );
00149 
00150   KIconLoader * il = KGlobal::instance()->iconLoader();
00151   if ( mFolder->useCustomIcons() ) {
00152     pm = il->loadIcon( mFolder->unreadIconPath(), KIcon::Small, size,
00153                        KIcon::DefaultState, 0, true );
00154     if ( pm.isNull() )
00155       pm = il->loadIcon( mFolder->normalIconPath(), KIcon::Small, size,
00156                          KIcon::DefaultState, 0, true );
00157   }
00158   if ( pm.isNull() )
00159     pm = il->loadIcon( "folder_open", KIcon::Small, size,
00160                        KIcon::DefaultState, 0, true );
00161 
00162   return pm;
00163 }
00164 
00165 void KMFolderTreeItem::init()
00166 {
00167   if ( !mFolder )
00168     return;
00169 
00170   setProtocol( protocolFor( mFolder->folderType() ) );
00171 
00172   if ( depth() == 0 )
00173     setType(Root);
00174   else {
00175     if ( mFolder == kmkernel->inboxFolder() )
00176       setType( Inbox );
00177     else if ( kmkernel->folderIsDraftOrOutbox( mFolder ) ) {
00178       if ( mFolder == kmkernel->outboxFolder() )
00179         setType( Outbox );
00180       else
00181         setType( Drafts );
00182     }
00183     else if ( kmkernel->folderIsSentMailFolder( mFolder ) )
00184       setType( SentMail );
00185     else if ( kmkernel->folderIsTrash( mFolder ) )
00186       setType( Trash );
00187     else if( kmkernel->iCalIface().isResourceImapFolder(mFolder) )
00188       setType( kmkernel->iCalIface().folderType(mFolder) );
00189     // System folders on dimap or imap which are not resource folders are
00190     // inboxes. Urgs.
00191     if ( mFolder->isSystemFolder() &&
00192         !kmkernel->iCalIface().isResourceImapFolder( mFolder) &&
00193          ( mFolder->folderType() == KMFolderTypeImap
00194         || mFolder->folderType() == KMFolderTypeCachedImap ) )
00195       setType( Inbox );
00196   }
00197   if ( !mFolder->isSystemFolder() )
00198     setRenameEnabled( 0, false );
00199 
00200   KMFolderTree* tree = static_cast<KMFolderTree*>( listView() );
00201   tree->insertIntoFolderToItemMap( mFolder, this );
00202 }
00203 
00204 void KMFolderTreeItem::adjustUnreadCount( int newUnreadCount ) {
00205   // adjust the icons if the folder is now newly unread or
00206   // now newly not-unread
00207   if ( newUnreadCount != 0 && unreadCount() == 0 )
00208     setPixmap( 0, unreadIcon() );
00209   if ( unreadCount() != 0 && newUnreadCount == 0 )
00210     setPixmap( 0, normalIcon() );
00211 
00212   setUnreadCount( newUnreadCount );
00213 }
00214 
00215 void KMFolderTreeItem::slotRepaint() {
00216   if ( unreadCount() > 0 )
00217     setPixmap( 0, unreadIcon() );
00218   else
00219     setPixmap( 0, normalIcon() );
00220   emit iconChanged( this );
00221   repaint();
00222 }
00223 
00224 
00225 //-----------------------------------------------------------------------------
00226 bool KMFolderTreeItem::acceptDrag(QDropEvent*) const
00227 {
00228   if ( !mFolder || mFolder->isReadOnly() ||
00229       (mFolder->noContent() && childCount() == 0) ||
00230        (mFolder->noContent() && isOpen()) ) {
00231     return false;
00232   }
00233   else {
00234     return true;
00235   }
00236 }
00237 
00238 //-----------------------------------------------------------------------------
00239 void KMFolderTreeItem::properties()
00240 {
00241   if ( !mFolder )
00242     return;
00243 
00244   KMFolderTree* tree = static_cast<KMFolderTree*>( listView() );
00245   tree->mainWidget()->modifyFolder( this );
00246   //Nothing here the above may actually delete this KMFolderTreeItem
00247 }
00248 
00249 //=============================================================================
00250 
00251 
00252 KMFolderTree::KMFolderTree( KMMainWidget *mainWidget, QWidget *parent,
00253                             const char *name )
00254   : KFolderTree( parent, name )
00255 {
00256   oldSelected = 0;
00257   oldCurrent = 0;
00258   mLastItem = 0;
00259   mMainWidget = mainWidget;
00260   mReloading = false;
00261 
00262   addAcceptableDropMimetype(MailListDrag::format(), false);
00263 
00264   int namecol = addColumn( i18n("Folder"), 250 );
00265   header()->setStretchEnabled( true, namecol );
00266 
00267   // connect
00268   connectSignals();
00269 
00270   // popup to switch columns
00271   header()->setClickEnabled(true);
00272   header()->installEventFilter(this);
00273   mPopup = new KPopupMenu(this);
00274   mPopup->insertTitle(i18n("View Columns"));
00275   mPopup->setCheckable(true);
00276   mUnreadPop = mPopup->insertItem(i18n("Unread Column"), this, SLOT(slotToggleUnreadColumn()));
00277   mTotalPop = mPopup->insertItem(i18n("Total Column"), this, SLOT(slotToggleTotalColumn()));
00278 }
00279 
00280 //-----------------------------------------------------------------------------
00281 // connects all needed signals to their slots
00282 void KMFolderTree::connectSignals()
00283 {
00284   connect(&mUpdateTimer, SIGNAL(timeout()),
00285           this, SLOT(delayedUpdate()));
00286 
00287   connect(kmkernel->folderMgr(), SIGNAL(changed()),
00288           this, SLOT(doFolderListChanged()));
00289 
00290   connect(kmkernel->folderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00291           this, SLOT(slotFolderRemoved(KMFolder*)));
00292 
00293   connect(kmkernel->imapFolderMgr(), SIGNAL(changed()),
00294           this, SLOT(doFolderListChanged()));
00295 
00296   connect(kmkernel->imapFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00297           this, SLOT(slotFolderRemoved(KMFolder*)));
00298 
00299   connect(kmkernel->dimapFolderMgr(), SIGNAL(changed()),
00300           this, SLOT(doFolderListChanged()));
00301 
00302   connect(kmkernel->dimapFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00303           this, SLOT(slotFolderRemoved(KMFolder*)));
00304 
00305   connect(kmkernel->searchFolderMgr(), SIGNAL(changed()),
00306           this, SLOT(doFolderListChanged()));
00307 
00308   connect(kmkernel->acctMgr(), SIGNAL(accountRemoved(KMAccount*)),
00309           this, SLOT(slotAccountRemoved(KMAccount*)));
00310 
00311   connect(kmkernel->searchFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00312           this, SLOT(slotFolderRemoved(KMFolder*)));
00313 
00314   connect( &autoopen_timer, SIGNAL( timeout() ),
00315            this, SLOT( openFolder() ) );
00316 
00317   connect( this, SIGNAL( contextMenuRequested( QListViewItem*, const QPoint &, int ) ),
00318            this, SLOT( slotContextMenuRequested( QListViewItem*, const QPoint & ) ) );
00319 
00320   connect( this, SIGNAL( expanded( QListViewItem* ) ),
00321            this, SLOT( slotFolderExpanded( QListViewItem* ) ) );
00322 
00323   connect( this, SIGNAL( collapsed( QListViewItem* ) ),
00324            this, SLOT( slotFolderCollapsed( QListViewItem* ) ) );
00325 
00326   connect( this, SIGNAL( itemRenamed( QListViewItem*, int, const QString &)),
00327            this, SLOT( slotRenameFolder( QListViewItem*, int, const QString &)));
00328 }
00329 
00330 //-----------------------------------------------------------------------------
00331 bool KMFolderTree::event(QEvent *e)
00332 {
00333   if (e->type() == QEvent::ApplicationPaletteChange)
00334   {
00335      readColorConfig();
00336      return true;
00337   }
00338   return KListView::event(e);
00339 }
00340 
00341 //-----------------------------------------------------------------------------
00342 void KMFolderTree::readColorConfig (void)
00343 {
00344   KConfig* conf = KMKernel::config();
00345   // Custom/System color support
00346   KConfigGroupSaver saver(conf, "Reader");
00347   QColor c1=QColor(kapp->palette().active().text());
00348   QColor c2=QColor("blue");
00349   QColor c4=QColor(kapp->palette().active().base());
00350 
00351   if (!conf->readBoolEntry("defaultColors",TRUE)) {
00352     mPaintInfo.colFore = conf->readColorEntry("ForegroundColor",&c1);
00353     mPaintInfo.colUnread = conf->readColorEntry("UnreadMessage",&c2);
00354     mPaintInfo.colBack = conf->readColorEntry("BackgroundColor",&c4);
00355   }
00356   else {
00357     mPaintInfo.colFore = c1;
00358     mPaintInfo.colUnread = c2;
00359     mPaintInfo.colBack = c4;
00360   }
00361   QPalette newPal = kapp->palette();
00362   newPal.setColor( QColorGroup::Base, mPaintInfo.colBack );
00363   newPal.setColor( QColorGroup::Text, mPaintInfo.colFore );
00364   setPalette( newPal );
00365 }
00366 
00367 //-----------------------------------------------------------------------------
00368 void KMFolderTree::readConfig (void)
00369 {
00370   KConfig* conf = KMKernel::config();
00371 
00372   readColorConfig();
00373 
00374   // Custom/Ssystem font support
00375   {
00376     KConfigGroupSaver saver(conf, "Fonts");
00377     if (!conf->readBoolEntry("defaultFonts",TRUE)) {
00378       QFont folderFont( KGlobalSettings::generalFont() );
00379       setFont(conf->readFontEntry("folder-font", &folderFont));
00380     }
00381     else
00382       setFont(KGlobalSettings::generalFont());
00383   }
00384 
00385   // restore the layout
00386   restoreLayout(conf, "Geometry");
00387 }
00388 
00389 //-----------------------------------------------------------------------------
00390 // Save the configuration file
00391 void KMFolderTree::writeConfig()
00392 {
00393   // save the current state of the folders
00394   for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00395     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00396     if (fti)
00397       writeIsListViewItemOpen(fti);
00398   }
00399 
00400   // save the current layout
00401   saveLayout(KMKernel::config(), "Geometry");
00402 }
00403 
00404 //-----------------------------------------------------------------------------
00405 // Updates the count of unread messages (count of unread messages
00406 // is now cached in KMails config file)
00407 void KMFolderTree::updateUnreadAll()
00408 {
00409   bool upd = isUpdatesEnabled();
00410   setUpdatesEnabled(FALSE);
00411 
00412   KMFolderDir* fdir;
00413   KMFolderNode* folderNode;
00414   KMFolder* folder;
00415 
00416   fdir = &kmkernel->folderMgr()->dir();
00417   for (folderNode = fdir->first();
00418     folderNode != 0;
00419     folderNode =fdir->next())
00420   {
00421     if (!folderNode->isDir()) {
00422       folder = static_cast<KMFolder*>(folderNode);
00423 
00424       folder->open();
00425       folder->countUnread();
00426       folder->close();
00427     }
00428   }
00429 
00430   setUpdatesEnabled(upd);
00431 }
00432 
00433 //-----------------------------------------------------------------------------
00434 // Reload the tree of items in the list view
00435 void KMFolderTree::reload(bool openFolders)
00436 {
00437   if ( mReloading ) {
00438     // no parallel reloads are allowed
00439     kdDebug(5006) << "KMFolderTree::reload - already reloading" << endl;
00440     return;
00441   }
00442   mReloading = true;
00443   
00444   int top = contentsY();
00445   mLastItem = 0;
00446   // invalidate selected drop item
00447   oldSelected = 0;
00448   // remember last
00449   KMFolder* last = currentFolder();
00450   KMFolder* selected = 0;
00451   KMFolder* oldCurrentFolder = 
00452     ( oldCurrent ? static_cast<KMFolderTreeItem*>(oldCurrent)->folder(): 0 );
00453   for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00454     KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
00455     writeIsListViewItemOpen( fti );
00456     if ( fti->isSelected() )
00457       selected = fti->folder();
00458   }
00459   mFolderToItem.clear();
00460   clear();
00461 
00462   // construct the root of the local folders
00463   KMFolderTreeItem * root = new KMFolderTreeItem( this, i18n("Local Folders") );
00464   root->setOpen( readIsListViewItemOpen(root) );
00465 
00466   KMFolderDir * fdir = &kmkernel->folderMgr()->dir();
00467   addDirectory(fdir, root);
00468 
00469   fdir = &kmkernel->imapFolderMgr()->dir();
00470   // each imap-account creates it's own root
00471   addDirectory(fdir, 0);
00472 
00473   fdir = &kmkernel->dimapFolderMgr()->dir();
00474   // each dimap-account creates it's own root
00475   addDirectory(fdir, 0);
00476 
00477   // construct the root of the search folder hierarchy:
00478   root = new KMFolderTreeItem( this, i18n("Searches"), KFolderTreeItem::Search );
00479   root->setOpen( readIsListViewItemOpen( root ) );
00480 
00481   fdir = &kmkernel->searchFolderMgr()->dir();
00482   addDirectory(fdir, root);
00483 
00484   if (openFolders)
00485   {
00486     // we open all folders to update the count
00487     mUpdateIterator = QListViewItemIterator (this);
00488     QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
00489   }
00490 
00491   for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00492     KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
00493     if ( !fti || !fti->folder() )
00494       continue;
00495 
00496     disconnect(fti->folder(),SIGNAL(iconsChanged()),
00497                fti,SLOT(slotRepaint()));
00498     connect(fti->folder(),SIGNAL(iconsChanged()),
00499             fti,SLOT(slotRepaint()));
00500 
00501     disconnect(fti->folder(),SIGNAL(nameChanged()),
00502                fti,SLOT(slotNameChanged()));
00503     connect(fti->folder(),SIGNAL(nameChanged()),
00504             fti,SLOT(slotNameChanged()));
00505 
00506     if (fti->folder()->folderType() == KMFolderTypeImap) {
00507       // imap-only
00508       KMFolderImap *imapFolder =
00509         dynamic_cast<KMFolderImap*> ( fti->folder()->storage() );
00510       disconnect( imapFolder, SIGNAL(folderComplete(KMFolderImap*, bool)),
00511           this,SLOT(slotUpdateCounts(KMFolderImap*, bool)));
00512       connect( imapFolder, SIGNAL(folderComplete(KMFolderImap*, bool)),
00513           this,SLOT(slotUpdateCounts(KMFolderImap*, bool)));
00514     } else {
00515       // others-only, imap doesn't need this because of the folderComplete-signal
00516       // we want to be noticed of changes to update the unread/total columns
00517       disconnect(fti->folder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
00518           this,SLOT(slotUpdateCounts(KMFolder*)));
00519       connect(fti->folder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
00520           this,SLOT(slotUpdateCounts(KMFolder*)));
00521     }
00522 
00523     disconnect(fti->folder(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00524                this,SLOT(slotUpdateCounts(KMFolder*)));
00525     connect(fti->folder(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00526             this,SLOT(slotUpdateCounts(KMFolder*)));
00527     disconnect(fti->folder(), SIGNAL(msgRemoved(KMFolder*)),
00528                this,SLOT(slotUpdateCounts(KMFolder*)));
00529     connect(fti->folder(), SIGNAL(msgRemoved(KMFolder*)),
00530             this,SLOT(slotUpdateCounts(KMFolder*)));
00531 
00532     if (!openFolders)
00533       slotUpdateCounts(fti->folder());
00534   }
00535   ensureVisible(0, top + visibleHeight(), 0, 0);
00536   // if current and selected folder did not change set it again
00537   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
00538   {
00539     if ( last && 
00540         static_cast<KMFolderTreeItem*>( it.current() )->folder() == last )
00541     {
00542       mLastItem = static_cast<KMFolderTreeItem*>( it.current() );
00543       setCurrentItem( it.current() );
00544     }
00545     if ( selected && 
00546         static_cast<KMFolderTreeItem*>( it.current() )->folder() == selected )
00547     {
00548       setSelected( it.current(), true );
00549     }
00550     if ( oldCurrentFolder && 
00551         static_cast<KMFolderTreeItem*>( it.current() )->folder() == oldCurrentFolder )
00552     {
00553       oldCurrent = it.current();
00554     }
00555   }
00556   refresh();  
00557   mReloading = false;
00558 }
00559 
00560 //-----------------------------------------------------------------------------
00561 void KMFolderTree::slotUpdateOneCount()
00562 {
00563   if ( !mUpdateIterator.current() ) return;
00564   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(mUpdateIterator.current());
00565   ++mUpdateIterator;
00566   if ( !fti->folder() ) {
00567     // next one please
00568     QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
00569     return;
00570   }
00571 
00572   // open the folder and update the count
00573   bool open = fti->folder()->isOpened();
00574   if (!open) fti->folder()->open();
00575   slotUpdateCounts(fti->folder());
00576   // restore previous state
00577   if (!open) fti->folder()->close();
00578 
00579   QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
00580 }
00581 
00582 //-----------------------------------------------------------------------------
00583 // Recursively add a directory of folders to the tree of folders
00584 void KMFolderTree::addDirectory( KMFolderDir *fdir, KMFolderTreeItem* parent )
00585 {
00586   for ( KMFolderNode * node = fdir->first() ; node ; node = fdir->next() ) {
00587     if ( node->isDir() )
00588       continue;
00589 
00590     KMFolder * folder = static_cast<KMFolder*>(node);
00591     KMFolderTreeItem * fti = 0;
00592     if (!parent)
00593     {
00594       // create new root-item
00595       // it needs a folder e.g. to save it's state (open/close)
00596       fti = new KMFolderTreeItem( this, folder->label(), folder );
00597       fti->setExpandable( true );
00598     } else {
00599       // Check if this is an IMAP resource folder
00600       if ( kmkernel->iCalIface().hideResourceImapFolder( folder ) )
00601         // It is
00602         continue;
00603 
00604       // create new child
00605       fti = new KMFolderTreeItem( parent, folder->label(), folder );
00606       // set folders explicitely to exandable even with unknown child state
00607       // this way we can do a listing for IMAP folders when they're expanded
00608       if ( folder->storage()->hasChildren() != FolderStorage::HasNoChildren )
00609         fti->setExpandable( true );
00610       else
00611         fti->setExpandable( false );
00612 
00613       connect (fti, SIGNAL(iconChanged(KMFolderTreeItem*)),
00614                this, SIGNAL(iconChanged(KMFolderTreeItem*)));
00615       connect (fti, SIGNAL(nameChanged(KMFolderTreeItem*)),
00616                this, SIGNAL(nameChanged(KMFolderTreeItem*)));
00617     }
00618     // restore last open-state
00619     fti->setOpen( readIsListViewItemOpen(fti) );
00620 
00621     // add child-folders
00622     if (folder && folder->child()) {
00623       addDirectory( folder->child(), fti );
00624     }
00625    } // for-end
00626 }
00627 
00628 //-----------------------------------------------------------------------------
00629 // Initiate a delayed refresh of the tree
00630 void KMFolderTree::refresh()
00631 {
00632   mUpdateTimer.changeInterval(200);
00633 }
00634 
00635 //-----------------------------------------------------------------------------
00636 // Updates the pixmap and extendedLabel information for items
00637 void KMFolderTree::delayedUpdate()
00638 {
00639   bool upd = isUpdatesEnabled();
00640   if ( upd ) {
00641     setUpdatesEnabled(FALSE);
00642 
00643     for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00644       KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00645       if (!fti || !fti->folder())
00646         continue;
00647 
00648       if ( fti->needsRepaint() ) {
00649         fti->repaint();
00650         fti->setNeedsRepaint( false );
00651       }
00652     }
00653     setUpdatesEnabled(upd);
00654   }
00655   mUpdateTimer.stop();
00656 }
00657 
00658 //-----------------------------------------------------------------------------
00659 // Folders have been added/deleted update the tree of folders
00660 void KMFolderTree::doFolderListChanged()
00661 {
00662   reload();
00663 }
00664 
00665 //-----------------------------------------------------------------------------
00666 void KMFolderTree::slotAccountRemoved(KMAccount *)
00667 {
00668   doFolderSelected( firstChild() );
00669 }
00670 
00671 //-----------------------------------------------------------------------------
00672 void KMFolderTree::slotFolderRemoved(KMFolder *aFolder)
00673 {
00674   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>
00675     (indexOfFolder(aFolder));
00676   if (!fti || !fti->folder()) return;
00677   if (fti == currentItem())
00678   {
00679     QListViewItem *qlvi = fti->itemAbove();
00680     if (!qlvi) qlvi = fti->itemBelow();
00681     doFolderSelected( qlvi );
00682   }
00683   removeFromFolderToItemMap( aFolder );
00684   delete fti;
00685 }
00686 
00687 //-----------------------------------------------------------------------------
00688 // Methods for navigating folders with the keyboard
00689 void KMFolderTree::prepareItem( KMFolderTreeItem* fti )
00690 {
00691   for ( QListViewItem * parent = fti->parent() ; parent ; parent = parent->parent() )
00692     parent->setOpen( TRUE );
00693   ensureItemVisible( fti );
00694 }
00695 
00696 //-----------------------------------------------------------------------------
00697 void KMFolderTree::nextUnreadFolder()
00698 {
00699     nextUnreadFolder( false );
00700 }
00701 
00702 //-----------------------------------------------------------------------------
00703 void KMFolderTree::nextUnreadFolder(bool confirm)
00704 {
00705   QListViewItemIterator it( currentItem() ? currentItem() : firstChild() );
00706   if ( currentItem() )
00707     ++it; // don't find current item
00708   for ( ; it.current() ; ++it ) {
00709     //check if folder is one to stop on
00710     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00711     if (checkUnreadFolder(fti,confirm)) return;
00712   }
00713   //Now if confirm is true we are doing "ReadOn"
00714   //we have got to the bottom of the folder list
00715   //so we have to start at the top
00716   if (confirm) {
00717     for ( it = firstChild() ; it.current() ; ++it ) {
00718       //check if folder is one to stop on
00719       KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00720       if (checkUnreadFolder(fti,confirm)) return;
00721     }
00722   }
00723 }
00724 
00725 //-----------------------------------------------------------------------------
00726 bool KMFolderTree::checkUnreadFolder (KMFolderTreeItem* fti, bool confirm)
00727 {
00728   if (fti && fti->folder()  &&
00729       (fti->folder()->countUnread() > 0)) {
00730 
00731     // Don't change into the trash or outbox folders.
00732     if (fti->type() == KFolderTreeItem::Trash ||
00733         fti->type() == KFolderTreeItem::Outbox )
00734       return false;
00735 
00736     if (confirm) {
00737       // Skip drafts and sent mail as well, when reading mail with the space bar
00738       // but not when changing into the next folder with unread mail via ctrl+ or
00739       // ctrl- so we do this only if (confirm == true), which means we are doing
00740       // readOn.
00741       if ( fti->type() == KFolderTreeItem::Drafts ||
00742            fti->type() == KFolderTreeItem::SentMail )
00743         return false;
00744 
00745       //  warn user that going to next folder - but keep track of
00746       //  whether he wishes to be notified again in "AskNextFolder"
00747       //  parameter (kept in the config file for kmail)
00748       if ( KMessageBox::questionYesNo( this,
00749             i18n( "<qt>Go to the next unread message in folder <b>%1</b>?</qt>" )
00750             .arg( fti->folder()->label() ),
00751             i18n( "Go to the Next Unread Message" ),
00752             KStdGuiItem::yes(), KStdGuiItem::no(), // defaults
00753             "AskNextFolder",
00754             false)
00755           == KMessageBox::No ) return true;
00756     }
00757     prepareItem( fti );
00758     blockSignals( true );
00759     doFolderSelected( fti );
00760     blockSignals( false );
00761     emit folderSelectedUnread( fti->folder() );
00762     return true;
00763   }
00764   return false;
00765 }
00766 
00767 //-----------------------------------------------------------------------------
00768 void KMFolderTree::prevUnreadFolder()
00769 {
00770   QListViewItemIterator it( currentItem() ? currentItem() : lastItem() );
00771   if ( currentItem() )
00772     --it; // don't find current item
00773   for ( ; it.current() ; --it ) {
00774     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00775     if (checkUnreadFolder(fti,false)) return;
00776   }
00777 }
00778 
00779 //-----------------------------------------------------------------------------
00780 void KMFolderTree::incCurrentFolder()
00781 {
00782   QListViewItemIterator it( currentItem() );
00783   ++it;
00784   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00785   if (fti && fti->folder()) {
00786       prepareItem( fti );
00787       setFocus();
00788       setCurrentItem( fti );
00789   }
00790 }
00791 
00792 //-----------------------------------------------------------------------------
00793 void KMFolderTree::decCurrentFolder()
00794 {
00795   QListViewItemIterator it( currentItem() );
00796   --it;
00797   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00798   if (fti && fti->folder()) {
00799       prepareItem( fti );
00800       setFocus();
00801       setCurrentItem( fti );
00802   }
00803 }
00804 
00805 //-----------------------------------------------------------------------------
00806 void KMFolderTree::selectCurrentFolder()
00807 {
00808   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() );
00809   if (fti && fti->folder()) {
00810       prepareItem( fti );
00811       doFolderSelected( fti );
00812   }
00813 }
00814 
00815 //-----------------------------------------------------------------------------
00816 KMFolder *KMFolderTree::currentFolder() const
00817 {
00818     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() );
00819     if (fti )
00820         return fti->folder();
00821     else
00822         return 0;
00823 }
00824 
00825 //-----------------------------------------------------------------------------
00826 // When not dragging and dropping a change in the selected item
00827 // indicates the user has changed the active folder emit a signal
00828 // so that the header list and reader window can be udpated.
00829 void KMFolderTree::doFolderSelected( QListViewItem* qlvi )
00830 {
00831   if (!qlvi) return;
00832   if ( mLastItem && mLastItem == qlvi )
00833     return;
00834 
00835   KMFolderTreeItem* fti = static_cast< KMFolderTreeItem* >(qlvi);
00836   KMFolder* folder = 0;
00837   if (fti) folder = fti->folder();
00838 
00839 
00840   if (mLastItem && mLastItem != fti && mLastItem->folder()
00841      && (mLastItem->folder()->folderType() == KMFolderTypeImap))
00842   {
00843     KMFolderImap *imapFolder = static_cast<KMFolderImap*>(mLastItem->folder()->storage());
00844     imapFolder->setSelected(FALSE);
00845   }
00846   mLastItem = fti;
00847 
00848   clearSelection();
00849   setCurrentItem( qlvi );
00850   setSelected( qlvi, TRUE );
00851   if (!folder) {
00852     emit folderSelected(0); // Root has been selected
00853   }
00854   else {
00855     emit folderSelected(folder);
00856     slotUpdateCounts(folder);
00857   }
00858 }
00859 
00860 //-----------------------------------------------------------------------------
00861 void KMFolderTree::resizeEvent(QResizeEvent* e)
00862 {
00863   KConfig* conf = KMKernel::config();
00864 
00865   KConfigGroupSaver saver(conf, "Geometry");
00866   conf->writeEntry(name(), size().width());
00867 
00868   KListView::resizeEvent(e);
00869 }
00870 
00871 //-----------------------------------------------------------------------------
00872 // show context menu
00873 void KMFolderTree::slotContextMenuRequested( QListViewItem *lvi,
00874                                              const QPoint &p )
00875 {
00876   if (!lvi)
00877     return;
00878   setCurrentItem( lvi );
00879   setSelected( lvi, TRUE );
00880 
00881   if (!mMainWidget) return; // safe bet
00882 
00883   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(lvi);
00884   if ( fti != mLastItem )
00885     doFolderSelected( fti );
00886 
00887   if (!fti )
00888     return;
00889 
00890   KPopupMenu *folderMenu = new KPopupMenu;
00891   if (fti->folder()) folderMenu->insertTitle(fti->folder()->label());
00892 
00893   if ((!fti->folder() || (fti->folder()->noContent()
00894     && !fti->parent())))
00895   {
00896     QString createChild = i18n("&New Subfolder...");
00897     if (!fti->folder()) createChild = i18n("&New Folder...");
00898 
00899     if (fti->folder() || (fti->text(0) != i18n("Searches")))
00900         folderMenu->insertItem(SmallIcon("folder_new"),
00901                                createChild, this,
00902                                SLOT(addChildFolder()));
00903 
00904     if (!fti->folder()) {
00905       folderMenu->insertItem(i18n("&Compact All Folders"),
00906                              kmkernel->folderMgr(), SLOT(compactAll()));
00907       folderMenu->insertItem(i18n("&Expire All Folders"),
00908                              kmkernel->folderMgr(), SLOT(expireAll()));
00909     } else if (fti->folder()->folderType() == KMFolderTypeImap) {
00910       folderMenu->insertItem(SmallIcon("mail_get"), i18n("Check &Mail"),
00911         this,
00912         SLOT(slotCheckMail()));
00913     }
00914   } else {
00915     if ((fti->folder() == kmkernel->outboxFolder()) && (fti->folder()->count()) )
00916         folderMenu->insertItem(SmallIcon("mail_send"),
00917                                i18n("&Send Queued Messages"), mMainWidget,
00918                                SLOT(slotSendQueued()));
00919     if (!fti->folder()->noChildren())
00920     {
00921       folderMenu->insertItem(SmallIcon("folder_new"),
00922                              i18n("&New Subfolder..."), this,
00923                              SLOT(addChildFolder()));
00924     }
00925 
00926     // Want to be able to display properties for ALL folders,
00927     // so we can edit expiry properties.
00928     // -- smp.
00929     if (!fti->folder()->noContent())
00930     {
00931       int itemId = folderMenu->insertItem( SmallIcon("goto"),
00932                                            i18n("Mark All Messages as &Read"),
00933                                            mMainWidget,
00934                                            SLOT( slotMarkAllAsRead() ) );
00935       folderMenu->setItemEnabled( itemId, fti->folder()->countUnread() > 0 );
00936 
00937       folderMenu->insertItem(i18n("&Compact"), mMainWidget,
00938                              SLOT(slotCompactFolder()));
00939 
00940       itemId = folderMenu->insertItem(i18n("&Expire"), mMainWidget,
00941                                       SLOT(slotExpireFolder()));
00942       folderMenu->setItemEnabled( itemId, fti->folder()->isAutoExpire() && !fti->folder()->isReadOnly() );
00943 
00944 
00945       folderMenu->insertSeparator();
00946 
00947       itemId = folderMenu->insertItem(SmallIcon("edittrash"),
00948         (kmkernel->folderIsTrash(fti->folder())) ? i18n("&Empty") :
00949                              i18n("&Move All Messages to Trash"), mMainWidget,
00950                              SLOT(slotEmptyFolder()));
00951       folderMenu->setItemEnabled( itemId, fti->folder()->count() > 0 && !fti->folder()->isReadOnly() );
00952     }
00953     if ( !fti->folder()->isSystemFolder() )
00954       folderMenu->insertItem(SmallIcon("editdelete"),
00955                              i18n("&Delete Folder"), mMainWidget,
00956                              SLOT(slotRemoveFolder()));
00957 
00958   }
00959   if (fti->folder() &&
00960       (fti->folder()->folderType() == KMFolderTypeImap ||
00961        fti->folder()->folderType() == KMFolderTypeCachedImap ))
00962   {
00963     folderMenu->insertSeparator();
00964     folderMenu->insertItem(SmallIcon("bookmark_folder"),
00965         i18n("Subscription..."), mMainWidget,
00966         SLOT(slotSubscriptionDialog()));
00967 
00968     if (!fti->folder()->noContent())
00969     {
00970       int id = folderMenu->insertItem(SmallIcon("kmmsgnew"), i18n("Check Mail in This Folder"), mMainWidget,
00971                                       SLOT(slotRefreshFolder()));
00972       if ( fti->folder()->folderType() == KMFolderTypeImap ) {
00973         folderMenu->insertItem(SmallIcon("reload"), i18n("Refresh Folder List"), this,
00974             SLOT(slotResetFolderList()));
00975       } else {
00976         bool knownImapPath = !static_cast<KMFolderCachedImap*>( fti->folder()->storage() )->imapPath().isEmpty();
00977         folderMenu->setItemEnabled( id, knownImapPath );
00978 
00979       }
00980     }
00981     if ( fti->folder()->folderType() == KMFolderTypeCachedImap ) {
00982       KMFolderCachedImap * folder = static_cast<KMFolderCachedImap*>( fti->folder()->storage() );
00983       folderMenu->insertItem( SmallIcon("wizard"),
00984                               i18n("&Troubleshoot IMAP Cache..."),
00985                               folder, SLOT(slotTroubleshoot()) );
00986     }
00987   }
00988 
00989   if ( fti->folder() && fti->folder()->isMailingListEnabled() ) {
00990     folderMenu->insertSeparator();
00991     folderMenu->insertItem( i18n("New Message to Mailing-List..."),
00992                             this,
00993                             SLOT( slotNewMessageToMailingList() ) );
00994   }
00995 
00996   if (fti->folder() && fti->parent())
00997   {
00998     folderMenu->insertSeparator();
00999     folderMenu->insertItem(SmallIcon("configure"),
01000         i18n("&Properties"),
01001         fti,
01002         SLOT(properties()));
01003   }
01004 
01005 
01006   kmkernel->setContextMenuShown( true );
01007   folderMenu->exec (p, 0);
01008   kmkernel->setContextMenuShown( false );
01009   triggerUpdate();
01010   delete folderMenu;
01011   folderMenu = 0;
01012 }
01013 
01014 //-----------------------------------------------------------------------------
01015 // If middle button and folder holds mailing-list, create a message to that list
01016 void KMFolderTree::contentsMouseReleaseEvent(QMouseEvent* me)
01017 {
01018   QListViewItem *lvi = currentItem(); // Needed for when branches are clicked on
01019   ButtonState btn = me->button();
01020   doFolderSelected(lvi);
01021 
01022   // get underlying folder
01023   KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>(lvi);
01024 
01025   if (!fti || !fti->folder()) {
01026     KFolderTree::contentsMouseReleaseEvent(me);
01027     return;
01028   }
01029 
01030   // react on middle-button only
01031   if (btn != Qt::MidButton) {
01032     KFolderTree::contentsMouseReleaseEvent(me);
01033     return;
01034   }
01035 
01036   if ( fti->folder()->isMailingListEnabled() ) {
01037     KMCommand *command = new KMMailingListPostCommand( this, fti->folder() );
01038     command->start();
01039   }
01040 
01041   KFolderTree::contentsMouseReleaseEvent(me);
01042 }
01043 
01044 //-----------------------------------------------------------------------------
01045 // Create a subfolder.
01046 // Requires creating the appropriate subdirectory and show a dialog
01047 void KMFolderTree::addChildFolder()
01048 {
01049   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(currentItem());
01050   if (!fti)
01051     return;
01052   KMFolder *aFolder = fti->folder();
01053   if (fti->folder())
01054     if (!fti->folder()->createChildFolder())
01055       return;
01056 
01057   KMFolderDir *dir = &(kmkernel->folderMgr()->dir());
01058   if (fti->folder())
01059     dir = fti->folder()->child();
01060 
01061   KMFolderDialog *d =
01062     new KMFolderDialog(0, dir, this, i18n("Create Subfolder") );
01063 
01064   if (d->exec()) /* fti may be deleted here */ {
01065     QListViewItem *qlvi = indexOfFolder( aFolder );
01066     if (qlvi) {
01067       qlvi->setOpen(TRUE);
01068       blockSignals( true );
01069       setCurrentItem( qlvi );
01070       blockSignals( false );
01071     }
01072   }
01073   delete d;
01074   // update if added to root Folder
01075   if (!aFolder || aFolder->noContent()) {
01076      doFolderListChanged();
01077   }
01078 }
01079 
01080 //-----------------------------------------------------------------------------
01081 // Returns whether a folder directory should be open as specified in the
01082 // config file.
01083 bool KMFolderTree::readIsListViewItemOpen(KMFolderTreeItem *fti)
01084 {
01085   KConfig* config = KMKernel::config();
01086   KMFolder *folder = fti->folder();
01087   QString name;
01088   if (folder)
01089   {
01090     name = "Folder-" + folder->idString();
01091   } else if (fti->type() == KFolderTreeItem::Root)
01092   {
01093     if (fti->protocol() == KFolderTreeItem::NONE) // local root
01094       name = "Folder_local_root";
01095     else if (fti->protocol() == KFolderTreeItem::Search)
01096       name = "Folder_search";
01097     else
01098       return false;
01099   } else {
01100     return false;
01101   }
01102   KConfigGroupSaver saver(config, name);
01103 
01104   return config->readBoolEntry("isOpen", false);
01105 }
01106 
01107 //-----------------------------------------------------------------------------
01108 // Saves open/closed state of a folder directory into the config file
01109 void KMFolderTree::writeIsListViewItemOpen(KMFolderTreeItem *fti)
01110 {
01111   KConfig* config = KMKernel::config();
01112   KMFolder *folder = fti->folder();
01113   QString name;
01114   if (folder)
01115   {
01116     name = "Folder-" + folder->idString();
01117   } else if (fti->type() == KFolderTreeItem::Root)
01118   {
01119     if (fti->protocol() == KFolderTreeItem::NONE) // local root
01120       name = "Folder_local_root";
01121     else if (fti->protocol() == KFolderTreeItem::Search)
01122       name = "Folder_search";
01123     else
01124       return;
01125   } else {
01126     return;
01127   }
01128   KConfigGroupSaver saver(config, name);
01129   config->writeEntry("isOpen", fti->isOpen() );
01130 }
01131 
01132 
01133 //-----------------------------------------------------------------------------
01134 void KMFolderTree::cleanupConfigFile()
01135 {
01136   if ( childCount() == 0 )
01137     return; // just in case reload wasn't called before
01138   KConfig* config = KMKernel::config();
01139   QStringList existingFolders;
01140   QListViewItemIterator fldIt(this);
01141   QMap<QString,bool> folderMap;
01142   KMFolderTreeItem *fti;
01143   for (QListViewItemIterator fldIt(this); fldIt.current(); fldIt++)
01144   {
01145     fti = static_cast<KMFolderTreeItem*>(fldIt.current());
01146     if (fti && fti->folder())
01147       folderMap.insert(fti->folder()->idString(), true);
01148   }
01149   QStringList groupList = config->groupList();
01150   QString name;
01151   for (QStringList::Iterator grpIt = groupList.begin();
01152     grpIt != groupList.end(); grpIt++)
01153   {
01154     if ((*grpIt).left(7) != "Folder-") continue;
01155     name = (*grpIt).mid(7);
01156     if (folderMap.find(name) == folderMap.end())
01157     {
01158       KMFolder* folder = kmkernel->findFolderById( name );
01159       if ( folder && kmkernel->iCalIface().hideResourceImapFolder( folder ) )
01160         continue; // hidden IMAP resource folder, don't delete info
01161 
01162       config->deleteGroup(*grpIt, TRUE);
01163       kdDebug(5006) << "Deleting information about folder " << name << endl;
01164     }
01165   }
01166 }
01167 
01168 
01169 //-----------------------------------------------------------------------------
01170 // Drag and Drop handling -- based on the Troll Tech dirview example
01171 
01172 enum {
01173   DRAG_COPY = 0,
01174   DRAG_MOVE = 1,
01175   DRAG_CANCEL = 2
01176 };
01177 
01178 //-----------------------------------------------------------------------------
01179 void KMFolderTree::openFolder()
01180 {
01181     autoopen_timer.stop();
01182     if ( dropItem && !dropItem->isOpen() ) {
01183         dropItem->setOpen( TRUE );
01184         dropItem->repaint();
01185     }
01186 }
01187 
01188 static const int autoopenTime = 750;
01189 
01190 //-----------------------------------------------------------------------------
01191 void KMFolderTree::contentsDragEnterEvent( QDragEnterEvent *e )
01192 {
01193   oldCurrent = 0;
01194   oldSelected = 0;
01195 
01196   oldCurrent = currentItem();
01197   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
01198     if ( it.current()->isSelected() )
01199       oldSelected = it.current();
01200 
01201   setFocus();
01202 
01203   QListViewItem *i = itemAt( contentsToViewport(e->pos()) );
01204   if ( i ) {
01205     dropItem = i;
01206     autoopen_timer.start( autoopenTime );
01207   }
01208   e->accept( acceptDrag(e) );
01209 }
01210 
01211 //-----------------------------------------------------------------------------
01212 void KMFolderTree::contentsDragMoveEvent( QDragMoveEvent *e )
01213 {
01214     QPoint vp = contentsToViewport(e->pos());
01215     QListViewItem *i = itemAt( vp );
01216     if ( i ) {
01217         bool dragAccepted = acceptDrag( e );
01218         if ( dragAccepted ) {
01219             setCurrentItem( i );
01220         }
01221 
01222         if ( i != dropItem ) {
01223             autoopen_timer.stop();
01224             dropItem = i;
01225             autoopen_timer.start( autoopenTime );
01226         }
01227 
01228         if ( dragAccepted ) {
01229             e->accept( itemRect(i) );
01230 
01231             switch ( e->action() ) {
01232                 case QDropEvent::Copy:
01233                 break;
01234                 case QDropEvent::Move:
01235                 e->acceptAction();
01236                 break;
01237                 case QDropEvent::Link:
01238                 e->acceptAction();
01239                 break;
01240                 default:
01241                 ;
01242             }
01243         } else {
01244             e->accept( false );
01245         }
01246     } else {
01247         e->accept( false );
01248         autoopen_timer.stop();
01249         dropItem = 0;
01250     }
01251 }
01252 
01253 //-----------------------------------------------------------------------------
01254 void KMFolderTree::contentsDragLeaveEvent( QDragLeaveEvent * )
01255 {
01256     if (!oldCurrent) return;
01257 
01258     autoopen_timer.stop();
01259     dropItem = 0;
01260 
01261     setCurrentItem( oldCurrent );
01262     if ( oldSelected )
01263       setSelected( oldSelected, TRUE );
01264 }
01265 
01266 //-----------------------------------------------------------------------------
01267 void KMFolderTree::contentsDropEvent( QDropEvent *e )
01268 {
01269     autoopen_timer.stop();
01270 
01271     QListViewItem *item = itemAt( contentsToViewport(e->pos()) );
01272     KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01273     if (fti && (fti != oldSelected) && (fti->folder()) && acceptDrag(e))
01274     {
01275       int keybstate = kapp->keyboardModifiers();
01276       if ( keybstate & KApplication::ControlModifier ) {
01277         emit folderDropCopy(fti->folder());
01278       } else if ( keybstate & KApplication::ShiftModifier ) {
01279         emit folderDrop(fti->folder());
01280       } else {
01281         if ( GlobalSettings::showPopupAfterDnD() ) {
01282           KPopupMenu *menu = new KPopupMenu( this );
01283           menu->insertItem( i18n("&Move Here"), DRAG_MOVE, 0 );
01284           menu->insertItem( SmallIcon("editcopy"), i18n("&Copy Here"), DRAG_COPY, 1 );
01285           menu->insertSeparator();
01286           menu->insertItem( SmallIcon("cancel"), i18n("C&ancel"), DRAG_CANCEL, 3 );
01287           int id = menu->exec( QCursor::pos(), 0 );
01288           switch(id) {
01289             case DRAG_COPY:
01290               emit folderDropCopy(fti->folder());
01291               break;
01292             case DRAG_MOVE:
01293               emit folderDrop(fti->folder());
01294               break;
01295             case DRAG_CANCEL: // cancelled by menuitem
01296             case -1: // cancelled by Esc
01297               //just chill, doing nothing
01298               break;
01299             default:
01300               kdDebug(5006) << "Unknown dnd-type! " << id << endl;
01301           }
01302         }
01303         else
01304           emit folderDrop(fti->folder());
01305       }
01306       e->accept( true );
01307     } else
01308       e->accept( false );
01309 
01310     dropItem = 0;
01311 
01312     setCurrentItem( oldCurrent );
01313     if ( oldCurrent) mLastItem = static_cast<KMFolderTreeItem*>(oldCurrent);
01314     if ( oldSelected )
01315     {
01316       clearSelection();
01317       setSelected( oldSelected, TRUE );
01318     }
01319 }
01320 
01321 //-----------------------------------------------------------------------------
01322 void KMFolderTree::slotFolderExpanded( QListViewItem * item )
01323 {
01324   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01325 
01326   if ( fti && fti->folder() &&
01327        fti->folder()->folderType() == KMFolderTypeImap )
01328   {
01329     KMFolderImap *folder = static_cast<KMFolderImap*>( fti->folder()->storage() );
01330     // if we should list all folders we limit this to the root folder
01331     if ( !folder->account()->listOnlyOpenFolders() &&
01332          fti->parent() )
01333       return;
01334     if ( folder->getSubfolderState() == KMFolderImap::imapNoInformation )
01335     {
01336       // check if all parents are expanded
01337       QListViewItem *parent = item->parent();
01338       while ( parent )
01339       {
01340         if ( !parent->isOpen() )
01341           return;
01342         parent = parent->parent();
01343       }
01344       // the tree will be reloaded after that
01345       bool success = folder->listDirectory();
01346       if (!success) fti->setOpen( false );
01347       if ( fti->childCount() == 0 && fti->parent() )
01348         fti->setExpandable( false );
01349     }
01350   }
01351 }
01352 
01353 
01354 //-----------------------------------------------------------------------------
01355 void KMFolderTree::slotFolderCollapsed( QListViewItem * item )
01356 {
01357   slotResetFolderList( item, false );
01358 }
01359 
01360 //-----------------------------------------------------------------------------
01361 void KMFolderTree::slotRenameFolder(QListViewItem *item, int col,
01362                 const QString &text)
01363 {
01364 
01365   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01366 
01367   if (fti && fti->folder() && col != 0 && !currentFolder()->child())
01368           return;
01369 
01370   QString fldName, oldFldName;
01371 
01372   oldFldName = fti->name(0);
01373 
01374   if (!text.isEmpty())
01375           fldName = text;
01376   else
01377           fldName = oldFldName;
01378 
01379   fldName.replace("/", "");
01380   fldName.replace(QRegExp("^\\."), "");
01381 
01382   if (fldName.isEmpty())
01383           fldName = i18n("unnamed");
01384 
01385   fti->setText(0, fldName);
01386   fti->folder()->rename(fldName, &(kmkernel->folderMgr()->dir()));
01387 }
01388 
01389 //-----------------------------------------------------------------------------
01390 void KMFolderTree::slotUpdateCounts(KMFolderImap * folder, bool success)
01391 {
01392   if (success) slotUpdateCounts(folder->folder());
01393 }
01394 
01395 //-----------------------------------------------------------------------------
01396 void KMFolderTree::slotUpdateCounts(KMFolder * folder)
01397 {
01398   QListViewItem * current;
01399 
01400   if (folder)
01401     current = indexOfFolder(folder);
01402   else
01403     current = currentItem();
01404 
01405   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(current);
01406   // sanity check
01407   if (!fti) return;
01408   if (!fti->folder()) fti->setTotalCount(-1);
01409 
01410   // get the unread count
01411   int count = 0;
01412   if (folder->noContent()) // always empty
01413     count = -1;
01414   else
01415     count = fti->folder()->countUnread();
01416 
01417   // set it
01418   bool repaint = false;
01419   if (fti->unreadCount() != count) {
01420      fti->adjustUnreadCount( count );
01421      repaint = true;
01422   }
01423 
01424   if (isTotalActive())
01425   {
01426     // get the total-count
01427     if (fti->folder()->noContent())
01428       count = -1;
01429     else {
01430       // get the cached count if the folder is not open
01431       count = fti->folder()->count( !fti->folder()->isOpened() );
01432     }
01433     // set it
01434     if ( count != fti->totalCount() ) {
01435       fti->setTotalCount(count);
01436       repaint = true;
01437     }
01438   }
01439   if (fti->parent() && !fti->parent()->isOpen())
01440     repaint = false; // we're not visible
01441   if (repaint) {
01442     fti->setNeedsRepaint( true );
01443     refresh();
01444   }
01445   // tell the kernel that one of the counts has changed
01446   kmkernel->messageCountChanged();
01447 }
01448 
01449 void KMFolderTree::updatePopup() const
01450 {
01451    mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
01452    mPopup->setItemChecked( mTotalPop, isTotalActive() );
01453 }
01454 
01455 //-----------------------------------------------------------------------------
01456 void KMFolderTree::toggleColumn(int column, bool openFolders)
01457 {
01458   if (column == unread)
01459   {
01460     // switch unread
01461     if ( isUnreadActive() )
01462     {
01463       removeUnreadColumn();
01464       reload();
01465     } else {
01466       addUnreadColumn( i18n("Unread"), 70 );
01467       reload();
01468     }
01469     // toggle KPopupMenu
01470     mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
01471 
01472   } else if (column == total) {
01473     // switch total
01474     if ( isTotalActive() )
01475     {
01476       removeTotalColumn();
01477       reload();
01478     } else {
01479       addTotalColumn( i18n("Total"), 70 );
01480       reload(openFolders);
01481     }
01482     // toggle KPopupMenu
01483     mPopup->setItemChecked( mTotalPop, isTotalActive() );
01484 
01485   } else kdDebug(5006) << "unknown column:" << column << endl;
01486 
01487   // toggles the switches of the mainwin
01488   emit columnsChanged();
01489 }
01490 
01491 //-----------------------------------------------------------------------------
01492 void KMFolderTree::slotToggleUnreadColumn()
01493 {
01494   toggleColumn(unread);
01495 }
01496 
01497 //-----------------------------------------------------------------------------
01498 void KMFolderTree::slotToggleTotalColumn()
01499 {
01500   // activate the total-column and force the folders to be opened
01501   toggleColumn(total, true);
01502 }
01503 
01504 //-----------------------------------------------------------------------------
01505 bool KMFolderTree::eventFilter( QObject *o, QEvent *e )
01506 {
01507   if ( e->type() == QEvent::MouseButtonPress &&
01508       static_cast<QMouseEvent*>(e)->button() == RightButton &&
01509       o->isA("QHeader") )
01510   {
01511     mPopup->popup( static_cast<QMouseEvent*>(e)->globalPos() );
01512     return true;
01513   }
01514   return KFolderTree::eventFilter(o, e);
01515 }
01516 
01517 //-----------------------------------------------------------------------------
01518 void KMFolderTree::slotCheckMail()
01519 {
01520   if (!currentItem())
01521     return;
01522   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(currentItem());
01523   KMFolder* folder = fti->folder();
01524   if (folder && folder->folderType() == KMFolderTypeImap)
01525   {
01526     KMAccount* acct = static_cast<KMFolderImap*>(folder->storage())->account();
01527     kmkernel->acctMgr()->singleCheckMail(acct, true);
01528   }
01529 }
01530 
01531 //-----------------------------------------------------------------------------
01532 void KMFolderTree::slotNewMessageToMailingList()
01533 {
01534   KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>( currentItem() );
01535   if ( !fti || !fti->folder() )
01536     return;
01537   KMCommand *command = new KMMailingListPostCommand( this, fti->folder() );
01538   command->start();
01539 }
01540 
01541 //-----------------------------------------------------------------------------
01542 void KMFolderTree::createFolderList( QStringList *str,
01543                                      QValueList<QGuardedPtr<KMFolder> > *folders,
01544                                      bool localFolders,
01545                                      bool imapFolders,
01546                                      bool dimapFolders,
01547                                      bool searchFolders,
01548                                      bool includeNoContent,
01549                                      bool includeNoChildren )
01550 {
01551   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
01552   {
01553     KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
01554     if (!fti || !fti->folder()) continue;
01555     // type checks
01556     KMFolder* folder = fti->folder();
01557     if (!imapFolders && folder->folderType() == KMFolderTypeImap) continue;
01558     if (!dimapFolders && folder->folderType() == KMFolderTypeCachedImap) continue;
01559     if (!localFolders && (folder->folderType() == KMFolderTypeMbox ||
01560                           folder->folderType() == KMFolderTypeMaildir)) continue;
01561     if (!searchFolders && folder->folderType() == KMFolderTypeSearch) continue;
01562     if (!includeNoContent && folder->noContent()) continue;
01563     if (!includeNoChildren && folder->noChildren()) continue;
01564     QString prefix;
01565     prefix.fill( ' ', 2 * fti->depth() );
01566     str->append(prefix + fti->text(0));
01567     folders->append(fti->folder());
01568   }
01569 }
01570 
01571 //-----------------------------------------------------------------------------
01572 void KMFolderTree::slotResetFolderList( QListViewItem* item, bool startList )
01573 {
01574   if ( !item )
01575     item = currentItem();
01576 
01577   KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>( item );
01578   if ( fti && fti->folder() &&
01579        fti->folder()->folderType() == KMFolderTypeImap )
01580   {
01581     KMFolderImap *folder = static_cast<KMFolderImap*>( fti->folder()->storage() );
01582     folder->setSubfolderState( KMFolderImap::imapNoInformation );
01583     if ( startList )
01584       folder->listDirectory();
01585   }
01586 }
01587 
01588 //-----------------------------------------------------------------------------
01589 void KMFolderTree::showFolder( KMFolder* folder )
01590 {
01591   if ( !folder ) return;
01592   QListViewItem* item = indexOfFolder( folder );
01593   if ( item )
01594   {
01595     doFolderSelected( item );
01596     ensureItemVisible( item );
01597   }
01598 }
01599 
01600 #include "kmfoldertree.moc"
01601 
KDE Logo
This file is part of the documentation for kmail Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 23 22:43:48 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003