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->userRightsState() != KMail::ACLJobs::Ok || // hack, we should get the acls
01253       ( imapFolder->userRightsState() == KMail::ACLJobs::Ok &&
01254         ( imapFolder->userRights() & KMail::ACLJobs::Create ) );
01255   } else if ( folder && folder->folderType() == KMFolderTypeCachedImap ) {
01256     const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
01257     createRights = dimapFolder->userRightsState() != KMail::ACLJobs::Ok ||
01258       ( dimapFolder->userRightsState() == KMail::ACLJobs::Ok &&
01259         ( dimapFolder->userRights() & KMail::ACLJobs::Create ) );
01260   }
01261   return createRights;
01262 }
01263 
01264 //-----------------------------------------------------------------------------
01265 // Create a subfolder.
01266 // Requires creating the appropriate subdirectory and show a dialog
01267 void KMFolderTree::addChildFolder( KMFolder *folder, QWidget * parent )
01268 {
01269   KMFolder *aFolder = folder;
01270   if ( !aFolder ) {
01271     KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(currentItem());
01272     if (!fti)
01273       return;
01274     aFolder = fti->folder();
01275   }
01276   if (aFolder) {
01277     if (!aFolder->createChildFolder())
01278       return;
01279     if ( !folderHasCreateRights( aFolder ) ) {
01280       const QString message = i18n( "<qt>Cannot create folder under <b>%1</b> because of insufficient "
01281                                     "permissions on the server. If you think you should be able to create "
01282                                     "subfolders here, ask your administrator to grant you rights to do so."
01283                                     "</qt> " ).arg(aFolder->label());
01284       KMessageBox::error( this, message );
01285       return;
01286     }
01287   }
01288 
01289   if ( parent )
01290     ( new KMail::NewFolderDialog( parent, aFolder ) )->exec();
01291   else
01292     ( new KMail::NewFolderDialog( this, aFolder ) )->show();
01293   return;
01294 /*
01295   KMFolderDir *dir = &(kmkernel->folderMgr()->dir());
01296   if (aFolder)
01297     dir = aFolder->child();
01298 
01299   KMFolderDialog *d =
01300     new KMFolderDialog(0, dir, this, i18n("Create Subfolder") );
01301 
01302   if (d->exec()) { // fti may be deleted here
01303     QListViewItem *qlvi = indexOfFolder( aFolder );
01304     if (qlvi) {
01305       qlvi->setOpen(true);
01306       blockSignals( true );
01307       setCurrentItem( qlvi );
01308       blockSignals( false );
01309     }
01310   }
01311   delete d;
01312   // update if added to root Folder
01313   if (!aFolder || aFolder->noContent()) {
01314      doFolderListChanged();
01315   }
01316   */
01317 }
01318 
01319 //-----------------------------------------------------------------------------
01320 // Returns whether a folder directory should be open as specified in the
01321 // config file.
01322 bool KMFolderTree::readIsListViewItemOpen(KMFolderTreeItem *fti)
01323 {
01324   KConfig* config = KMKernel::config();
01325   KMFolder *folder = fti->folder();
01326   QString name;
01327   if (folder)
01328   {
01329     name = "Folder-" + folder->idString();
01330   } else if (fti->type() == KFolderTreeItem::Root)
01331   {
01332     if (fti->protocol() == KFolderTreeItem::NONE) // local root
01333       name = "Folder_local_root";
01334     else if (fti->protocol() == KFolderTreeItem::Search)
01335       name = "Folder_search";
01336     else
01337       return false;
01338   } else {
01339     return false;
01340   }
01341   KConfigGroupSaver saver(config, name);
01342 
01343   return config->readBoolEntry("isOpen", false);
01344 }
01345 
01346 //-----------------------------------------------------------------------------
01347 // Saves open/closed state of a folder directory into the config file
01348 void KMFolderTree::writeIsListViewItemOpen(KMFolderTreeItem *fti)
01349 {
01350   KConfig* config = KMKernel::config();
01351   KMFolder *folder = fti->folder();
01352   QString name;
01353   if (folder && !folder->idString().isEmpty())
01354   {
01355     name = "Folder-" + folder->idString();
01356   } else if (fti->type() == KFolderTreeItem::Root)
01357   {
01358     if (fti->protocol() == KFolderTreeItem::NONE) // local root
01359       name = "Folder_local_root";
01360     else if (fti->protocol() == KFolderTreeItem::Search)
01361       name = "Folder_search";
01362     else
01363       return;
01364   } else {
01365     return;
01366   }
01367   KConfigGroupSaver saver(config, name);
01368   config->writeEntry("isOpen", fti->isOpen() );
01369 }
01370 
01371 
01372 //-----------------------------------------------------------------------------
01373 void KMFolderTree::cleanupConfigFile()
01374 {
01375   if ( childCount() == 0 )
01376     return; // just in case reload wasn't called before
01377   KConfig* config = KMKernel::config();
01378   QStringList existingFolders;
01379   QListViewItemIterator fldIt(this);
01380   QMap<QString,bool> folderMap;
01381   KMFolderTreeItem *fti;
01382   for (QListViewItemIterator fldIt(this); fldIt.current(); fldIt++)
01383   {
01384     fti = static_cast<KMFolderTreeItem*>(fldIt.current());
01385     if (fti && fti->folder())
01386       folderMap.insert(fti->folder()->idString(), true);
01387   }
01388   QStringList groupList = config->groupList();
01389   QString name;
01390   for (QStringList::Iterator grpIt = groupList.begin();
01391     grpIt != groupList.end(); grpIt++)
01392   {
01393     if ((*grpIt).left(7) != "Folder-") continue;
01394     name = (*grpIt).mid(7);
01395     if (folderMap.find(name) == folderMap.end())
01396     {
01397       KMFolder* folder = kmkernel->findFolderById( name );
01398       if ( folder ) {
01399         if ( kmkernel->iCalIface().hideResourceFolder( folder )
01400            ||  kmkernel->iCalIface().hideResourceAccountRoot( folder ) )
01401           continue; // hidden IMAP resource folder, don't delete info
01402         if ( folder->noContent() )
01403           continue; // we hide nocontent folders if they have no child folders
01404         if ( folder == kmkernel->inboxFolder() )
01405           continue; // local inbox can be hidden as well
01406       }
01407 
01408       //KMessageBox::error( 0, "cleanupConfigFile: Deleting group " + *grpIt );
01409       config->deleteGroup(*grpIt, true);
01410       kdDebug(5006) << "Deleting information about folder " << name << endl;
01411     }
01412   }
01413 }
01414 
01415 
01416 //-----------------------------------------------------------------------------
01417 void KMFolderTree::openFolder()
01418 {
01419     autoopen_timer.stop();
01420     if ( dropItem && !dropItem->isOpen() ) {
01421         dropItem->setOpen( true );
01422         dropItem->repaint();
01423     }
01424 }
01425 
01426 static const int autoopenTime = 750;
01427 
01428 //-----------------------------------------------------------------------------
01429 void KMFolderTree::contentsDragEnterEvent( QDragEnterEvent *e )
01430 {
01431   oldCurrent = 0;
01432   oldSelected = 0;
01433 
01434   oldCurrent = currentItem();
01435   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
01436     if ( it.current()->isSelected() )
01437       oldSelected = it.current();
01438 
01439   setFocus();
01440 
01441   QListViewItem *i = itemAt( contentsToViewport(e->pos()) );
01442   if ( i ) {
01443     dropItem = i;
01444     autoopen_timer.start( autoopenTime );
01445   }
01446   else
01447     dropItem = 0;
01448 
01449   e->accept( acceptDrag(e) );
01450 }
01451 
01452 //-----------------------------------------------------------------------------
01453 void KMFolderTree::contentsDragMoveEvent( QDragMoveEvent *e )
01454 {
01455     QPoint vp = contentsToViewport(e->pos());
01456     QListViewItem *i = itemAt( vp );
01457     if ( i ) {
01458         bool dragAccepted = acceptDrag( e );
01459         if ( dragAccepted ) {
01460             setCurrentItem( i );
01461         }
01462 
01463         if ( i != dropItem ) {
01464             autoopen_timer.stop();
01465             dropItem = i;
01466             autoopen_timer.start( autoopenTime );
01467         }
01468 
01469         if ( dragAccepted ) {
01470             e->accept( itemRect(i) );
01471 
01472             switch ( e->action() ) {
01473                 case QDropEvent::Copy:
01474                 break;
01475                 case QDropEvent::Move:
01476                 e->acceptAction();
01477                 break;
01478                 case QDropEvent::Link:
01479                 e->acceptAction();
01480                 break;
01481                 default:
01482                 ;
01483             }
01484         } else {
01485             e->accept( false );
01486         }
01487     } else {
01488         e->accept( false );
01489         autoopen_timer.stop();
01490         dropItem = 0;
01491     }
01492 }
01493 
01494 //-----------------------------------------------------------------------------
01495 void KMFolderTree::contentsDragLeaveEvent( QDragLeaveEvent * )
01496 {
01497     if (!oldCurrent) return;
01498 
01499     autoopen_timer.stop();
01500     dropItem = 0;
01501 
01502     setCurrentItem( oldCurrent );
01503     if ( oldSelected )
01504       setSelected( oldSelected, true );
01505 }
01506 
01507 //-----------------------------------------------------------------------------
01508 void KMFolderTree::contentsDropEvent( QDropEvent *e )
01509 {
01510     autoopen_timer.stop();
01511 
01512     QListViewItem *item = itemAt( contentsToViewport(e->pos()) );
01513     KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01514     // Check that each pointer is not null
01515     for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = mCopySourceFolders.constBegin();
01516       it != mCopySourceFolders.constEnd(); ++it ) {
01517       if ( ! (*it) ) {
01518     fti = 0;
01519     break;
01520       }
01521     }
01522     if (fti && mCopySourceFolders.count() == 1)
01523     {
01524       KMFolder *source = mCopySourceFolders.first();
01525       // if we are dragging to ourselves or to our parent, set fti to 0 so nothing is done
01526       if (source == fti->folder() || source->parent()->owner() == fti->folder()) fti = 0;
01527     }
01528     if (fti && acceptDrag(e) && ( fti != oldSelected || e->source() != mMainWidget->headers()->viewport() ) )
01529     {
01530       if ( e->provides("application/x-qlistviewitem") ) {
01531         int action = dndMode( true /* always ask */ );
01532         if ( (action == DRAG_COPY || action == DRAG_MOVE) && !mCopySourceFolders.isEmpty() ) {
01533           for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = mCopySourceFolders.constBegin();
01534                 it != mCopySourceFolders.constEnd(); ++it ) {
01535             if ( ! (*it)->isMoveable() )
01536               action = DRAG_COPY;
01537           }
01538           moveOrCopyFolder( mCopySourceFolders, fti->folder(), (action == DRAG_MOVE) );
01539         }
01540       } else {
01541         if ( e->source() == mMainWidget->headers()->viewport() ) {
01542           int action;
01543           if ( mMainWidget->headers()->folder() && mMainWidget->headers()->folder()->isReadOnly() )
01544             action = DRAG_COPY;
01545           else
01546             action = dndMode();
01547           // KMHeaders does copy/move itself
01548           if ( action == DRAG_MOVE && fti->folder() )
01549             emit folderDrop( fti->folder() );
01550           else if ( action == DRAG_COPY && fti->folder() )
01551             emit folderDropCopy( fti->folder() );
01552         } else {
01553           handleMailListDrop( e, fti->folder() );
01554         }
01555       }
01556       e->accept( true );
01557     } else
01558       e->accept( false );
01559 
01560     dropItem = 0;
01561 
01562     setCurrentItem( oldCurrent );
01563     if ( oldCurrent) mLastItem = static_cast<KMFolderTreeItem*>(oldCurrent);
01564     if ( oldSelected )
01565     {
01566       clearSelection();
01567       setSelected( oldSelected, true );
01568     }
01569 
01570     mCopySourceFolders.clear();
01571 }
01572 
01573 //-----------------------------------------------------------------------------
01574 void KMFolderTree::slotFolderExpanded( QListViewItem * item )
01575 {
01576   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01577   if ( !fti || !fti->folder() || !fti->folder()->storage() ) return;
01578 
01579   fti->setFolderSize( fti->folder()->storage()->folderSize() );
01580 
01581   if( fti->folder()->folderType() == KMFolderTypeImap )
01582   {
01583     KMFolderImap *folder = static_cast<KMFolderImap*>( fti->folder()->storage() );
01584     // if we should list all folders we limit this to the root folder
01585     if ( !folder->account() || ( !folder->account()->listOnlyOpenFolders() &&
01586          fti->parent() ) )
01587       return;
01588     if ( folder->getSubfolderState() == KMFolderImap::imapNoInformation )
01589     {
01590       // check if all parents are expanded
01591       QListViewItem *parent = item->parent();
01592       while ( parent )
01593       {
01594         if ( !parent->isOpen() )
01595           return;
01596         parent = parent->parent();
01597       }
01598       // the tree will be reloaded after that
01599       bool success = folder->listDirectory();
01600       if (!success) fti->setOpen( false );
01601       if ( fti->childCount() == 0 && fti->parent() )
01602         fti->setExpandable( false );
01603     }
01604   }
01605 }
01606 
01607 
01608 //-----------------------------------------------------------------------------
01609 void KMFolderTree::slotFolderCollapsed( QListViewItem * item )
01610 {
01611   slotResetFolderList( item, false );
01612   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01613   if ( !fti || !fti->folder() || !fti->folder()->storage() ) return;
01614 
01615   fti->setFolderSize( fti->folder()->storage()->folderSize() );
01616 }
01617 
01618 //-----------------------------------------------------------------------------
01619 void KMFolderTree::slotRenameFolder(QListViewItem *item, int col,
01620                 const QString &text)
01621 {
01622 
01623   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01624 
01625   if ((!fti) || (fti && fti->folder() && col != 0 && !currentFolder()->child()))
01626           return;
01627 
01628   QString fldName, oldFldName;
01629 
01630   oldFldName = fti->name(0);
01631 
01632   if (!text.isEmpty())
01633           fldName = text;
01634   else
01635           fldName = oldFldName;
01636 
01637   fldName.replace("/", "");
01638   fldName.replace(QRegExp("^\\."), "");
01639 
01640   if (fldName.isEmpty())
01641           fldName = i18n("unnamed");
01642 
01643   fti->setText(0, fldName);
01644   fti->folder()->rename(fldName, &(kmkernel->folderMgr()->dir()));
01645 }
01646 
01647 //-----------------------------------------------------------------------------
01648 void KMFolderTree::slotUpdateCountsDelayed(KMFolder * folder)
01649 {
01650 //  kdDebug(5006) << "KMFolderTree::slotUpdateCountsDelayed()" << endl;
01651   if ( !mFolderToUpdateCount.contains( folder->idString() ) )
01652   {
01653 //    kdDebug( 5006 )<< "adding " << folder->idString() << " to updateCountList " << endl;
01654     mFolderToUpdateCount.insert( folder->idString(),folder );
01655   }
01656   if ( !mUpdateCountTimer->isActive() )
01657     mUpdateCountTimer->start( 500 );
01658 }
01659 
01660 
01661 void KMFolderTree::slotUpdateCountTimeout()
01662 {
01663 //  kdDebug(5006) << "KMFolderTree::slotUpdateCountTimeout()" << endl;
01664 
01665   QMap<QString,KMFolder*>::iterator it;
01666   for ( it= mFolderToUpdateCount.begin();
01667       it!=mFolderToUpdateCount.end();
01668       ++it )
01669   {
01670     slotUpdateCounts( it.data() );
01671   }
01672   mFolderToUpdateCount.clear();
01673   mUpdateCountTimer->stop();
01674 
01675 }
01676 
01677 void KMFolderTree::updatePopup() const
01678 {
01679    mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
01680    mPopup->setItemChecked( mTotalPop, isTotalActive() );
01681    mPopup->setItemChecked( mSizePop, isSizeActive() );
01682 }
01683 
01684 //-----------------------------------------------------------------------------
01685 void KMFolderTree::toggleColumn(int column, bool openFolders)
01686 {
01687   if (column == unread)
01688   {
01689     // switch unread
01690     if ( isUnreadActive() )
01691     {
01692       removeUnreadColumn();
01693       reload();
01694     } else {
01695       addUnreadColumn( i18n("Unread"), 70 );
01696       reload();
01697     }
01698     // toggle KPopupMenu
01699     mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
01700 
01701   } else if (column == total) {
01702     // switch total
01703     if ( isTotalActive() )
01704     {
01705       removeTotalColumn();
01706       reload();
01707     } else {
01708       addTotalColumn( i18n("Total"), 70 );
01709       reload(openFolders);
01710     }
01711     mPopup->setItemChecked( mTotalPop, isTotalActive() );
01712   } else if (column == foldersize) {
01713     // switch total
01714     if ( isSizeActive() )
01715     {
01716       removeSizeColumn();
01717       reload();
01718     } else {
01719       addSizeColumn( i18n("Size"), 70 );
01720       reload( openFolders );
01721     }
01722     // toggle KPopupMenu
01723     mPopup->setItemChecked( mSizePop, isSizeActive() );
01724 
01725   } else kdDebug(5006) << "unknown column:" << column << endl;
01726 
01727   // toggles the switches of the mainwin
01728   emit columnsChanged();
01729 }
01730 
01731 //-----------------------------------------------------------------------------
01732 void KMFolderTree::slotToggleUnreadColumn()
01733 {
01734   toggleColumn(unread);
01735 }
01736 
01737 //-----------------------------------------------------------------------------
01738 void KMFolderTree::slotToggleTotalColumn()
01739 {
01740   // activate the total-column and force the folders to be opened
01741   toggleColumn(total, true);
01742 }
01743 
01744 //-----------------------------------------------------------------------------
01745 void KMFolderTree::slotToggleSizeColumn()
01746 {
01747   // activate the size-column and force the folders to be opened
01748   toggleColumn(foldersize, true);
01749 }
01750 
01751 
01752 //-----------------------------------------------------------------------------
01753 bool KMFolderTree::eventFilter( QObject *o, QEvent *e )
01754 {
01755   if ( e->type() == QEvent::MouseButtonPress &&
01756       static_cast<QMouseEvent*>(e)->button() == RightButton &&
01757       o->isA("QHeader") )
01758   {
01759     mPopup->popup( static_cast<QMouseEvent*>(e)->globalPos() );
01760     return true;
01761   }
01762   return KFolderTree::eventFilter(o, e);
01763 }
01764 
01765 //-----------------------------------------------------------------------------
01766 void KMFolderTree::slotCheckMail()
01767 {
01768   if (!currentItem())
01769     return;
01770   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(currentItem());
01771   KMFolder* folder = fti->folder();
01772   if (folder && folder->storage() ) {
01773       if ( KMAccount* acct = folder->storage()->account() ) {
01774          kmkernel->acctMgr()->singleCheckMail(acct, true);
01775       }
01776   }
01777 }
01778 
01779 //-----------------------------------------------------------------------------
01780 void KMFolderTree::slotNewMessageToMailingList()
01781 {
01782   KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>( currentItem() );
01783   if ( !fti || !fti->folder() )
01784     return;
01785   KMCommand *command = new KMMailingListPostCommand( this, fti->folder() );
01786   command->start();
01787 }
01788 
01789 //-----------------------------------------------------------------------------
01790 void KMFolderTree::createFolderList( QStringList *str,
01791                                      QValueList<QGuardedPtr<KMFolder> > *folders,
01792                                      bool localFolders,
01793                                      bool imapFolders,
01794                                      bool dimapFolders,
01795                                      bool searchFolders,
01796                                      bool includeNoContent,
01797                                      bool includeNoChildren )
01798 {
01799   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
01800   {
01801     KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
01802     if (!fti || !fti->folder()) continue;
01803     // type checks
01804     KMFolder* folder = fti->folder();
01805     if (!imapFolders && folder->folderType() == KMFolderTypeImap) continue;
01806     if (!dimapFolders && folder->folderType() == KMFolderTypeCachedImap) continue;
01807     if (!localFolders && (folder->folderType() == KMFolderTypeMbox ||
01808                           folder->folderType() == KMFolderTypeMaildir)) continue;
01809     if (!searchFolders && folder->folderType() == KMFolderTypeSearch) continue;
01810     if (!includeNoContent && folder->noContent()) continue;
01811     if (!includeNoChildren && folder->noChildren()) continue;
01812     QString prefix;
01813     prefix.fill( ' ', 2 * fti->depth() );
01814     str->append(prefix + fti->text(0));
01815     folders->append(fti->folder());
01816   }
01817 }
01818 
01819 //-----------------------------------------------------------------------------
01820 void KMFolderTree::slotResetFolderList( QListViewItem* item, bool startList )
01821 {
01822   if ( !item )
01823     item = currentItem();
01824 
01825   KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>( item );
01826   if ( fti && fti->folder() &&
01827        fti->folder()->folderType() == KMFolderTypeImap )
01828   {
01829     KMFolderImap *folder = static_cast<KMFolderImap*>( fti->folder()->storage() );
01830     folder->setSubfolderState( KMFolderImap::imapNoInformation );
01831     if ( startList )
01832       folder->listDirectory();
01833   }
01834 }
01835 
01836 //-----------------------------------------------------------------------------
01837 void KMFolderTree::showFolder( KMFolder* folder )
01838 {
01839   if ( !folder ) return;
01840   QListViewItem* item = indexOfFolder( folder );
01841   if ( item )
01842   {
01843     doFolderSelected( item );
01844     ensureItemVisible( item );
01845   }
01846 }
01847 
01848 //-----------------------------------------------------------------------------
01849 void KMFolderTree::folderToPopupMenu( MenuAction action, QObject *receiver,
01850     KMMenuToFolder *aMenuToFolder, QPopupMenu *menu, QListViewItem *item )
01851 {
01852   while ( menu->count() )
01853   {
01854     QPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup();
01855     if ( popup )
01856       delete popup;
01857     else
01858       menu->removeItemAt( 0 );
01859   }
01860   // connect the signals
01861   if ( action == MoveMessage || action == MoveFolder )
01862   {
01863     disconnect( menu, SIGNAL(activated(int)), receiver,
01864         SLOT(moveSelectedToFolder(int)) );
01865     connect( menu, SIGNAL(activated(int)), receiver,
01866         SLOT(moveSelectedToFolder(int)) );
01867   } else {
01868     disconnect( menu, SIGNAL(activated(int)), receiver,
01869         SLOT(copySelectedToFolder(int)) );
01870     connect( menu, SIGNAL(activated(int)), receiver,
01871         SLOT(copySelectedToFolder(int)) );
01872   }
01873   if ( !item ) {
01874     item = firstChild();
01875 
01876     // avoid a popup menu with the single entry 'Local Folders' if there
01877     // are no IMAP accounts
01878     if ( childCount() == 2 && action != MoveFolder ) { // only 'Local Folders' and 'Searches'
01879       KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>( item );
01880       if ( fti->protocol() == KFolderTreeItem::Search ) {
01881         // skip 'Searches'
01882         item = item->nextSibling();
01883         fti = static_cast<KMFolderTreeItem*>( item );
01884       }
01885       folderToPopupMenu( action, receiver, aMenuToFolder, menu, fti->firstChild() );
01886       return;
01887     }
01888   }
01889 
01890   while ( item )
01891   {
01892     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( item );
01893     if ( fti->protocol() == KFolderTreeItem::Search )
01894     {
01895       // skip search folders
01896       item = item->nextSibling();
01897       continue;
01898     }
01899     QString label = fti->text( 0 );
01900     label.replace( "&","&&" );
01901     if ( fti->firstChild() )
01902     {
01903       // new level
01904       QPopupMenu* popup = new QPopupMenu( menu, "subMenu" );
01905       folderToPopupMenu( action, receiver, aMenuToFolder, popup, fti->firstChild() );
01906       bool subMenu = false;
01907       if ( ( action == MoveMessage || action == CopyMessage ) &&
01908            fti->folder() && !fti->folder()->noContent() )
01909         subMenu = true;
01910       if ( ( action == MoveFolder || action == CopyFolder )
01911           && ( !fti->folder() || ( fti->folder() && !fti->folder()->noChildren() ) ) )
01912         subMenu = true;
01913 
01914       QString sourceFolderName;
01915       KMFolderTreeItem* srcItem = dynamic_cast<KMFolderTreeItem*>( currentItem() );
01916       if ( srcItem )
01917         sourceFolderName = srcItem->text( 0 );
01918 
01919       if ( (action == MoveFolder || action == CopyFolder)
01920               && fti->folder() && fti->folder()->child()
01921               && fti->folder()->child()->hasNamedFolder( sourceFolderName ) ) {
01922         subMenu = false;
01923       }
01924 
01925       if ( subMenu )
01926       {
01927         int menuId;
01928         if ( action == MoveMessage || action == MoveFolder )
01929           menuId = popup->insertItem( i18n("Move to This Folder"), -1, 0 );
01930         else
01931           menuId = popup->insertItem( i18n("Copy to This Folder"), -1, 0 );
01932         popup->insertSeparator( 1 );
01933         aMenuToFolder->insert( menuId, fti->folder() );
01934       }
01935       menu->insertItem( label, popup );
01936     } else
01937     {
01938       // insert an item
01939       int menuId = menu->insertItem( label );
01940       if ( fti->folder() )
01941         aMenuToFolder->insert( menuId, fti->folder() );
01942       bool enabled = (fti->folder() ? true : false);
01943       if ( fti->folder() &&
01944            ( fti->folder()->isReadOnly() || fti->folder()->noContent() ) )
01945         enabled = false;
01946       menu->setItemEnabled( menuId, enabled );
01947     }
01948 
01949     item = item->nextSibling();
01950   }
01951 }
01952 
01953 //-----------------------------------------------------------------------------
01954 void KMFolderTree::moveSelectedToFolder( int menuId )
01955 {
01956   moveOrCopyFolder( selectedFolders(), mMenuToFolder[ menuId ], true /*move*/ );
01957 }
01958 
01959 //-----------------------------------------------------------------------------
01960 void KMFolderTree::copySelectedToFolder( int menuId )
01961 {
01962   moveOrCopyFolder( selectedFolders(), mMenuToFolder[ menuId ], false /*copy, don't move*/ );
01963 }
01964 
01965 //-----------------------------------------------------------------------------
01966 void KMFolderTree::moveOrCopyFolder( QValueList<QGuardedPtr<KMFolder> > sources, KMFolder* destination, bool move )
01967 {
01968   kdDebug(5006) << k_funcinfo << "source: " << sources << " destination: " << destination << " move: " << move << endl;
01969 
01970   // Disable drag during copy operation since it prevents from many crashes
01971   setDragEnabled( false );
01972 
01973   KMFolderDir* parent = &(kmkernel->folderMgr()->dir());
01974   if ( destination )
01975     parent = destination->createChildFolder();
01976 
01977   QStringList sourceFolderNames;
01978 
01979   // check if move/copy is possible at all
01980   for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); it != sources.constEnd(); ++it ) {
01981     KMFolder* source = *it;
01982 
01983     // check if folder with same name already exits
01984     QString sourceFolderName;
01985     if ( source )
01986       sourceFolderName = source->label();
01987 
01988     if ( parent->hasNamedFolder( sourceFolderName ) || sourceFolderNames.contains( sourceFolderName ) ) {
01989       KMessageBox::error( this, i18n("<qt>Cannot move or copy folder <b>%1</b> here because a folder with the same name already exists.</qt>")
01990           .arg( sourceFolderName ) );
01991       setDragEnabled( true );
01992       return;
01993     }
01994     sourceFolderNames.append( sourceFolderName );
01995 
01996     // don't move/copy a folder that's still not completely moved/copied
01997     KMFolder *f = source;
01998     while ( f ) {
01999       if ( f->moveInProgress() ) {
02000         KMessageBox::error( this, i18n("<qt>Cannot move or copy folder <b>%1</b> because it is not completely copied itself.</qt>")
02001             .arg( sourceFolderName ) );
02002         setDragEnabled( true );
02003         return;
02004       }
02005       if ( f->parent() )
02006         f = f->parent()->owner();
02007     }
02008 
02009     QString message =
02010       i18n( "<qt>Cannot move or copy folder <b>%1</b> into a subfolder below itself.</qt>" ).
02011           arg( sourceFolderName );
02012     KMFolderDir* folderDir = parent;
02013     // check that the folder can be moved
02014     if ( source && source->child() )
02015     {
02016       while ( folderDir && ( folderDir != &kmkernel->folderMgr()->dir() ) &&
02017           ( folderDir != source->parent() ) )
02018       {
02019         if ( folderDir->findRef( source ) != -1 )
02020         {
02021           KMessageBox::error( this, message );
02022           setDragEnabled( true );
02023           return;
02024         }
02025         folderDir = folderDir->parent();
02026       }
02027     }
02028 
02029     if( source && source->child() && parent &&
02030         ( parent->path().find( source->child()->path() + "/" ) == 0 ) ) {
02031       KMessageBox::error( this, message );
02032       setDragEnabled( true );
02033       return;
02034     }
02035 
02036     if( source && source->child()
02037         && ( parent == source->child() ) ) {
02038       KMessageBox::error( this, message );
02039       setDragEnabled( true );
02040       return;
02041     }
02042   }
02043 
02044   // check if the source folders are independent of each other
02045   for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); move && it != sources.constEnd(); ++it ) {
02046     KMFolderDir *parentDir = (*it)->child();
02047     if ( !parentDir )
02048       continue;
02049     for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it2 = sources.constBegin(); it2 != sources.constEnd(); ++it2 ) {
02050       if ( *it == *it2 )
02051         continue;
02052       KMFolderDir *childDir = (*it2)->parent();
02053       do {
02054         if ( parentDir == childDir || parentDir->findRef( childDir->owner() ) != -1 ) {
02055           KMessageBox::error( this, i18n("Moving the selected folders is not possible") );
02056           setDragEnabled( true );
02057           return;
02058         }
02059         childDir = childDir->parent();
02060       }
02061       while ( childDir && childDir != &kmkernel->folderMgr()->dir() );
02062     }
02063   }
02064 
02065   // de-select moved source folders (can cause crash due to unGetMsg() in KMHeaders)
02066   if ( move ) {
02067     doFolderSelected( indexOfFolder( destination ), false );
02068     oldCurrent = currentItem();
02069   }
02070 
02071   // do the actual move/copy
02072   for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); it != sources.constEnd(); ++it ) {
02073     KMFolder* source = *it;
02074     if ( move ) {
02075       kdDebug(5006) << "move folder " << (source ? source->label(): "Unknown") << " to "
02076         << ( destination ? destination->label() : "Local Folders" ) << endl;
02077       kmkernel->folderMgr()->moveFolder( source, parent );
02078     } else {
02079       kmkernel->folderMgr()->copyFolder( source, parent );
02080     }
02081   }
02082 }
02083 
02084 QDragObject * KMFolderTree::dragObject()
02085 {
02086   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>
02087       (itemAt(viewport()->mapFromGlobal(QCursor::pos())));
02088   if ( !item || !item->parent() || !item->folder() ) // top-level items or something invalid
02089     return 0;
02090   mCopySourceFolders = selectedFolders();
02091 
02092   QDragObject *drag = KFolderTree::dragObject();
02093   if ( drag )
02094     drag->setPixmap( SmallIcon("folder") );
02095   return drag;
02096 }
02097 
02098 void KMFolderTree::copyFolder()
02099 {
02100   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
02101   if ( item ) {
02102     mCopySourceFolders = selectedFolders();
02103     mCutFolder = false;
02104   }
02105   updateCopyActions();
02106 }
02107 
02108 void KMFolderTree::cutFolder()
02109 {
02110   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
02111   if ( item ) {
02112     mCopySourceFolders = selectedFolders();
02113     mCutFolder = true;
02114   }
02115   updateCopyActions();
02116 }
02117 
02118 void KMFolderTree::pasteFolder()
02119 {
02120   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
02121   if ( !mCopySourceFolders.isEmpty() && item && !mCopySourceFolders.contains( item->folder() ) ) {
02122     moveOrCopyFolder( mCopySourceFolders, item->folder(), mCutFolder );
02123     if ( mCutFolder )
02124       mCopySourceFolders.clear();
02125   }
02126   updateCopyActions();
02127 }
02128 
02129 void KMFolderTree::updateCopyActions()
02130 {
02131   KAction *copy = mMainWidget->action("copy_folder");
02132   KAction *cut = mMainWidget->action("cut_folder");
02133   KAction *paste = mMainWidget->action("paste_folder");
02134   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
02135 
02136   if ( !item ||  !item->folder() ) {
02137     copy->setEnabled( false );
02138     cut->setEnabled( false );
02139   } else {
02140     copy->setEnabled( true );
02141     cut->setEnabled( item->folder()->isMoveable() );
02142   }
02143 
02144   if ( mCopySourceFolders.isEmpty() )
02145     paste->setEnabled( false );
02146   else
02147     paste->setEnabled( true );
02148 }
02149 
02150 void KMFolderTree::slotSyncStateChanged()
02151 {
02152   // Only emit the signal when a selected folder changes, otherwise the folder menu is updated
02153   // too often
02154   QValueList< QGuardedPtr<KMFolder> > folders = selectedFolders();
02155   QValueList< QGuardedPtr<KMFolder> >::const_iterator it = folders.constBegin();
02156   QValueList< QGuardedPtr<KMFolder> >::const_iterator end = folders.constEnd();
02157   while ( it != end ) {
02158     QGuardedPtr<KMFolder> folder = *it;
02159     if ( folder == sender() ) {
02160       emit syncStateChanged();
02161       break;
02162     }
02163     ++it;
02164   }
02165 }
02166 
02167 void KMFolderTree::slotAddToFavorites()
02168 {
02169   KMail::FavoriteFolderView *favView = mMainWidget->favoriteFolderView();
02170   assert( favView );
02171   for ( QListViewItemIterator it( this ); it.current(); ++it ) {
02172     if ( it.current()->isSelected() )
02173       favView->addFolder( static_cast<KMFolderTreeItem*>( it.current() ) );
02174   }
02175 }
02176 
02177 void KMFolderTree::slotUnhideLocalInbox()
02178 {
02179   disconnect( kmkernel->inboxFolder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
02180               this, SLOT(slotUnhideLocalInbox()) );
02181   reload();
02182 }
02183 
02184 void KMFolderTree::delayedReload()
02185 {
02186   QTimer::singleShot( 0, this, SLOT(reload()) );
02187 }
02188 
02189 #include "kmfoldertree.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys