kmail

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 "kmfolder.h"
00010 #include "kmfolderimap.h"
00011 #include "kmfoldercachedimap.h"
00012 #include "kmfolderdia.h"
00013 #include "kmheaders.h"
00014 #include "kmmainwidget.h"
00015 #include "kmailicalifaceimpl.h"
00016 #include "accountmanager.h"
00017 using KMail::AccountManager;
00018 #include "globalsettings.h"
00019 #include "kmcommands.h"
00020 #include "foldershortcutdialog.h"
00021 #include "expirypropertiesdialog.h"
00022 #include "newfolderdialog.h"
00023 #include "acljobs.h"
00024 #include "messagecopyhelper.h"
00025 using KMail::MessageCopyHelper;
00026 #include "favoritefolderview.h"
00027 #include "folderviewtooltip.h"
00028 using KMail::FolderViewToolTip;
00029 
00030 #include <maillistdrag.h>
00031 using namespace KPIM;
00032 
00033 #include <kapplication.h>
00034 #include <kglobalsettings.h>
00035 #include <kiconloader.h>
00036 #include <kmessagebox.h>
00037 #include <kconfig.h>
00038 #include <kpopupmenu.h>
00039 #include <kdebug.h>
00040 
00041 #include <qpainter.h>
00042 #include <qcursor.h>
00043 #include <qregexp.h>
00044 #include <qpopupmenu.h>
00045 
00046 #include <unistd.h>
00047 #include <assert.h>
00048 
00049 #include <X11/Xlib.h>
00050 #include <fixx11h.h>
00051 
00052 //=============================================================================
00053 
00054 KMFolderTreeItem::KMFolderTreeItem( KFolderTree *parent, const QString & name,
00055                                     KFolderTreeItem::Protocol protocol )
00056   : QObject( parent, name.latin1() ),
00057     KFolderTreeItem( parent, name, protocol, Root ),
00058     mFolder( 0 ), mNeedsRepaint( true )
00059 {
00060   init();
00061   setPixmap( 0, normalIcon( iconSize() ) );
00062 }
00063 
00064 //-----------------------------------------------------------------------------
00065 KMFolderTreeItem::KMFolderTreeItem( KFolderTree *parent, const QString & name,
00066                     KMFolder* folder )
00067   : QObject( parent, name.latin1() ),
00068     KFolderTreeItem( parent, name ),
00069     mFolder( folder ), mNeedsRepaint( true )
00070 {
00071   init();
00072   setPixmap( 0, normalIcon( iconSize() ) );
00073 }
00074 
00075 //-----------------------------------------------------------------------------
00076 KMFolderTreeItem::KMFolderTreeItem( KFolderTreeItem *parent, const QString & name,
00077                     KMFolder* folder )
00078   : QObject( 0, name.latin1() ),
00079     KFolderTreeItem( parent, name ),
00080     mFolder( folder ), mNeedsRepaint( true )
00081 {
00082   init();
00083   setPixmap( 0, normalIcon( iconSize() ) );
00084 }
00085 
00086 KMFolderTreeItem::~KMFolderTreeItem()
00087 {
00088 }
00089 
00090 static KFolderTreeItem::Protocol protocolFor( KMFolderType t ) {
00091   switch ( t ) {
00092   case KMFolderTypeImap:
00093     return KFolderTreeItem::Imap;
00094   case KMFolderTypeCachedImap:
00095     return KFolderTreeItem::CachedImap;
00096   case KMFolderTypeMbox:
00097   case KMFolderTypeMaildir:
00098     return KFolderTreeItem::Local;
00099   case KMFolderTypeSearch:
00100     return KFolderTreeItem::Search;
00101   default:
00102     return KFolderTreeItem::NONE;
00103   }
00104 }
00105 
00106 QPixmap KMFolderTreeItem::normalIcon(int size) const
00107 {
00108   QString icon;
00109   if ( (!mFolder && type() == Root) || useTopLevelIcon() ) {
00110     switch ( protocol() ) {
00111       case KFolderTreeItem::Imap:
00112       case KFolderTreeItem::CachedImap:
00113       case KFolderTreeItem::News:
00114         icon = "server"; break;
00115       case KFolderTreeItem::Search:
00116         icon = "viewmag";break;
00117       default:
00118         icon = "folder";break;
00119     }
00120   } else {
00121     // special folders
00122     switch ( type() ) {
00123       case Inbox: icon = "folder_inbox"; break;
00124       case Outbox: icon = "folder_outbox"; break;
00125       case SentMail: icon = "folder_sent_mail"; break;
00126       case Trash: icon = "trashcan_empty"; break;
00127       case Drafts: icon = "edit"; break;
00128       case Templates: icon = "filenew"; break;
00129       default:
00130       {
00131         //If not a resource folder don't try to use icalIface folder pixmap
00132         if(kmkernel->iCalIface().isResourceFolder( mFolder ))
00133           icon = kmkernel->iCalIface().folderPixmap( type() );
00134         break;
00135       }
00136     }
00137     // non-root search folders
00138     if ( protocol() == KMFolderTreeItem::Search ) {
00139       icon = "mail_find";
00140     }
00141     if ( mFolder && mFolder->noContent() ) {
00142       icon = "folder_grey";
00143     }
00144   }
00145 
00146   if ( icon.isEmpty() )
00147     icon = "folder";
00148 
00149   if (mFolder && mFolder->useCustomIcons() ) {
00150     icon = mFolder->normalIconPath();
00151   }
00152   KIconLoader * il = KGlobal::instance()->iconLoader();
00153   QPixmap pm = il->loadIcon( icon, KIcon::Small, size,
00154                              KIcon::DefaultState, 0, true );
00155   if ( mFolder && pm.isNull() ) {
00156       pm = il->loadIcon( mFolder->normalIconPath(), KIcon::Small, size,
00157                          KIcon::DefaultState, 0, true );
00158   }
00159 
00160   return pm;
00161 }
00162 
00163 QPixmap KMFolderTreeItem::unreadIcon(int size) const
00164 {
00165   QPixmap pm;
00166 
00167   if ( !mFolder || useTopLevelIcon() || mFolder->isSystemFolder() ||
00168        kmkernel->folderIsTrash( mFolder ) ||
00169        kmkernel->folderIsTemplates( mFolder ) ||
00170        kmkernel->folderIsDraftOrOutbox( mFolder ) )
00171     pm = normalIcon( size );
00172 
00173   KIconLoader * il = KGlobal::instance()->iconLoader();
00174   if ( mFolder && mFolder->useCustomIcons() ) {
00175     pm = il->loadIcon( mFolder->unreadIconPath(), KIcon::Small, size,
00176                        KIcon::DefaultState, 0, true );
00177     if ( pm.isNull() )
00178       pm = il->loadIcon( mFolder->normalIconPath(), KIcon::Small, size,
00179                          KIcon::DefaultState, 0, true );
00180   }
00181   if ( pm.isNull() ) {
00182     if ( mFolder && mFolder->noContent() ) {
00183       pm = il->loadIcon( "folder_grey_open", KIcon::Small, size,
00184                          KIcon::DefaultState, 0, true );
00185     } else {
00186       if( kmkernel->iCalIface().isResourceFolder( mFolder ) )
00187         pm = il->loadIcon( kmkernel->iCalIface().folderPixmap( type() ),
00188                          KIcon::Small, size, KIcon::DefaultState, 0, true );
00189       if ( pm.isNull() )
00190         pm = il->loadIcon( "folder_open", KIcon::Small, size,
00191                            KIcon::DefaultState, 0, true );
00192     }
00193   }
00194 
00195   return pm;
00196 }
00197 
00198 void KMFolderTreeItem::init()
00199 {
00200   if ( !mFolder )
00201     return;
00202 
00203   setProtocol( protocolFor( mFolder->folderType() ) );
00204 
00205   if ( useTopLevelIcon() )
00206     setType(Root);
00207   else {
00208     if ( mFolder == kmkernel->inboxFolder() )
00209       setType( Inbox );
00210     else if ( kmkernel->folderIsDraftOrOutbox( mFolder ) ) {
00211       if ( mFolder == kmkernel->outboxFolder() )
00212         setType( Outbox );
00213       else
00214         setType( Drafts );
00215     }
00216     else if ( kmkernel->folderIsSentMailFolder( mFolder ) )
00217       setType( SentMail );
00218     else if ( kmkernel->folderIsTrash( mFolder ) )
00219       setType( Trash );
00220     else if ( kmkernel->folderIsTemplates( mFolder ) )
00221       setType( Templates );
00222     else if( kmkernel->iCalIface().isResourceFolder(mFolder) )
00223       setType( kmkernel->iCalIface().folderType(mFolder) );
00224     // System folders on dimap or imap which are not resource folders are
00225     // inboxes. Urgs.
00226     if ( mFolder->isSystemFolder() &&
00227         !kmkernel->iCalIface().isResourceFolder( mFolder) &&
00228          ( mFolder->folderType() == KMFolderTypeImap
00229         || mFolder->folderType() == KMFolderTypeCachedImap ) )
00230       setType( Inbox );
00231   }
00232   if ( !mFolder->isSystemFolder() )
00233     setRenameEnabled( 0, false );
00234 
00235   KMFolderTree* tree = dynamic_cast<KMFolderTree*>( listView() );
00236   if ( tree )
00237     tree->insertIntoFolderToItemMap( mFolder, this );
00238 }
00239 
00240 void KMFolderTreeItem::adjustUnreadCount( int newUnreadCount ) {
00241   // adjust the icons if the folder is now newly unread or
00242   // now newly not-unread
00243   if ( newUnreadCount != 0 && unreadCount() == 0 )
00244     setPixmap( 0, unreadIcon( iconSize() ) );
00245   if ( unreadCount() != 0 && newUnreadCount == 0 )
00246     setPixmap( 0, normalIcon( iconSize() ) );
00247 
00248   setUnreadCount( newUnreadCount );
00249 }
00250 
00251 void KMFolderTreeItem::slotIconsChanged()
00252 {
00253   kdDebug(5006) << k_funcinfo << endl;
00254   // this is prone to change, so better check
00255   KFolderTreeItem::Type newType = type();
00256   if( kmkernel->iCalIface().isResourceFolder( mFolder ) )
00257     newType = kmkernel->iCalIface().folderType(mFolder);
00258 
00259   // reload the folder tree if the type changed, needed because of the
00260   // various type-dependent folder hiding options
00261   if ( type() != newType )
00262     static_cast<KMFolderTree*>( listView() )->delayedReload();
00263   setType( newType );
00264 
00265   if ( unreadCount() > 0 )
00266     setPixmap( 0, unreadIcon( iconSize() ) );
00267   else
00268     setPixmap( 0, normalIcon( iconSize() ) );
00269   emit iconChanged( this );
00270   repaint();
00271 }
00272 
00273 void KMFolderTreeItem::slotNameChanged()
00274 {
00275   setText( 0, mFolder->label() );
00276   emit nameChanged( this );
00277   repaint();
00278 }
00279 
00280 void KMFolderTreeItem::slotNoContentChanged()
00281 {
00282   // reload the folder tree if the no content state changed, needed because
00283   // we hide no-content folders if their child nodes are hidden
00284   QTimer::singleShot( 0, static_cast<KMFolderTree*>( listView() ), SLOT(reload()) );
00285 }
00286 
00287 //-----------------------------------------------------------------------------
00288 bool KMFolderTreeItem::acceptDrag(QDropEvent* e) const
00289 {
00290   // Do not allow drags from the favorite folder view, as they don't really
00291   // make sense and do not work.
00292   KMMainWidget *mainWidget = static_cast<KMFolderTree*>( listView() )->mainWidget();
00293   assert( mainWidget );
00294   if ( mainWidget->favoriteFolderView() &&
00295        e->source() == mainWidget->favoriteFolderView()->viewport() )
00296     return false;
00297 
00298   if ( protocol() == KFolderTreeItem::Search )
00299     return false; // nothing can be dragged into search folders
00300 
00301   if ( e->provides( KPIM::MailListDrag::format() ) ) {
00302     if ( !mFolder || mFolder->moveInProgress() || mFolder->isReadOnly() ||
00303         (mFolder->noContent() && childCount() == 0) ||
00304         (mFolder->noContent() && isOpen()) ) {
00305       return false;
00306     }
00307     else {
00308       return true;
00309     }
00310   } else if ( e->provides("application/x-qlistviewitem") ) {
00311     // wtf: protocol() is NONE instead of Local for the local root folder
00312     if ( !mFolder && protocol() == KFolderTreeItem::NONE && type() == KFolderTreeItem::Root )
00313       return true; // local top-level folder
00314     if ( !mFolder || mFolder->isReadOnly() || mFolder->noContent() )
00315       return false;
00316     return true;
00317   }
00318   return false;
00319 }
00320 
00321 //-----------------------------------------------------------------------------
00322 void KMFolderTreeItem::slotShowExpiryProperties()
00323 {
00324   if ( !mFolder )
00325     return;
00326 
00327   KMFolderTree* tree = static_cast<KMFolderTree*>( listView() );
00328   KMail::ExpiryPropertiesDialog *dlg =
00329     new KMail::ExpiryPropertiesDialog( tree, mFolder );
00330   dlg->show();
00331 }
00332 
00333 
00334 //-----------------------------------------------------------------------------
00335 void KMFolderTreeItem::properties()
00336 {
00337   if ( !mFolder )
00338     return;
00339 
00340   KMail::FolderTreeBase* tree = static_cast<KMail::FolderTreeBase*>( listView() );
00341   tree->mainWidget()->modifyFolder( this );
00342   //Nothing here the above may actually delete this KMFolderTreeItem
00343 }
00344 
00345 //-----------------------------------------------------------------------------
00346 void KMFolderTreeItem::assignShortcut()
00347 {
00348   if ( !mFolder )
00349     return;
00350 
00351   KMail::FolderShortcutDialog *shorty =
00352     new KMail::FolderShortcutDialog( mFolder,
00353               kmkernel->getKMMainWidget(),
00354               listView() );
00355   shorty->exec();
00356   delete shorty;
00357 }
00358 
00359 //-----------------------------------------------------------------------------
00360 void KMFolderTreeItem::updateCount()
00361 {
00362     if ( !folder() ) {
00363       setTotalCount( -1 );
00364       return;
00365     }
00366     KMail::FolderTreeBase* tree = dynamic_cast<KMail::FolderTreeBase*>( listView() );
00367     if ( !tree ) return;
00368 
00369     tree->slotUpdateCounts( folder(), true /* force update */ );
00370 }
00371 
00372 
00373 //=============================================================================
00374 
00375 
00376 KMFolderTree::KMFolderTree( KMMainWidget *mainWidget, QWidget *parent,
00377                             const char *name )
00378   : KMail::FolderTreeBase( mainWidget, parent, name )
00379   , mUpdateTimer( 0, "mUpdateTimer" )
00380   , autoopen_timer( 0, "autoopen_timer" )
00381 {
00382   oldSelected = 0;
00383   oldCurrent = 0;
00384   mLastItem = 0;
00385   dropItem = 0;
00386   mMainWidget = mainWidget;
00387   mReloading = false;
00388   mCutFolder = false;
00389 
00390   mUpdateCountTimer= new QTimer( this, "mUpdateCountTimer" );
00391 
00392   setDragEnabled( true );
00393   addAcceptableDropMimetype( "application/x-qlistviewitem", false );
00394 
00395   setSelectionModeExt( Extended );
00396 
00397   int namecol = addColumn( i18n("Folder"), 250 );
00398   header()->setStretchEnabled( true, namecol );
00399   setResizeMode( QListView::NoColumn );
00400   // connect
00401   connectSignals();
00402 
00403   // popup to switch columns
00404   header()->setClickEnabled(true);
00405   header()->installEventFilter(this);
00406   mPopup = new KPopupMenu(this);
00407   mPopup->insertTitle(i18n("View Columns"));
00408   mPopup->setCheckable(true);
00409   mUnreadPop = mPopup->insertItem(i18n("Unread Column"), this, SLOT(slotToggleUnreadColumn()));
00410   mTotalPop = mPopup->insertItem(i18n("Total Column"), this, SLOT(slotToggleTotalColumn()));
00411   mSizePop = mPopup->insertItem(i18n("Size Column"), this, SLOT(slotToggleSizeColumn()));
00412 
00413   connect( this, SIGNAL( triggerRefresh() ),
00414            this, SLOT( refresh() ) );
00415 
00416   new FolderViewToolTip( this );
00417 }
00418 
00419 //-----------------------------------------------------------------------------
00420 // connects all needed signals to their slots
00421 void KMFolderTree::connectSignals()
00422 {
00423   connect( mUpdateCountTimer, SIGNAL(timeout()),
00424           this, SLOT(slotUpdateCountTimeout()) );
00425 
00426   connect(&mUpdateTimer, SIGNAL(timeout()),
00427           this, SLOT(delayedUpdate()));
00428 
00429   connect(kmkernel->folderMgr(), SIGNAL(changed()),
00430           this, SLOT(doFolderListChanged()));
00431 
00432   connect(kmkernel->folderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00433           this, SLOT(slotFolderRemoved(KMFolder*)));
00434 
00435   connect(kmkernel->folderMgr(), SIGNAL(folderMoveOrCopyOperationFinished()),
00436       this, SLOT(slotFolderMoveOrCopyOperationFinished()));
00437 
00438   connect(kmkernel->imapFolderMgr(), SIGNAL(changed()),
00439           this, SLOT(doFolderListChanged()));
00440 
00441   connect(kmkernel->imapFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00442           this, SLOT(slotFolderRemoved(KMFolder*)));
00443 
00444   connect(kmkernel->dimapFolderMgr(), SIGNAL(changed()),
00445           this, SLOT(doFolderListChanged()));
00446 
00447   connect(kmkernel->dimapFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00448           this, SLOT(slotFolderRemoved(KMFolder*)));
00449 
00450   connect(kmkernel->searchFolderMgr(), SIGNAL(changed()),
00451           this, SLOT(doFolderListChanged()));
00452 
00453   connect(kmkernel->acctMgr(), SIGNAL(accountRemoved(KMAccount*)),
00454           this, SLOT(slotAccountRemoved(KMAccount*)));
00455 
00456   connect(kmkernel->acctMgr(), SIGNAL(accountAdded(KMAccount*)),
00457           this, SLOT(slotUnhideLocalInbox()));
00458 
00459   connect(kmkernel->searchFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00460           this, SLOT(slotFolderRemoved(KMFolder*)));
00461 
00462   connect( &autoopen_timer, SIGNAL( timeout() ),
00463            this, SLOT( openFolder() ) );
00464 
00465   connect( this, SIGNAL( contextMenuRequested( QListViewItem*, const QPoint &, int ) ),
00466            this, SLOT( slotContextMenuRequested( QListViewItem*, const QPoint & ) ) );
00467 
00468   connect( this, SIGNAL( expanded( QListViewItem* ) ),
00469            this, SLOT( slotFolderExpanded( QListViewItem* ) ) );
00470 
00471   connect( this, SIGNAL( collapsed( QListViewItem* ) ),
00472            this, SLOT( slotFolderCollapsed( QListViewItem* ) ) );
00473 
00474   connect( this, SIGNAL( itemRenamed( QListViewItem*, int, const QString &)),
00475            this, SLOT( slotRenameFolder( QListViewItem*, int, const QString &)));
00476 
00477   connect( this, SIGNAL(folderSelected(KMFolder*)), SLOT(updateCopyActions()) );
00478 }
00479 
00480 //-----------------------------------------------------------------------------
00481 void KMFolderTree::readConfig (void)
00482 {
00483   KConfig* conf = KMKernel::config();
00484 
00485   readColorConfig();
00486 
00487   // Custom/Ssystem font support
00488   {
00489     KConfigGroupSaver saver(conf, "Fonts");
00490     if (!conf->readBoolEntry("defaultFonts",true)) {
00491       QFont folderFont( KGlobalSettings::generalFont() );
00492       setFont(conf->readFontEntry("folder-font", &folderFont));
00493     }
00494     else
00495       setFont(KGlobalSettings::generalFont());
00496   }
00497 
00498   // restore the layout
00499   restoreLayout(conf, "Geometry");
00500 }
00501 
00502 //-----------------------------------------------------------------------------
00503 // Save the configuration file
00504 void KMFolderTree::writeConfig()
00505 {
00506   // save the current state of the folders
00507   for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00508     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00509     if (fti)
00510       writeIsListViewItemOpen(fti);
00511   }
00512 
00513   // save the current layout
00514   saveLayout(KMKernel::config(), "Geometry");
00515 }
00516 
00517 //-----------------------------------------------------------------------------
00518 // Updates the count of unread messages (count of unread messages
00519 // is now cached in KMails config file)
00520 void KMFolderTree::updateUnreadAll()
00521 {
00522   bool upd = isUpdatesEnabled();
00523   setUpdatesEnabled(false);
00524 
00525   KMFolderDir* fdir;
00526   KMFolderNode* folderNode;
00527   KMFolder* folder;
00528 
00529   fdir = &kmkernel->folderMgr()->dir();
00530   for (folderNode = fdir->first();
00531     folderNode != 0;
00532     folderNode =fdir->next())
00533   {
00534     if (!folderNode->isDir()) {
00535       folder = static_cast<KMFolder*>(folderNode);
00536 
00537       folder->open("updateunread");
00538       folder->countUnread();
00539       folder->close("updateunread");
00540     }
00541   }
00542 
00543   setUpdatesEnabled(upd);
00544 }
00545 
00546 //-----------------------------------------------------------------------------
00547 // Reload the tree of items in the list view
00548 void KMFolderTree::reload(bool openFolders)
00549 {
00550   if ( mReloading ) {
00551     // no parallel reloads are allowed
00552     kdDebug(5006) << "KMFolderTree::reload - already reloading" << endl;
00553     return;
00554   }
00555   mReloading = true;
00556 
00557   int top = contentsY();
00558   mLastItem = 0;
00559   // invalidate selected drop item
00560   oldSelected = 0;
00561   // remember last
00562   KMFolder* last = currentFolder();
00563   KMFolder* selected = 0;
00564   KMFolder* oldCurrentFolder =
00565     ( oldCurrent ? static_cast<KMFolderTreeItem*>(oldCurrent)->folder(): 0 );
00566   for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00567     KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
00568     writeIsListViewItemOpen( fti );
00569     if ( fti->isSelected() )
00570       selected = fti->folder();
00571   }
00572   mFolderToItem.clear();
00573   clear();
00574 
00575   // construct the root of the local folders
00576   KMFolderTreeItem * root = new KMFolderTreeItem( this, i18n("Local Folders") );
00577   root->setOpen( readIsListViewItemOpen(root) );
00578 
00579   KMFolderDir * fdir = &kmkernel->folderMgr()->dir();
00580   addDirectory(fdir, root);
00581 
00582   fdir = &kmkernel->imapFolderMgr()->dir();
00583   // each imap-account creates it's own root
00584   addDirectory(fdir, 0);
00585 
00586   fdir = &kmkernel->dimapFolderMgr()->dir();
00587   // each dimap-account creates it's own root
00588   addDirectory(fdir, 0);
00589 
00590   // construct the root of the search folder hierarchy:
00591   root = new KMFolderTreeItem( this, i18n("Searches"), KFolderTreeItem::Search );
00592   root->setOpen( readIsListViewItemOpen( root ) );
00593 
00594   fdir = &kmkernel->searchFolderMgr()->dir();
00595   addDirectory(fdir, root);
00596 
00597   if (openFolders)
00598   {
00599     // we open all folders to update the count
00600     mUpdateIterator = QListViewItemIterator (this);
00601     QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
00602   }
00603 
00604   for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00605     KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
00606     if ( !fti || !fti->folder() )
00607       continue;
00608 
00609     disconnect(fti->folder(),SIGNAL(iconsChanged()),
00610                fti,SLOT(slotIconsChanged()));
00611     connect(fti->folder(),SIGNAL(iconsChanged()),
00612             fti,SLOT(slotIconsChanged()));
00613 
00614     disconnect(fti->folder(),SIGNAL(nameChanged()),
00615                fti,SLOT(slotNameChanged()));
00616     connect(fti->folder(),SIGNAL(nameChanged()),
00617             fti,SLOT(slotNameChanged()));
00618 
00619     disconnect( fti->folder(), SIGNAL(noContentChanged()),
00620                 fti, SLOT(slotNoContentChanged()) );
00621     connect( fti->folder(), SIGNAL(noContentChanged()),
00622              fti, SLOT(slotNoContentChanged()) );
00623 
00624     disconnect( fti->folder(), SIGNAL(syncStateChanged()),
00625                 this, SLOT(slotSyncStateChanged()) );
00626     connect( fti->folder(), SIGNAL(syncStateChanged()),
00627              this, SLOT(slotSyncStateChanged()) );
00628 
00629     // we want to be noticed of changes to update the unread/total columns
00630     disconnect(fti->folder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
00631         this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00632     connect(fti->folder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
00633         this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00634     //}
00635 
00636     disconnect(fti->folder(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00637                this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00638     connect(fti->folder(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00639             this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00640     disconnect(fti->folder(), SIGNAL(msgRemoved(KMFolder*)),
00641                this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00642     connect(fti->folder(), SIGNAL(msgRemoved(KMFolder*)),
00643             this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00644 
00645   disconnect(fti->folder(), SIGNAL(folderSizeChanged( KMFolder* )),
00646                this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00647   connect(fti->folder(), SIGNAL(folderSizeChanged( KMFolder* )),
00648                this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00649 
00650 
00651 
00652     disconnect(fti->folder(), SIGNAL(shortcutChanged(KMFolder*)),
00653                mMainWidget, SLOT( slotShortcutChanged(KMFolder*)));
00654     connect(fti->folder(), SIGNAL(shortcutChanged(KMFolder*)),
00655             mMainWidget, SLOT( slotShortcutChanged(KMFolder*)));
00656 
00657 
00658     if (!openFolders)
00659       slotUpdateCounts(fti->folder());
00660 
00661     // populate the size column
00662     fti->setFolderSize( 0 );
00663     fti->setFolderIsCloseToQuota( fti->folder()->storage()->isCloseToQuota() );
00664 
00665   }
00666   ensureVisible(0, top + visibleHeight(), 0, 0);
00667   // if current and selected folder did not change set it again
00668   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
00669   {
00670     if ( last &&
00671          static_cast<KMFolderTreeItem*>( it.current() )->folder() == last )
00672     {
00673       mLastItem = static_cast<KMFolderTreeItem*>( it.current() );
00674       setCurrentItem( it.current() );
00675     }
00676     if ( selected &&
00677          static_cast<KMFolderTreeItem*>( it.current() )->folder() == selected )
00678     {
00679       setSelected( it.current(), true );
00680     }
00681     if ( oldCurrentFolder &&
00682          static_cast<KMFolderTreeItem*>( it.current() )->folder() == oldCurrentFolder )
00683     {
00684       oldCurrent = it.current();
00685     }
00686   }
00687   refresh();
00688   mReloading = false;
00689 }
00690 
00691 //-----------------------------------------------------------------------------
00692 void KMFolderTree::slotUpdateOneCount()
00693 {
00694   if ( !mUpdateIterator.current() ) return;
00695   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(mUpdateIterator.current());
00696   ++mUpdateIterator;
00697   if ( !fti->folder() ) {
00698     // next one please
00699     QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
00700     return;
00701   }
00702 
00703   // open the folder and update the count
00704   bool open = fti->folder()->isOpened();
00705   if (!open) fti->folder()->open("updatecount");
00706   slotUpdateCounts(fti->folder());
00707   // restore previous state
00708   if (!open) fti->folder()->close("updatecount");
00709 
00710   QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
00711 }
00712 
00713 //-----------------------------------------------------------------------------
00714 // Recursively add a directory of folders to the tree of folders
00715 void KMFolderTree::addDirectory( KMFolderDir *fdir, KMFolderTreeItem* parent )
00716 {
00717   for ( KMFolderNode * node = fdir->first() ; node ; node = fdir->next() ) {
00718     if ( node->isDir() )
00719       continue;
00720 
00721     KMFolder * folder = static_cast<KMFolder*>(node);
00722     KMFolderTreeItem * fti = 0;
00723     if (!parent)
00724     {
00725       // create new root-item, but only if this is not the root of a
00726       // "groupware folders only" account
00727       if ( kmkernel->iCalIface().hideResourceAccountRoot( folder ) )
00728         continue;
00729       // it needs a folder e.g. to save it's state (open/close)
00730       fti = new KMFolderTreeItem( this, folder->label(), folder );
00731       fti->setExpandable( true );
00732 
00733       // add child-folders
00734       if (folder && folder->child()) {
00735         addDirectory( folder->child(), fti );
00736       }
00737     } else {
00738       // hide local inbox if unused
00739       if ( kmkernel->inboxFolder() == folder && hideLocalInbox() ) {
00740         connect( kmkernel->inboxFolder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)), SLOT(slotUnhideLocalInbox()) );
00741         continue;
00742       }
00743 
00744       // create new child
00745       fti = new KMFolderTreeItem( parent, folder->label(), folder );
00746       // set folders explicitely to exandable when they have children
00747       // this way we can do a listing for IMAP folders when the user expands them
00748       // even when the child folders are not created yet
00749       if ( folder->storage()->hasChildren() == FolderStorage::HasChildren ) {
00750         fti->setExpandable( true );
00751       } else {
00752         fti->setExpandable( false );
00753       }
00754 
00755       // add child-folders
00756       if (folder && folder->child()) {
00757         addDirectory( folder->child(), fti );
00758       }
00759 
00760       // Check if this is an IMAP resource folder or a no-content parent only
00761       // containing groupware folders
00762       if ( (kmkernel->iCalIface().hideResourceFolder( folder ) || folder->noContent())
00763             && fti->childCount() == 0 ) {
00764         // It is
00765         removeFromFolderToItemMap( folder );
00766         delete fti;
00767         // still, it might change in the future, so we better check the change signals
00768         connect ( folder, SIGNAL(noContentChanged()), SLOT(delayedReload()) );
00769         continue;
00770       }
00771 
00772       connect (fti, SIGNAL(iconChanged(KMFolderTreeItem*)),
00773           this, SIGNAL(iconChanged(KMFolderTreeItem*)));
00774       connect (fti, SIGNAL(nameChanged(KMFolderTreeItem*)),
00775           this, SIGNAL(nameChanged(KMFolderTreeItem*)));
00776     }
00777     // restore last open-state
00778     fti->setOpen( readIsListViewItemOpen(fti) );
00779   } // for-end
00780 }
00781 
00782 //-----------------------------------------------------------------------------
00783 // Initiate a delayed refresh of the tree
00784 void KMFolderTree::refresh()
00785 {
00786   mUpdateTimer.changeInterval(200);
00787 }
00788 
00789 //-----------------------------------------------------------------------------
00790 // Updates the pixmap and extendedLabel information for items
00791 void KMFolderTree::delayedUpdate()
00792 {
00793   bool upd = isUpdatesEnabled();
00794   if ( upd ) {
00795     setUpdatesEnabled(false);
00796 
00797     for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00798       KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00799       if (!fti || !fti->folder())
00800         continue;
00801 
00802       if ( fti->needsRepaint() ) {
00803         fti->repaint();
00804         fti->setNeedsRepaint( false );
00805       }
00806     }
00807     setUpdatesEnabled(upd);
00808   }
00809   mUpdateTimer.stop();
00810 }
00811 
00812 //-----------------------------------------------------------------------------
00813 // Folders have been added/deleted update the tree of folders
00814 void KMFolderTree::doFolderListChanged()
00815 {
00816   reload();
00817 }
00818 
00819 //-----------------------------------------------------------------------------
00820 void KMFolderTree::slotAccountRemoved(KMAccount *)
00821 {
00822   doFolderSelected( firstChild() );
00823 }
00824 
00825 //-----------------------------------------------------------------------------
00826 void KMFolderTree::slotFolderMoveOrCopyOperationFinished()
00827 {
00828   setDragEnabled( true );
00829 }
00830 //-----------------------------------------------------------------------------
00831 void KMFolderTree::slotFolderRemoved(KMFolder *aFolder)
00832 {
00833   QListViewItem *item = indexOfFolder(aFolder);
00834   if (!item) return;
00835   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*> ( item );
00836   if ( oldCurrent == fti )
00837     oldCurrent = 0;
00838   if ( oldSelected == fti )
00839     oldSelected = 0;
00840   if (!fti || !fti->folder()) return;
00841   if (fti == currentItem())
00842   {
00843     QListViewItem *qlvi = fti->itemAbove();
00844     if (!qlvi) qlvi = fti->itemBelow();
00845     doFolderSelected( qlvi );
00846   }
00847   removeFromFolderToItemMap( aFolder );
00848 
00849   if ( dropItem == fti ) { // The removed item is the dropItem
00850     dropItem = 0; // it becomes invalid
00851   }
00852 
00853   delete fti;
00854   updateCopyActions();
00855 }
00856 
00857 //-----------------------------------------------------------------------------
00858 // Methods for navigating folders with the keyboard
00859 void KMFolderTree::prepareItem( KMFolderTreeItem* fti )
00860 {
00861   for ( QListViewItem * parent = fti->parent() ; parent ; parent = parent->parent() )
00862     parent->setOpen( true );
00863   ensureItemVisible( fti );
00864 }
00865 
00866 //-----------------------------------------------------------------------------
00867 void KMFolderTree::nextUnreadFolder()
00868 {
00869     nextUnreadFolder( false );
00870 }
00871 
00872 //-----------------------------------------------------------------------------
00873 void KMFolderTree::nextUnreadFolder(bool confirm)
00874 {
00875   QListViewItemIterator it( currentItem() ? currentItem() : firstChild() );
00876   if ( currentItem() )
00877     ++it; // don't find current item
00878   for ( ; it.current() ; ++it ) {
00879     //check if folder is one to stop on
00880     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00881     if (checkUnreadFolder(fti,confirm)) return;
00882   }
00883   //Now if confirm is true we are doing "ReadOn"
00884   //we have got to the bottom of the folder list
00885   //so we have to start at the top
00886   if (confirm) {
00887     for ( it = firstChild() ; it.current() ; ++it ) {
00888       //check if folder is one to stop on
00889       KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00890       if (checkUnreadFolder(fti,confirm)) return;
00891     }
00892   }
00893 }
00894 
00895 //-----------------------------------------------------------------------------
00896 bool KMFolderTree::checkUnreadFolder (KMFolderTreeItem* fti, bool confirm)
00897 {
00898   if ( fti && fti->folder() && !fti->folder()->ignoreNewMail() &&
00899        ( fti->folder()->countUnread() > 0 ) ) {
00900 
00901     // Don't change into the trash or outbox folders.
00902     if (fti->type() == KFolderTreeItem::Trash ||
00903         fti->type() == KFolderTreeItem::Outbox )
00904       return false;
00905 
00906     if (confirm) {
00907       // Skip drafts, sent mail and templates as well, when reading mail with
00908       // the space bar but not when changing into the next folder with unread
00909       // mail via ctrl+ or ctrl- so we do this only if (confirm == true),
00910       // which means we are doing readOn.
00911       if ( fti->type() == KFolderTreeItem::Drafts ||
00912            fti->type() == KFolderTreeItem::Templates ||
00913            fti->type() == KFolderTreeItem::SentMail )
00914         return false;
00915 
00916       //  warn user that going to next folder - but keep track of
00917       //  whether he wishes to be notified again in "AskNextFolder"
00918       //  parameter (kept in the config file for kmail)
00919       if ( KMessageBox::questionYesNo( this,
00920             i18n( "<qt>Go to the next unread message in folder <b>%1</b>?</qt>" )
00921             .arg( fti->folder()->label() ),
00922             i18n( "Go to Next Unread Message" ),
00923             i18n("Go To"), i18n("Do Not Go To"), // defaults
00924             "AskNextFolder",
00925             false)
00926           == KMessageBox::No ) return true;
00927     }
00928     prepareItem( fti );
00929     blockSignals( true );
00930     doFolderSelected( fti );
00931     blockSignals( false );
00932     emit folderSelectedUnread( fti->folder() );
00933     return true;
00934   }
00935   return false;
00936 }
00937 
00938 //-----------------------------------------------------------------------------
00939 void KMFolderTree::prevUnreadFolder()
00940 {
00941   QListViewItemIterator it( currentItem() ? currentItem() : lastItem() );
00942   if ( currentItem() )
00943     --it; // don't find current item
00944   for ( ; it.current() ; --it ) {
00945     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00946     if (checkUnreadFolder(fti,false)) return;
00947   }
00948 }
00949 
00950 //-----------------------------------------------------------------------------
00951 void KMFolderTree::incCurrentFolder()
00952 {
00953   QListViewItemIterator it( currentItem() );
00954   ++it;
00955   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00956   if (fti) {
00957       prepareItem( fti );
00958       setFocus();
00959       setCurrentItem( fti );
00960   }
00961 }
00962 
00963 //-----------------------------------------------------------------------------
00964 void KMFolderTree::decCurrentFolder()
00965 {
00966   QListViewItemIterator it( currentItem() );
00967   --it;
00968   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00969   if (fti) {
00970       prepareItem( fti );
00971       setFocus();
00972       setCurrentItem( fti );
00973   }
00974 }
00975 
00976 //-----------------------------------------------------------------------------
00977 void KMFolderTree::selectCurrentFolder()
00978 {
00979   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() );
00980   if (fti) {
00981       prepareItem( fti );
00982       doFolderSelected( fti );
00983   }
00984 }
00985 
00986 //-----------------------------------------------------------------------------
00987 KMFolder *KMFolderTree::currentFolder() const
00988 {
00989     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() );
00990     if (fti )
00991         return fti->folder();
00992     else
00993         return 0;
00994 }
00995 
00996 QValueList<QGuardedPtr<KMFolder> > KMFolderTree::selectedFolders()
00997 {
00998   QValueList<QGuardedPtr<KMFolder> > rv;
00999   for ( QListViewItemIterator it( this ); it.current(); ++it ) {
01000     if ( it.current()->isSelected() ) {
01001       KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>( it.current() );
01002       rv.append( fti->folder() );
01003     }
01004   }
01005   return rv;
01006 }
01007 
01008 //-----------------------------------------------------------------------------
01009 // When not dragging and dropping a change in the selected item
01010 // indicates the user has changed the active folder emit a signal
01011 // so that the header list and reader window can be udpated.
01012 void KMFolderTree::doFolderSelected( QListViewItem* qlvi, bool keepSelection )
01013 {
01014   if (!qlvi) return;
01015   if ( mLastItem && mLastItem == qlvi && (keepSelection || selectedFolders().count() == 1) )
01016     return;
01017 
01018   KMFolderTreeItem* fti = static_cast< KMFolderTreeItem* >(qlvi);
01019   KMFolder* folder = 0;
01020   if (fti) folder = fti->folder();
01021 
01022   if (mLastItem && mLastItem != fti && mLastItem->folder()
01023      && (mLastItem->folder()->folderType() == KMFolderTypeImap))
01024   {
01025     KMFolderImap *imapFolder = static_cast<KMFolderImap*>(mLastItem->folder()->storage());
01026     imapFolder->setSelected(false);
01027   }
01028   mLastItem = fti;
01029 
01030   if ( !keepSelection )
01031     clearSelection();
01032   setCurrentItem( qlvi );
01033   if ( !keepSelection )
01034     setSelected( qlvi, true );
01035   ensureItemVisible( qlvi );
01036   if (!folder) {
01037     emit folderSelected(0); // Root has been selected
01038   }
01039   else {
01040     emit folderSelected(folder);
01041     slotUpdateCounts(folder);
01042   }
01043 }
01044 
01045 //-----------------------------------------------------------------------------
01046 void KMFolderTree::resizeEvent(QResizeEvent* e)
01047 {
01048   KConfig* conf = KMKernel::config();
01049 
01050   KConfigGroupSaver saver(conf, "Geometry");
01051   conf->writeEntry(name(), size().width());
01052 
01053   KListView::resizeEvent(e);
01054 }
01055 
01056 //-----------------------------------------------------------------------------
01057 // show context menu
01058 void KMFolderTree::slotContextMenuRequested( QListViewItem *lvi,
01059                                              const QPoint &p )
01060 {
01061   if (!lvi)
01062     return;
01063   setCurrentItem( lvi );
01064 
01065   if (!mMainWidget) return; // safe bet
01066 
01067   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(lvi);
01068   if ( !isSelected( fti ) )
01069     doFolderSelected( fti );
01070   else if ( fti != mLastItem )
01071     doFolderSelected( fti, true );
01072 
01073   if (!fti )
01074     return;
01075 
01076   KPopupMenu *folderMenu = new KPopupMenu;
01077   bool multiFolder = selectedFolders().count() > 1;
01078   if (fti->folder()) folderMenu->insertTitle(fti->folder()->label());
01079 
01080   // outbox specific, but there it's the most used action
01081   if ( (fti->folder() == kmkernel->outboxFolder()) && fti->folder()->count() )
01082         mMainWidget->action("send_queued")->plug( folderMenu );
01083   // Mark all as read is supposedly used often, therefor it is first
01084   if ( fti->folder() && !fti->folder()->noContent() )
01085       mMainWidget->action("mark_all_as_read")->plug( folderMenu );
01086 
01087   /* Treat the special case of the root and account folders */
01088   if ((!fti->folder() || (fti->folder()->noContent()
01089     && !fti->parent())))
01090   {
01091     QString createChild = i18n("&New Subfolder...");
01092     if (!fti->folder()) createChild = i18n("&New Folder...");
01093 
01094     if ( ( fti->folder() || (fti->text(0) != i18n("Searches")) ) && !multiFolder)
01095         folderMenu->insertItem(SmallIconSet("folder_new"),
01096                                createChild, this,
01097                                SLOT(addChildFolder()));
01098 
01099     if (!fti->folder()) {
01100       mMainWidget->action("compact_all_folders")->plug(folderMenu);
01101       mMainWidget->action("expire_all_folders")->plug(folderMenu);
01102     } else if (fti->folder()->folderType() == KMFolderTypeImap) {
01103       folderMenu->insertItem(SmallIconSet("mail_get"), i18n("Check &Mail"),
01104         this,
01105         SLOT(slotCheckMail()));
01106     }
01107   } else { // regular folders
01108 
01109     folderMenu->insertSeparator();
01110     if ( !fti->folder()->noChildren() && !multiFolder ) {
01111       folderMenu->insertItem(SmallIconSet("folder_new"),
01112                              i18n("&New Subfolder..."), this,
01113                              SLOT(addChildFolder()));
01114     }
01115 
01116     // copy folder
01117     QPopupMenu *copyMenu = new QPopupMenu( folderMenu );
01118     folderToPopupMenu( CopyFolder, this, &mMenuToFolder, copyMenu );
01119     folderMenu->insertItem( i18n("&Copy Folder To"), copyMenu );
01120 
01121     if ( fti->folder()->isMoveable() && fti->folder()->canDeleteMessages() )
01122     {
01123       QPopupMenu *moveMenu = new QPopupMenu( folderMenu );
01124       folderToPopupMenu( MoveFolder, this, &mMenuToFolder, moveMenu );
01125       folderMenu->insertItem( i18n("&Move Folder To"), moveMenu );
01126     }
01127 
01128     // Want to be able to display properties for ALL folders,
01129     // so we can edit expiry properties.
01130     // -- smp.
01131     if (!fti->folder()->noContent())
01132     {
01133       if ( !multiFolder )
01134         mMainWidget->action("search_messages")->plug(folderMenu);
01135 
01136       mMainWidget->action( "archive_folder" )->plug( folderMenu );
01137 
01138       mMainWidget->action("compact")->plug(folderMenu);
01139 
01140       if ( GlobalSettings::self()->enableFavoriteFolderView() ) {
01141         folderMenu->insertItem( SmallIconSet("bookmark_add"), i18n("Add to Favorite Folders"),
01142                                 this, SLOT(slotAddToFavorites()) );
01143       }
01144 
01145       folderMenu->insertSeparator();
01146       mMainWidget->action("empty")->plug(folderMenu);
01147       if ( !fti->folder()->isSystemFolder() ) {
01148         mMainWidget->action("delete_folder")->plug(folderMenu);
01149       }
01150       folderMenu->insertSeparator();
01151     }
01152   }
01153 
01154   /* plug in IMAP and DIMAP specific things */
01155   if (fti->folder() &&
01156       (fti->folder()->folderType() == KMFolderTypeImap ||
01157        fti->folder()->folderType() == KMFolderTypeCachedImap ))
01158   {
01159     folderMenu->insertItem(SmallIconSet("bookmark_folder"),
01160         i18n("Serverside Subscription..."), mMainWidget,
01161         SLOT(slotSubscriptionDialog()));
01162     folderMenu->insertItem(SmallIcon("bookmark_folder"),
01163         i18n("Local Subscription..."), mMainWidget,
01164         SLOT(slotLocalSubscriptionDialog()));
01165 
01166     if (!fti->folder()->noContent())
01167     {
01168       mMainWidget->action("refresh_folder")->plug(folderMenu);
01169       if ( fti->folder()->folderType() == KMFolderTypeImap && !multiFolder ) {
01170         folderMenu->insertItem(SmallIconSet("reload"), i18n("Refresh Folder List"), this,
01171             SLOT(slotResetFolderList()));
01172       }
01173     }
01174     if ( fti->folder()->folderType() == KMFolderTypeCachedImap && !multiFolder ) {
01175       KMFolderCachedImap * folder = static_cast<KMFolderCachedImap*>( fti->folder()->storage() );
01176       folderMenu->insertItem( SmallIconSet("wizard"),
01177                               i18n("&Troubleshoot IMAP Cache..."),
01178                               folder, SLOT(slotTroubleshoot()) );
01179     }
01180     folderMenu->insertSeparator();
01181   }
01182 
01183   if ( fti->folder() && fti->folder()->isMailingListEnabled() && !multiFolder ) {
01184     mMainWidget->action("post_message")->plug(folderMenu);
01185   }
01186 
01187   if (fti->folder() && fti->parent() && !multiFolder)
01188   {
01189     folderMenu->insertItem(SmallIconSet("configure_shortcuts"),
01190         i18n("&Assign Shortcut..."),
01191         fti,
01192         SLOT(assignShortcut()));
01193 
01194     if ( !fti->folder()->noContent() && fti->folder()->canDeleteMessages() ) {
01195       folderMenu->insertItem( i18n("Expire..."), fti,
01196                               SLOT( slotShowExpiryProperties() ) );
01197     }
01198     mMainWidget->action("modify")->plug(folderMenu);
01199   }
01200 
01201 
01202   kmkernel->setContextMenuShown( true );
01203   folderMenu->exec (p, 0);
01204   kmkernel->setContextMenuShown( false );
01205   triggerUpdate();
01206   delete folderMenu;
01207   folderMenu = 0;
01208 }
01209 
01210 //-----------------------------------------------------------------------------
01211 void KMFolderTree::contentsMousePressEvent(QMouseEvent * e)
01212 {
01213   // KFolderTree messes around with the selection mode
01214   KListView::contentsMousePressEvent( e );
01215 }
01216 
01217 // If middle button and folder holds mailing-list, create a message to that list
01218 void KMFolderTree::contentsMouseReleaseEvent(QMouseEvent* me)
01219 {
01220   QListViewItem *lvi = currentItem(); // Needed for when branches are clicked on
01221   ButtonState btn = me->button();
01222   doFolderSelected(lvi, true);
01223 
01224   // get underlying folder
01225   KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>(lvi);
01226 
01227   if (!fti || !fti->folder()) {
01228     KFolderTree::contentsMouseReleaseEvent(me);
01229     return;
01230   }
01231 
01232   // react on middle-button only
01233   if (btn != Qt::MidButton) {
01234     KFolderTree::contentsMouseReleaseEvent(me);
01235     return;
01236   }
01237 
01238   if ( fti->folder()->isMailingListEnabled() ) {
01239     KMCommand *command = new KMMailingListPostCommand( this, fti->folder() );
01240     command->start();
01241   }
01242 
01243   KFolderTree::contentsMouseReleaseEvent(me);
01244 }
01245 
01246 // little static helper
01247 static bool folderHasCreateRights( const KMFolder *folder )
01248 {
01249   bool createRights = true; // we don't have acls for local folders yet
01250   if ( folder && folder->folderType() == KMFolderTypeImap ) {
01251     const KMFolderImap *imapFolder = static_cast<const KMFolderImap*>( folder->storage() );
01252     createRights = imapFolder->userRights() == 0 || // hack, we should get the acls
01253       ( imapFolder->userRights() > 0 && ( imapFolder->userRights() & KMail::ACLJobs::Create ) );
01254   } else if ( folder && folder->folderType() == KMFolderTypeCachedImap ) {
01255     const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
01256     createRights = dimapFolder->userRights() == 0 ||
01257       ( dimapFolder->userRights() > 0 && ( dimapFolder->userRights() & KMail::ACLJobs::Create ) );
01258   }
01259   return createRights;
01260 }
01261 
01262 //-----------------------------------------------------------------------------
01263 // Create a subfolder.
01264 // Requires creating the appropriate subdirectory and show a dialog
01265 void KMFolderTree::addChildFolder( KMFolder *folder, QWidget * parent )
01266 {
01267   KMFolder *aFolder = folder;
01268   if ( !aFolder ) {
01269     KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(currentItem());
01270     if (!fti)
01271       return;
01272     aFolder = fti->folder();
01273   }
01274   if (aFolder) {
01275     if (!aFolder->createChildFolder())
01276       return;
01277     if ( !folderHasCreateRights( aFolder ) ) {
01278       // FIXME: change this message to "Cannot create folder under ..." or similar
01279       const QString message = i18n( "<qt>Cannot create folder <b>%1</b> because of insufficient "
01280                                     "permissions on the server. If you think you should be able to create "
01281                                     "subfolders here, ask your administrator to grant you rights to do so."
01282                                     "</qt> " ).arg(aFolder->label());
01283       KMessageBox::error( this, message );
01284       return;
01285     }
01286   }
01287 
01288   if ( parent )
01289     ( new KMail::NewFolderDialog( parent, aFolder ) )->exec();
01290   else
01291     ( new KMail::NewFolderDialog( this, aFolder ) )->show();
01292   return;
01293 /*
01294   KMFolderDir *dir = &(kmkernel->folderMgr()->dir());
01295   if (aFolder)
01296     dir = aFolder->child();
01297 
01298   KMFolderDialog *d =
01299     new KMFolderDialog(0, dir, this, i18n("Create Subfolder") );
01300 
01301   if (d->exec()) { // fti may be deleted here
01302     QListViewItem *qlvi = indexOfFolder( aFolder );
01303     if (qlvi) {
01304       qlvi->setOpen(true);
01305       blockSignals( true );
01306       setCurrentItem( qlvi );
01307       blockSignals( false );
01308     }
01309   }
01310   delete d;
01311   // update if added to root Folder
01312   if (!aFolder || aFolder->noContent()) {
01313      doFolderListChanged();
01314   }
01315   */
01316 }
01317 
01318 //-----------------------------------------------------------------------------
01319 // Returns whether a folder directory should be open as specified in the
01320 // config file.
01321 bool KMFolderTree::readIsListViewItemOpen(KMFolderTreeItem *fti)
01322 {
01323   KConfig* config = KMKernel::config();
01324   KMFolder *folder = fti->folder();
01325   QString name;
01326   if (folder)
01327   {
01328     name = "Folder-" + folder->idString();
01329   } else if (fti->type() == KFolderTreeItem::Root)
01330   {
01331     if (fti->protocol() == KFolderTreeItem::NONE) // local root
01332       name = "Folder_local_root";
01333     else if (fti->protocol() == KFolderTreeItem::Search)
01334       name = "Folder_search";
01335     else
01336       return false;
01337   } else {
01338     return false;
01339   }
01340   KConfigGroupSaver saver(config, name);
01341 
01342   return config->readBoolEntry("isOpen", false);
01343 }
01344 
01345 //-----------------------------------------------------------------------------
01346 // Saves open/closed state of a folder directory into the config file
01347 void KMFolderTree::writeIsListViewItemOpen(KMFolderTreeItem *fti)
01348 {
01349   KConfig* config = KMKernel::config();
01350   KMFolder *folder = fti->folder();
01351   QString name;
01352   if (folder && !folder->idString().isEmpty())
01353   {
01354     name = "Folder-" + folder->idString();
01355   } else if (fti->type() == KFolderTreeItem::Root)
01356   {
01357     if (fti->protocol() == KFolderTreeItem::NONE) // local root
01358       name = "Folder_local_root";
01359     else if (fti->protocol() == KFolderTreeItem::Search)
01360       name = "Folder_search";
01361     else
01362       return;
01363   } else {
01364     return;
01365   }
01366   KConfigGroupSaver saver(config, name);
01367   config->writeEntry("isOpen", fti->isOpen() );
01368 }
01369 
01370 
01371 //-----------------------------------------------------------------------------
01372 void KMFolderTree::cleanupConfigFile()
01373 {
01374   if ( childCount() == 0 )
01375     return; // just in case reload wasn't called before
01376   KConfig* config = KMKernel::config();
01377   QStringList existingFolders;
01378   QListViewItemIterator fldIt(this);
01379   QMap<QString,bool> folderMap;
01380   KMFolderTreeItem *fti;
01381   for (QListViewItemIterator fldIt(this); fldIt.current(); fldIt++)
01382   {
01383     fti = static_cast<KMFolderTreeItem*>(fldIt.current());
01384     if (fti && fti->folder())
01385       folderMap.insert(fti->folder()->idString(), true);
01386   }
01387   QStringList groupList = config->groupList();
01388   QString name;
01389   for (QStringList::Iterator grpIt = groupList.begin();
01390     grpIt != groupList.end(); grpIt++)
01391   {
01392     if ((*grpIt).left(7) != "Folder-") continue;
01393     name = (*grpIt).mid(7);
01394     if (folderMap.find(name) == folderMap.end())
01395     {
01396       KMFolder* folder = kmkernel->findFolderById( name );
01397       if ( folder ) {
01398         if ( kmkernel->iCalIface().hideResourceFolder( folder )
01399            ||  kmkernel->iCalIface().hideResourceAccountRoot( folder ) )
01400           continue; // hidden IMAP resource folder, don't delete info
01401         if ( folder->noContent() )
01402           continue; // we hide nocontent folders if they have no child folders
01403         if ( folder == kmkernel->inboxFolder() )
01404           continue; // local inbox can be hidden as well
01405       }
01406 
01407       //KMessageBox::error( 0, "cleanupConfigFile: Deleting group " + *grpIt );
01408       config->deleteGroup(*grpIt, true);
01409       kdDebug(5006) << "Deleting information about folder " << name << endl;
01410     }
01411   }
01412 }
01413 
01414 
01415 //-----------------------------------------------------------------------------
01416 void KMFolderTree::openFolder()
01417 {
01418     autoopen_timer.stop();
01419     if ( dropItem && !dropItem->isOpen() ) {
01420         dropItem->setOpen( true );
01421         dropItem->repaint();
01422     }
01423 }
01424 
01425 static const int autoopenTime = 750;
01426 
01427 //-----------------------------------------------------------------------------
01428 void KMFolderTree::contentsDragEnterEvent( QDragEnterEvent *e )
01429 {
01430   oldCurrent = 0;
01431   oldSelected = 0;
01432 
01433   oldCurrent = currentItem();
01434   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
01435     if ( it.current()->isSelected() )
01436       oldSelected = it.current();
01437 
01438   setFocus();
01439 
01440   QListViewItem *i = itemAt( contentsToViewport(e->pos()) );
01441   if ( i ) {
01442     dropItem = i;
01443     autoopen_timer.start( autoopenTime );
01444   }
01445   else
01446     dropItem = 0;
01447 
01448   e->accept( acceptDrag(e) );
01449 }
01450 
01451 //-----------------------------------------------------------------------------
01452 void KMFolderTree::contentsDragMoveEvent( QDragMoveEvent *e )
01453 {
01454     QPoint vp = contentsToViewport(e->pos());
01455     QListViewItem *i = itemAt( vp );
01456     if ( i ) {
01457         bool dragAccepted = acceptDrag( e );
01458         if ( dragAccepted ) {
01459             setCurrentItem( i );
01460         }
01461 
01462         if ( i != dropItem ) {
01463             autoopen_timer.stop();
01464             dropItem = i;
01465             autoopen_timer.start( autoopenTime );
01466         }
01467 
01468         if ( dragAccepted ) {
01469             e->accept( itemRect(i) );
01470 
01471             switch ( e->action() ) {
01472                 case QDropEvent::Copy:
01473                 break;
01474                 case QDropEvent::Move:
01475                 e->acceptAction();
01476                 break;
01477                 case QDropEvent::Link:
01478                 e->acceptAction();
01479                 break;
01480                 default:
01481                 ;
01482             }
01483         } else {
01484             e->accept( false );
01485         }
01486     } else {
01487         e->accept( false );
01488         autoopen_timer.stop();
01489         dropItem = 0;
01490     }
01491 }
01492 
01493 //-----------------------------------------------------------------------------
01494 void KMFolderTree::contentsDragLeaveEvent( QDragLeaveEvent * )
01495 {
01496     if (!oldCurrent) return;
01497 
01498     autoopen_timer.stop();
01499     dropItem = 0;
01500 
01501     setCurrentItem( oldCurrent );
01502     if ( oldSelected )
01503       setSelected( oldSelected, true );
01504 }
01505 
01506 //-----------------------------------------------------------------------------
01507 void KMFolderTree::contentsDropEvent( QDropEvent *e )
01508 {
01509     autoopen_timer.stop();
01510 
01511     QListViewItem *item = itemAt( contentsToViewport(e->pos()) );
01512     KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01513     // Check that each pointer is not null
01514     for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = mCopySourceFolders.constBegin();
01515       it != mCopySourceFolders.constEnd(); ++it ) {
01516       if ( ! (*it) ) {
01517     fti = 0;
01518     break;
01519       }
01520     }
01521     if (fti && mCopySourceFolders.count() == 1)
01522     {
01523       KMFolder *source = mCopySourceFolders.first();
01524       // if we are dragging to ourselves or to our parent, set fti to 0 so nothing is done
01525       if (source == fti->folder() || source->parent()->owner() == fti->folder()) fti = 0;
01526     }
01527     if (fti && acceptDrag(e) && ( fti != oldSelected || e->source() != mMainWidget->headers()->viewport() ) )
01528     {
01529       if ( e->provides("application/x-qlistviewitem") ) {
01530         int action = dndMode( true /* always ask */ );
01531         if ( (action == DRAG_COPY || action == DRAG_MOVE) && !mCopySourceFolders.isEmpty() ) {
01532           for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = mCopySourceFolders.constBegin();
01533                 it != mCopySourceFolders.constEnd(); ++it ) {
01534             if ( ! (*it)->isMoveable() )
01535               action = DRAG_COPY;
01536           }
01537           moveOrCopyFolder( mCopySourceFolders, fti->folder(), (action == DRAG_MOVE) );
01538         }
01539       } else {
01540         if ( e->source() == mMainWidget->headers()->viewport() ) {
01541           int action;
01542           if ( mMainWidget->headers()->folder() && mMainWidget->headers()->folder()->isReadOnly() )
01543             action = DRAG_COPY;
01544           else
01545             action = dndMode();
01546           // KMHeaders does copy/move itself
01547           if ( action == DRAG_MOVE && fti->folder() )
01548             emit folderDrop( fti->folder() );
01549           else if ( action == DRAG_COPY && fti->folder() )
01550             emit folderDropCopy( fti->folder() );
01551         } else {
01552           handleMailListDrop( e, fti->folder() );
01553         }
01554       }
01555       e->accept( true );
01556     } else
01557       e->accept( false );
01558 
01559     dropItem = 0;
01560 
01561     setCurrentItem( oldCurrent );
01562     if ( oldCurrent) mLastItem = static_cast<KMFolderTreeItem*>(oldCurrent);
01563     if ( oldSelected )
01564     {
01565       clearSelection();
01566       setSelected( oldSelected, true );
01567     }
01568 
01569     mCopySourceFolders.clear();
01570 }
01571 
01572 //-----------------------------------------------------------------------------
01573 void KMFolderTree::slotFolderExpanded( QListViewItem * item )
01574 {
01575   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01576   if ( !fti || !fti->folder() || !fti->folder()->storage() ) return;
01577 
01578   fti->setFolderSize( fti->folder()->storage()->folderSize() );
01579 
01580   if( fti->folder()->folderType() == KMFolderTypeImap )
01581   {
01582     KMFolderImap *folder = static_cast<KMFolderImap*>( fti->folder()->storage() );
01583     // if we should list all folders we limit this to the root folder
01584     if ( !folder->account() || ( !folder->account()->listOnlyOpenFolders() &&
01585          fti->parent() ) )
01586       return;
01587     if ( folder->getSubfolderState() == KMFolderImap::imapNoInformation )
01588     {
01589       // check if all parents are expanded
01590       QListViewItem *parent = item->parent();
01591       while ( parent )
01592       {
01593         if ( !parent->isOpen() )
01594           return;
01595         parent = parent->parent();
01596       }
01597       // the tree will be reloaded after that
01598       bool success = folder->listDirectory();
01599       if (!success) fti->setOpen( false );
01600       if ( fti->childCount() == 0 && fti->parent() )
01601         fti->setExpandable( false );
01602     }
01603   }
01604 }
01605 
01606 
01607 //-----------------------------------------------------------------------------
01608 void KMFolderTree::slotFolderCollapsed( QListViewItem * item )
01609 {
01610   slotResetFolderList( item, false );
01611   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01612   if ( !fti || !fti->folder() || !fti->folder()->storage() ) return;
01613 
01614   fti->setFolderSize( fti->folder()->storage()->folderSize() );
01615 }
01616 
01617 //-----------------------------------------------------------------------------
01618 void KMFolderTree::slotRenameFolder(QListViewItem *item, int col,
01619                 const QString &text)
01620 {
01621 
01622   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01623 
01624   if ((!fti) || (fti && fti->folder() && col != 0 && !currentFolder()->child()))
01625           return;
01626 
01627   QString fldName, oldFldName;
01628 
01629   oldFldName = fti->name(0);
01630 
01631   if (!text.isEmpty())
01632           fldName = text;
01633   else
01634           fldName = oldFldName;
01635 
01636   fldName.replace("/", "");
01637   fldName.replace(QRegExp("^\\."), "");
01638 
01639   if (fldName.isEmpty())
01640           fldName = i18n("unnamed");
01641 
01642   fti->setText(0, fldName);
01643   fti->folder()->rename(fldName, &(kmkernel->folderMgr()->dir()));
01644 }
01645 
01646 //-----------------------------------------------------------------------------
01647 void KMFolderTree::slotUpdateCountsDelayed(KMFolder * folder)
01648 {
01649 //  kdDebug(5006) << "KMFolderTree::slotUpdateCountsDelayed()" << endl;
01650   if ( !mFolderToUpdateCount.contains( folder->idString() ) )
01651   {
01652 //    kdDebug( 5006 )<< "adding " << folder->idString() << " to updateCountList " << endl;
01653     mFolderToUpdateCount.insert( folder->idString(),folder );
01654   }
01655   if ( !mUpdateCountTimer->isActive() )
01656     mUpdateCountTimer->start( 500 );
01657 }
01658 
01659 
01660 void KMFolderTree::slotUpdateCountTimeout()
01661 {
01662 //  kdDebug(5006) << "KMFolderTree::slotUpdateCountTimeout()" << endl;
01663 
01664   QMap<QString,KMFolder*>::iterator it;
01665   for ( it= mFolderToUpdateCount.begin();
01666       it!=mFolderToUpdateCount.end();
01667       ++it )
01668   {
01669     slotUpdateCounts( it.data() );
01670   }
01671   mFolderToUpdateCount.clear();
01672   mUpdateCountTimer->stop();
01673 
01674 }
01675 
01676 void KMFolderTree::updatePopup() const
01677 {
01678    mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
01679    mPopup->setItemChecked( mTotalPop, isTotalActive() );
01680    mPopup->setItemChecked( mSizePop, isSizeActive() );
01681 }
01682 
01683 //-----------------------------------------------------------------------------
01684 void KMFolderTree::toggleColumn(int column, bool openFolders)
01685 {
01686   if (column == unread)
01687   {
01688     // switch unread
01689     if ( isUnreadActive() )
01690     {
01691       removeUnreadColumn();
01692       reload();
01693     } else {
01694       addUnreadColumn( i18n("Unread"), 70 );
01695       reload();
01696     }
01697     // toggle KPopupMenu
01698     mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
01699 
01700   } else if (column == total) {
01701     // switch total
01702     if ( isTotalActive() )
01703     {
01704       removeTotalColumn();
01705       reload();
01706     } else {
01707       addTotalColumn( i18n("Total"), 70 );
01708       reload(openFolders);
01709     }
01710     mPopup->setItemChecked( mTotalPop, isTotalActive() );
01711   } else if (column == foldersize) {
01712     // switch total
01713     if ( isSizeActive() )
01714     {
01715       removeSizeColumn();
01716       reload();
01717     } else {
01718       addSizeColumn( i18n("Size"), 70 );
01719       reload( openFolders );
01720     }
01721     // toggle KPopupMenu
01722     mPopup->setItemChecked( mSizePop, isSizeActive() );
01723 
01724   } else kdDebug(5006) << "unknown column:" << column << endl;
01725 
01726   // toggles the switches of the mainwin
01727   emit columnsChanged();
01728 }
01729 
01730 //-----------------------------------------------------------------------------
01731 void KMFolderTree::slotToggleUnreadColumn()
01732 {
01733   toggleColumn(unread);
01734 }
01735 
01736 //-----------------------------------------------------------------------------
01737 void KMFolderTree::slotToggleTotalColumn()
01738 {
01739   // activate the total-column and force the folders to be opened
01740   toggleColumn(total, true);
01741 }
01742 
01743 //-----------------------------------------------------------------------------
01744 void KMFolderTree::slotToggleSizeColumn()
01745 {
01746   // activate the size-column and force the folders to be opened
01747   toggleColumn(foldersize, true);
01748 }
01749 
01750 
01751 //-----------------------------------------------------------------------------
01752 bool KMFolderTree::eventFilter( QObject *o, QEvent *e )
01753 {
01754   if ( e->type() == QEvent::MouseButtonPress &&
01755       static_cast<QMouseEvent*>(e)->button() == RightButton &&
01756       o->isA("QHeader") )
01757   {
01758     mPopup->popup( static_cast<QMouseEvent*>(e)->globalPos() );
01759     return true;
01760   }
01761   return KFolderTree::eventFilter(o, e);
01762 }
01763 
01764 //-----------------------------------------------------------------------------
01765 void KMFolderTree::slotCheckMail()
01766 {
01767   if (!currentItem())
01768     return;
01769   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(currentItem());
01770   KMFolder* folder = fti->folder();
01771   if (folder && folder->storage() ) {
01772       if ( KMAccount* acct = folder->storage()->account() ) {
01773          kmkernel->acctMgr()->singleCheckMail(acct, true);
01774       }
01775   }
01776 }
01777 
01778 //-----------------------------------------------------------------------------
01779 void KMFolderTree::slotNewMessageToMailingList()
01780 {
01781   KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>( currentItem() );
01782   if ( !fti || !fti->folder() )
01783     return;
01784   KMCommand *command = new KMMailingListPostCommand( this, fti->folder() );
01785   command->start();
01786 }
01787 
01788 //-----------------------------------------------------------------------------
01789 void KMFolderTree::createFolderList( QStringList *str,
01790                                      QValueList<QGuardedPtr<KMFolder> > *folders,
01791                                      bool localFolders,
01792                                      bool imapFolders,
01793                                      bool dimapFolders,
01794                                      bool searchFolders,
01795                                      bool includeNoContent,
01796                                      bool includeNoChildren )
01797 {
01798   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
01799   {
01800     KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
01801     if (!fti || !fti->folder()) continue;
01802     // type checks
01803     KMFolder* folder = fti->folder();
01804     if (!imapFolders && folder->folderType() == KMFolderTypeImap) continue;
01805     if (!dimapFolders && folder->folderType() == KMFolderTypeCachedImap) continue;
01806     if (!localFolders && (folder->folderType() == KMFolderTypeMbox ||
01807                           folder->folderType() == KMFolderTypeMaildir)) continue;
01808     if (!searchFolders && folder->folderType() == KMFolderTypeSearch) continue;
01809     if (!includeNoContent && folder->noContent()) continue;
01810     if (!includeNoChildren && folder->noChildren()) continue;
01811     QString prefix;
01812     prefix.fill( ' ', 2 * fti->depth() );
01813     str->append(prefix + fti->text(0));
01814     folders->append(fti->folder());
01815   }
01816 }
01817 
01818 //-----------------------------------------------------------------------------
01819 void KMFolderTree::slotResetFolderList( QListViewItem* item, bool startList )
01820 {
01821   if ( !item )
01822     item = currentItem();
01823 
01824   KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>( item );
01825   if ( fti && fti->folder() &&
01826        fti->folder()->folderType() == KMFolderTypeImap )
01827   {
01828     KMFolderImap *folder = static_cast<KMFolderImap*>( fti->folder()->storage() );
01829     folder->setSubfolderState( KMFolderImap::imapNoInformation );
01830     if ( startList )
01831       folder->listDirectory();
01832   }
01833 }
01834 
01835 //-----------------------------------------------------------------------------
01836 void KMFolderTree::showFolder( KMFolder* folder )
01837 {
01838   if ( !folder ) return;
01839   QListViewItem* item = indexOfFolder( folder );
01840   if ( item )
01841   {
01842     doFolderSelected( item );
01843     ensureItemVisible( item );
01844   }
01845 }
01846 
01847 //-----------------------------------------------------------------------------
01848 void KMFolderTree::folderToPopupMenu( MenuAction action, QObject *receiver,
01849     KMMenuToFolder *aMenuToFolder, QPopupMenu *menu, QListViewItem *item )
01850 {
01851   while ( menu->count() )
01852   {
01853     QPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup();
01854     if ( popup )
01855       delete popup;
01856     else
01857       menu->removeItemAt( 0 );
01858   }
01859   // connect the signals
01860   if ( action == MoveMessage || action == MoveFolder )
01861   {
01862     disconnect( menu, SIGNAL(activated(int)), receiver,
01863         SLOT(moveSelectedToFolder(int)) );
01864     connect( menu, SIGNAL(activated(int)), receiver,
01865         SLOT(moveSelectedToFolder(int)) );
01866   } else {
01867     disconnect( menu, SIGNAL(activated(int)), receiver,
01868         SLOT(copySelectedToFolder(int)) );
01869     connect( menu, SIGNAL(activated(int)), receiver,
01870         SLOT(copySelectedToFolder(int)) );
01871   }
01872   if ( !item ) {
01873     item = firstChild();
01874 
01875     // avoid a popup menu with the single entry 'Local Folders' if there
01876     // are no IMAP accounts
01877     if ( childCount() == 2 && action != MoveFolder ) { // only 'Local Folders' and 'Searches'
01878       KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>( item );
01879       if ( fti->protocol() == KFolderTreeItem::Search ) {
01880         // skip 'Searches'
01881         item = item->nextSibling();
01882         fti = static_cast<KMFolderTreeItem*>( item );
01883       }
01884       folderToPopupMenu( action, receiver, aMenuToFolder, menu, fti->firstChild() );
01885       return;
01886     }
01887   }
01888 
01889   while ( item )
01890   {
01891     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( item );
01892     if ( fti->protocol() == KFolderTreeItem::Search )
01893     {
01894       // skip search folders
01895       item = item->nextSibling();
01896       continue;
01897     }
01898     QString label = fti->text( 0 );
01899     label.replace( "&","&&" );
01900     if ( fti->firstChild() )
01901     {
01902       // new level
01903       QPopupMenu* popup = new QPopupMenu( menu, "subMenu" );
01904       folderToPopupMenu( action, receiver, aMenuToFolder, popup, fti->firstChild() );
01905       bool subMenu = false;
01906       if ( ( action == MoveMessage || action == CopyMessage ) &&
01907            fti->folder() && !fti->folder()->noContent() )
01908         subMenu = true;
01909       if ( ( action == MoveFolder || action == CopyFolder )
01910           && ( !fti->folder() || ( fti->folder() && !fti->folder()->noChildren() ) ) )
01911         subMenu = true;
01912 
01913       QString sourceFolderName;
01914       KMFolderTreeItem* srcItem = dynamic_cast<KMFolderTreeItem*>( currentItem() );
01915       if ( srcItem )
01916         sourceFolderName = srcItem->text( 0 );
01917 
01918       if ( (action == MoveFolder || action == CopyFolder)
01919               && fti->folder() && fti->folder()->child()
01920               && fti->folder()->child()->hasNamedFolder( sourceFolderName ) ) {
01921         subMenu = false;
01922       }
01923 
01924       if ( subMenu )
01925       {
01926         int menuId;
01927         if ( action == MoveMessage || action == MoveFolder )
01928           menuId = popup->insertItem( i18n("Move to This Folder"), -1, 0 );
01929         else
01930           menuId = popup->insertItem( i18n("Copy to This Folder"), -1, 0 );
01931         popup->insertSeparator( 1 );
01932         aMenuToFolder->insert( menuId, fti->folder() );
01933       }
01934       menu->insertItem( label, popup );
01935     } else
01936     {
01937       // insert an item
01938       int menuId = menu->insertItem( label );
01939       if ( fti->folder() )
01940         aMenuToFolder->insert( menuId, fti->folder() );
01941       bool enabled = (fti->folder() ? true : false);
01942       if ( fti->folder() &&
01943            ( fti->folder()->isReadOnly() || fti->folder()->noContent() ) )
01944         enabled = false;
01945       menu->setItemEnabled( menuId, enabled );
01946     }
01947 
01948     item = item->nextSibling();
01949   }
01950 }
01951 
01952 //-----------------------------------------------------------------------------
01953 void KMFolderTree::moveSelectedToFolder( int menuId )
01954 {
01955   moveOrCopyFolder( selectedFolders(), mMenuToFolder[ menuId ], true /*move*/ );
01956 }
01957 
01958 //-----------------------------------------------------------------------------
01959 void KMFolderTree::copySelectedToFolder( int menuId )
01960 {
01961   moveOrCopyFolder( selectedFolders(), mMenuToFolder[ menuId ], false /*copy, don't move*/ );
01962 }
01963 
01964 //-----------------------------------------------------------------------------
01965 void KMFolderTree::moveOrCopyFolder( QValueList<QGuardedPtr<KMFolder> > sources, KMFolder* destination, bool move )
01966 {
01967   kdDebug(5006) << k_funcinfo << "source: " << sources << " destination: " << destination << " move: " << move << endl;
01968 
01969   // Disable drag during copy operation since it prevents from many crashes
01970   setDragEnabled( false );
01971 
01972   KMFolderDir* parent = &(kmkernel->folderMgr()->dir());
01973   if ( destination )
01974     parent = destination->createChildFolder();
01975 
01976   QStringList sourceFolderNames;
01977 
01978   // check if move/copy is possible at all
01979   for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); it != sources.constEnd(); ++it ) {
01980     KMFolder* source = *it;
01981 
01982     // check if folder with same name already exits
01983     QString sourceFolderName;
01984     if ( source )
01985       sourceFolderName = source->label();
01986 
01987     if ( parent->hasNamedFolder( sourceFolderName ) || sourceFolderNames.contains( sourceFolderName ) ) {
01988       KMessageBox::error( this, i18n("<qt>Cannot move or copy folder <b>%1</b> here because a folder with the same name already exists.</qt>")
01989           .arg( sourceFolderName ) );
01990       setDragEnabled( true );
01991       return;
01992     }
01993     sourceFolderNames.append( sourceFolderName );
01994 
01995     // don't move/copy a folder that's still not completely moved/copied
01996     KMFolder *f = source;
01997     while ( f ) {
01998       if ( f->moveInProgress() ) {
01999         KMessageBox::error( this, i18n("<qt>Cannot move or copy folder <b>%1</b> because it is not completely copied itself.</qt>")
02000             .arg( sourceFolderName ) );
02001         setDragEnabled( true );
02002         return;
02003       }
02004       if ( f->parent() )
02005         f = f->parent()->owner();
02006     }
02007 
02008     QString message =
02009       i18n( "<qt>Cannot move or copy folder <b>%1</b> into a subfolder below itself.</qt>" ).
02010           arg( sourceFolderName );
02011     KMFolderDir* folderDir = parent;
02012     // check that the folder can be moved
02013     if ( source && source->child() )
02014     {
02015       while ( folderDir && ( folderDir != &kmkernel->folderMgr()->dir() ) &&
02016           ( folderDir != source->parent() ) )
02017       {
02018         if ( folderDir->findRef( source ) != -1 )
02019         {
02020           KMessageBox::error( this, message );
02021           setDragEnabled( true );
02022           return;
02023         }
02024         folderDir = folderDir->parent();
02025       }
02026     }
02027 
02028     if( source && source->child() && parent &&
02029         ( parent->path().find( source->child()->path() + "/" ) == 0 ) ) {
02030       KMessageBox::error( this, message );
02031       setDragEnabled( true );
02032       return;
02033     }
02034 
02035     if( source && source->child()
02036         && ( parent == source->child() ) ) {
02037       KMessageBox::error( this, message );
02038       setDragEnabled( true );
02039       return;
02040     }
02041   }
02042 
02043   // check if the source folders are independent of each other
02044   for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); move && it != sources.constEnd(); ++it ) {
02045     KMFolderDir *parentDir = (*it)->child();
02046     if ( !parentDir )
02047       continue;
02048     for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it2 = sources.constBegin(); it2 != sources.constEnd(); ++it2 ) {
02049       if ( *it == *it2 )
02050         continue;
02051       KMFolderDir *childDir = (*it2)->parent();
02052       do {
02053         if ( parentDir == childDir || parentDir->findRef( childDir->owner() ) != -1 ) {
02054           KMessageBox::error( this, i18n("Moving the selected folders is not possible") );
02055           setDragEnabled( true );
02056           return;
02057         }
02058         childDir = childDir->parent();
02059       }
02060       while ( childDir && childDir != &kmkernel->folderMgr()->dir() );
02061     }
02062   }
02063 
02064   // de-select moved source folders (can cause crash due to unGetMsg() in KMHeaders)
02065   if ( move ) {
02066     doFolderSelected( indexOfFolder( destination ), false );
02067     oldCurrent = currentItem();
02068   }
02069 
02070   // do the actual move/copy
02071   for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); it != sources.constEnd(); ++it ) {
02072     KMFolder* source = *it;
02073     if ( move ) {
02074       kdDebug(5006) << "move folder " << (source ? source->label(): "Unknown") << " to "
02075         << ( destination ? destination->label() : "Local Folders" ) << endl;
02076       kmkernel->folderMgr()->moveFolder( source, parent );
02077     } else {
02078       kmkernel->folderMgr()->copyFolder( source, parent );
02079     }
02080   }
02081 }
02082 
02083 QDragObject * KMFolderTree::dragObject()
02084 {
02085   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>
02086       (itemAt(viewport()->mapFromGlobal(QCursor::pos())));
02087   if ( !item || !item->parent() || !item->folder() ) // top-level items or something invalid
02088     return 0;
02089   mCopySourceFolders = selectedFolders();
02090 
02091   QDragObject *drag = KFolderTree::dragObject();
02092   if ( drag )
02093     drag->setPixmap( SmallIcon("folder") );
02094   return drag;
02095 }
02096 
02097 void KMFolderTree::copyFolder()
02098 {
02099   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
02100   if ( item ) {
02101     mCopySourceFolders = selectedFolders();
02102     mCutFolder = false;
02103   }
02104   updateCopyActions();
02105 }
02106 
02107 void KMFolderTree::cutFolder()
02108 {
02109   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
02110   if ( item ) {
02111     mCopySourceFolders = selectedFolders();
02112     mCutFolder = true;
02113   }
02114   updateCopyActions();
02115 }
02116 
02117 void KMFolderTree::pasteFolder()
02118 {
02119   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
02120   if ( !mCopySourceFolders.isEmpty() && item && !mCopySourceFolders.contains( item->folder() ) ) {
02121     moveOrCopyFolder( mCopySourceFolders, item->folder(), mCutFolder );
02122     if ( mCutFolder )
02123       mCopySourceFolders.clear();
02124   }
02125   updateCopyActions();
02126 }
02127 
02128 void KMFolderTree::updateCopyActions()
02129 {
02130   KAction *copy = mMainWidget->action("copy_folder");
02131   KAction *cut = mMainWidget->action("cut_folder");
02132   KAction *paste = mMainWidget->action("paste_folder");
02133   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
02134 
02135   if ( !item ||  !item->folder() ) {
02136     copy->setEnabled( false );
02137     cut->setEnabled( false );
02138   } else {
02139     copy->setEnabled( true );
02140     cut->setEnabled( item->folder()->isMoveable() );
02141   }
02142 
02143   if ( mCopySourceFolders.isEmpty() )
02144     paste->setEnabled( false );
02145   else
02146     paste->setEnabled( true );
02147 }
02148 
02149 void KMFolderTree::slotSyncStateChanged()
02150 {
02151   // Only emit the signal when a selected folder changes, otherwise the folder menu is updated
02152   // too often
02153   QValueList< QGuardedPtr<KMFolder> > folders = selectedFolders();
02154   QValueList< QGuardedPtr<KMFolder> >::const_iterator it = folders.constBegin();
02155   QValueList< QGuardedPtr<KMFolder> >::const_iterator end = folders.constEnd();
02156   while ( it != end ) {
02157     QGuardedPtr<KMFolder> folder = *it;
02158     if ( folder == sender() ) {
02159       emit syncStateChanged();
02160       break;
02161     }
02162     ++it;
02163   }
02164 }
02165 
02166 void KMFolderTree::slotAddToFavorites()
02167 {
02168   KMail::FavoriteFolderView *favView = mMainWidget->favoriteFolderView();
02169   assert( favView );
02170   for ( QListViewItemIterator it( this ); it.current(); ++it ) {
02171     if ( it.current()->isSelected() )
02172       favView->addFolder( static_cast<KMFolderTreeItem*>( it.current() ) );
02173   }
02174 }
02175 
02176 void KMFolderTree::slotUnhideLocalInbox()
02177 {
02178   disconnect( kmkernel->inboxFolder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
02179               this, SLOT(slotUnhideLocalInbox()) );
02180   reload();
02181 }
02182 
02183 void KMFolderTree::delayedReload()
02184 {
02185   QTimer::singleShot( 0, this, SLOT(reload()) );
02186 }
02187 
02188 #include "kmfoldertree.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys