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     // we want to be noticed of changes to update the unread/total columns
00625     disconnect(fti->folder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
00626         this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00627     connect(fti->folder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
00628         this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00629     //}
00630 
00631     disconnect(fti->folder(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00632                this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00633     connect(fti->folder(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00634             this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00635     disconnect(fti->folder(), SIGNAL(msgRemoved(KMFolder*)),
00636                this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00637     connect(fti->folder(), SIGNAL(msgRemoved(KMFolder*)),
00638             this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00639 
00640   disconnect(fti->folder(), SIGNAL(folderSizeChanged( KMFolder* )),
00641                this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00642   connect(fti->folder(), SIGNAL(folderSizeChanged( KMFolder* )),
00643                this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
00644 
00645 
00646 
00647     disconnect(fti->folder(), SIGNAL(shortcutChanged(KMFolder*)),
00648                mMainWidget, SLOT( slotShortcutChanged(KMFolder*)));
00649     connect(fti->folder(), SIGNAL(shortcutChanged(KMFolder*)),
00650             mMainWidget, SLOT( slotShortcutChanged(KMFolder*)));
00651 
00652 
00653     if (!openFolders)
00654       slotUpdateCounts(fti->folder());
00655 
00656     // populate the size column
00657     fti->setFolderSize( 0 );
00658     fti->setFolderIsCloseToQuota( fti->folder()->storage()->isCloseToQuota() );
00659 
00660   }
00661   ensureVisible(0, top + visibleHeight(), 0, 0);
00662   // if current and selected folder did not change set it again
00663   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
00664   {
00665     if ( last &&
00666          static_cast<KMFolderTreeItem*>( it.current() )->folder() == last )
00667     {
00668       mLastItem = static_cast<KMFolderTreeItem*>( it.current() );
00669       setCurrentItem( it.current() );
00670     }
00671     if ( selected &&
00672          static_cast<KMFolderTreeItem*>( it.current() )->folder() == selected )
00673     {
00674       setSelected( it.current(), true );
00675     }
00676     if ( oldCurrentFolder &&
00677          static_cast<KMFolderTreeItem*>( it.current() )->folder() == oldCurrentFolder )
00678     {
00679       oldCurrent = it.current();
00680     }
00681   }
00682   refresh();
00683   mReloading = false;
00684 }
00685 
00686 //-----------------------------------------------------------------------------
00687 void KMFolderTree::slotUpdateOneCount()
00688 {
00689   if ( !mUpdateIterator.current() ) return;
00690   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(mUpdateIterator.current());
00691   ++mUpdateIterator;
00692   if ( !fti->folder() ) {
00693     // next one please
00694     QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
00695     return;
00696   }
00697 
00698   // open the folder and update the count
00699   bool open = fti->folder()->isOpened();
00700   if (!open) fti->folder()->open("updatecount");
00701   slotUpdateCounts(fti->folder());
00702   // restore previous state
00703   if (!open) fti->folder()->close("updatecount");
00704 
00705   QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
00706 }
00707 
00708 //-----------------------------------------------------------------------------
00709 // Recursively add a directory of folders to the tree of folders
00710 void KMFolderTree::addDirectory( KMFolderDir *fdir, KMFolderTreeItem* parent )
00711 {
00712   for ( KMFolderNode * node = fdir->first() ; node ; node = fdir->next() ) {
00713     if ( node->isDir() )
00714       continue;
00715 
00716     KMFolder * folder = static_cast<KMFolder*>(node);
00717     KMFolderTreeItem * fti = 0;
00718     if (!parent)
00719     {
00720       // create new root-item, but only if this is not the root of a
00721       // "groupware folders only" account
00722       if ( kmkernel->iCalIface().hideResourceAccountRoot( folder ) )
00723         continue;
00724       // it needs a folder e.g. to save it's state (open/close)
00725       fti = new KMFolderTreeItem( this, folder->label(), folder );
00726       fti->setExpandable( true );
00727 
00728       // add child-folders
00729       if (folder && folder->child()) {
00730         addDirectory( folder->child(), fti );
00731       }
00732     } else {
00733       // hide local inbox if unused
00734       if ( kmkernel->inboxFolder() == folder && hideLocalInbox() ) {
00735         connect( kmkernel->inboxFolder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)), SLOT(slotUnhideLocalInbox()) );
00736         continue;
00737       }
00738 
00739       // create new child
00740       fti = new KMFolderTreeItem( parent, folder->label(), folder );
00741       // set folders explicitely to exandable when they have children
00742       // this way we can do a listing for IMAP folders when the user expands them
00743       // even when the child folders are not created yet
00744       if ( folder->storage()->hasChildren() == FolderStorage::HasChildren ) {
00745         fti->setExpandable( true );
00746       } else {
00747         fti->setExpandable( false );
00748       }
00749 
00750       // add child-folders
00751       if (folder && folder->child()) {
00752         addDirectory( folder->child(), fti );
00753       }
00754 
00755       // Check if this is an IMAP resource folder or a no-content parent only
00756       // containing groupware folders
00757       if ( (kmkernel->iCalIface().hideResourceFolder( folder ) || folder->noContent())
00758             && fti->childCount() == 0 ) {
00759         // It is
00760         removeFromFolderToItemMap( folder );
00761         delete fti;
00762         // still, it might change in the future, so we better check the change signals
00763         connect ( folder, SIGNAL(noContentChanged()), SLOT(delayedReload()) );
00764         continue;
00765       }
00766 
00767       connect (fti, SIGNAL(iconChanged(KMFolderTreeItem*)),
00768           this, SIGNAL(iconChanged(KMFolderTreeItem*)));
00769       connect (fti, SIGNAL(nameChanged(KMFolderTreeItem*)),
00770           this, SIGNAL(nameChanged(KMFolderTreeItem*)));
00771     }
00772     // restore last open-state
00773     fti->setOpen( readIsListViewItemOpen(fti) );
00774   } // for-end
00775 }
00776 
00777 //-----------------------------------------------------------------------------
00778 // Initiate a delayed refresh of the tree
00779 void KMFolderTree::refresh()
00780 {
00781   mUpdateTimer.changeInterval(200);
00782 }
00783 
00784 //-----------------------------------------------------------------------------
00785 // Updates the pixmap and extendedLabel information for items
00786 void KMFolderTree::delayedUpdate()
00787 {
00788   bool upd = isUpdatesEnabled();
00789   if ( upd ) {
00790     setUpdatesEnabled(false);
00791 
00792     for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00793       KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00794       if (!fti || !fti->folder())
00795         continue;
00796 
00797       if ( fti->needsRepaint() ) {
00798         fti->repaint();
00799         fti->setNeedsRepaint( false );
00800       }
00801     }
00802     setUpdatesEnabled(upd);
00803   }
00804   mUpdateTimer.stop();
00805 }
00806 
00807 //-----------------------------------------------------------------------------
00808 // Folders have been added/deleted update the tree of folders
00809 void KMFolderTree::doFolderListChanged()
00810 {
00811   reload();
00812 }
00813 
00814 //-----------------------------------------------------------------------------
00815 void KMFolderTree::slotAccountRemoved(KMAccount *)
00816 {
00817   doFolderSelected( firstChild() );
00818 }
00819 
00820 //-----------------------------------------------------------------------------
00821 void KMFolderTree::slotFolderMoveOrCopyOperationFinished()
00822 {
00823   setDragEnabled( true );
00824 }
00825 //-----------------------------------------------------------------------------
00826 void KMFolderTree::slotFolderRemoved(KMFolder *aFolder)
00827 {
00828   QListViewItem *item = indexOfFolder(aFolder);
00829   if (!item) return;
00830   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*> ( item );
00831   if ( oldCurrent == fti )
00832     oldCurrent = 0;
00833   if ( oldSelected == fti )
00834     oldSelected = 0;
00835   if (!fti || !fti->folder()) return;
00836   if (fti == currentItem())
00837   {
00838     QListViewItem *qlvi = fti->itemAbove();
00839     if (!qlvi) qlvi = fti->itemBelow();
00840     doFolderSelected( qlvi );
00841   }
00842   removeFromFolderToItemMap( aFolder );
00843 
00844   if ( dropItem == fti ) { // The removed item is the dropItem
00845     dropItem = 0; // it becomes invalid
00846   }
00847 
00848   delete fti;
00849   updateCopyActions();
00850 }
00851 
00852 //-----------------------------------------------------------------------------
00853 // Methods for navigating folders with the keyboard
00854 void KMFolderTree::prepareItem( KMFolderTreeItem* fti )
00855 {
00856   for ( QListViewItem * parent = fti->parent() ; parent ; parent = parent->parent() )
00857     parent->setOpen( true );
00858   ensureItemVisible( fti );
00859 }
00860 
00861 //-----------------------------------------------------------------------------
00862 void KMFolderTree::nextUnreadFolder()
00863 {
00864     nextUnreadFolder( false );
00865 }
00866 
00867 //-----------------------------------------------------------------------------
00868 void KMFolderTree::nextUnreadFolder(bool confirm)
00869 {
00870   QListViewItemIterator it( currentItem() ? currentItem() : firstChild() );
00871   if ( currentItem() )
00872     ++it; // don't find current item
00873   for ( ; it.current() ; ++it ) {
00874     //check if folder is one to stop on
00875     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00876     if (checkUnreadFolder(fti,confirm)) return;
00877   }
00878   //Now if confirm is true we are doing "ReadOn"
00879   //we have got to the bottom of the folder list
00880   //so we have to start at the top
00881   if (confirm) {
00882     for ( it = firstChild() ; it.current() ; ++it ) {
00883       //check if folder is one to stop on
00884       KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00885       if (checkUnreadFolder(fti,confirm)) return;
00886     }
00887   }
00888 }
00889 
00890 //-----------------------------------------------------------------------------
00891 bool KMFolderTree::checkUnreadFolder (KMFolderTreeItem* fti, bool confirm)
00892 {
00893   if ( fti && fti->folder() && !fti->folder()->ignoreNewMail() &&
00894        ( fti->folder()->countUnread() > 0 ) ) {
00895 
00896     // Don't change into the trash or outbox folders.
00897     if (fti->type() == KFolderTreeItem::Trash ||
00898         fti->type() == KFolderTreeItem::Outbox )
00899       return false;
00900 
00901     if (confirm) {
00902       // Skip drafts, sent mail and templates as well, when reading mail with
00903       // the space bar but not when changing into the next folder with unread
00904       // mail via ctrl+ or ctrl- so we do this only if (confirm == true),
00905       // which means we are doing readOn.
00906       if ( fti->type() == KFolderTreeItem::Drafts ||
00907            fti->type() == KFolderTreeItem::Templates ||
00908            fti->type() == KFolderTreeItem::SentMail )
00909         return false;
00910 
00911       //  warn user that going to next folder - but keep track of
00912       //  whether he wishes to be notified again in "AskNextFolder"
00913       //  parameter (kept in the config file for kmail)
00914       if ( KMessageBox::questionYesNo( this,
00915             i18n( "<qt>Go to the next unread message in folder <b>%1</b>?</qt>" )
00916             .arg( fti->folder()->label() ),
00917             i18n( "Go to Next Unread Message" ),
00918             i18n("Go To"), i18n("Do Not Go To"), // defaults
00919             "AskNextFolder",
00920             false)
00921           == KMessageBox::No ) return true;
00922     }
00923     prepareItem( fti );
00924     blockSignals( true );
00925     doFolderSelected( fti );
00926     blockSignals( false );
00927     emit folderSelectedUnread( fti->folder() );
00928     return true;
00929   }
00930   return false;
00931 }
00932 
00933 //-----------------------------------------------------------------------------
00934 void KMFolderTree::prevUnreadFolder()
00935 {
00936   QListViewItemIterator it( currentItem() ? currentItem() : lastItem() );
00937   if ( currentItem() )
00938     --it; // don't find current item
00939   for ( ; it.current() ; --it ) {
00940     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00941     if (checkUnreadFolder(fti,false)) return;
00942   }
00943 }
00944 
00945 //-----------------------------------------------------------------------------
00946 void KMFolderTree::incCurrentFolder()
00947 {
00948   QListViewItemIterator it( currentItem() );
00949   ++it;
00950   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00951   if (fti) {
00952       prepareItem( fti );
00953       setFocus();
00954       setCurrentItem( fti );
00955   }
00956 }
00957 
00958 //-----------------------------------------------------------------------------
00959 void KMFolderTree::decCurrentFolder()
00960 {
00961   QListViewItemIterator it( currentItem() );
00962   --it;
00963   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00964   if (fti) {
00965       prepareItem( fti );
00966       setFocus();
00967       setCurrentItem( fti );
00968   }
00969 }
00970 
00971 //-----------------------------------------------------------------------------
00972 void KMFolderTree::selectCurrentFolder()
00973 {
00974   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() );
00975   if (fti) {
00976       prepareItem( fti );
00977       doFolderSelected( fti );
00978   }
00979 }
00980 
00981 //-----------------------------------------------------------------------------
00982 KMFolder *KMFolderTree::currentFolder() const
00983 {
00984     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() );
00985     if (fti )
00986         return fti->folder();
00987     else
00988         return 0;
00989 }
00990 
00991 QValueList<QGuardedPtr<KMFolder> > KMFolderTree::selectedFolders()
00992 {
00993   QValueList<QGuardedPtr<KMFolder> > rv;
00994   for ( QListViewItemIterator it( this ); it.current(); ++it ) {
00995     if ( it.current()->isSelected() ) {
00996       KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>( it.current() );
00997       rv.append( fti->folder() );
00998     }
00999   }
01000   return rv;
01001 }
01002 
01003 //-----------------------------------------------------------------------------
01004 // When not dragging and dropping a change in the selected item
01005 // indicates the user has changed the active folder emit a signal
01006 // so that the header list and reader window can be udpated.
01007 void KMFolderTree::doFolderSelected( QListViewItem* qlvi, bool keepSelection )
01008 {
01009   if (!qlvi) return;
01010   if ( mLastItem && mLastItem == qlvi && (keepSelection || selectedFolders().count() == 1) )
01011     return;
01012 
01013   KMFolderTreeItem* fti = static_cast< KMFolderTreeItem* >(qlvi);
01014   KMFolder* folder = 0;
01015   if (fti) folder = fti->folder();
01016 
01017 
01018   if (mLastItem && mLastItem != fti && mLastItem->folder()
01019      && (mLastItem->folder()->folderType() == KMFolderTypeImap))
01020   {
01021     KMFolderImap *imapFolder = static_cast<KMFolderImap*>(mLastItem->folder()->storage());
01022     imapFolder->setSelected(false);
01023   }
01024   mLastItem = fti;
01025 
01026   if ( !keepSelection )
01027     clearSelection();
01028   setCurrentItem( qlvi );
01029   if ( !keepSelection )
01030     setSelected( qlvi, true );
01031   ensureItemVisible( qlvi );
01032   if (!folder) {
01033     emit folderSelected(0); // Root has been selected
01034   }
01035   else {
01036     emit folderSelected(folder);
01037     slotUpdateCounts(folder);
01038   }
01039 }
01040 
01041 //-----------------------------------------------------------------------------
01042 void KMFolderTree::resizeEvent(QResizeEvent* e)
01043 {
01044   KConfig* conf = KMKernel::config();
01045 
01046   KConfigGroupSaver saver(conf, "Geometry");
01047   conf->writeEntry(name(), size().width());
01048 
01049   KListView::resizeEvent(e);
01050 }
01051 
01052 //-----------------------------------------------------------------------------
01053 // show context menu
01054 void KMFolderTree::slotContextMenuRequested( QListViewItem *lvi,
01055                                              const QPoint &p )
01056 {
01057   if (!lvi)
01058     return;
01059   setCurrentItem( lvi );
01060 
01061   if (!mMainWidget) return; // safe bet
01062 
01063   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(lvi);
01064   if ( !isSelected( fti ) )
01065     doFolderSelected( fti );
01066   else if ( fti != mLastItem )
01067     doFolderSelected( fti, true );
01068 
01069   if (!fti )
01070     return;
01071 
01072   KPopupMenu *folderMenu = new KPopupMenu;
01073   bool multiFolder = selectedFolders().count() > 1;
01074   if (fti->folder()) folderMenu->insertTitle(fti->folder()->label());
01075 
01076   // outbox specific, but there it's the most used action
01077   if ( (fti->folder() == kmkernel->outboxFolder()) && fti->folder()->count() )
01078         mMainWidget->action("send_queued")->plug( folderMenu );
01079   // Mark all as read is supposedly used often, therefor it is first
01080   if ( fti->folder() && !fti->folder()->noContent() )
01081       mMainWidget->action("mark_all_as_read")->plug( folderMenu );
01082 
01083   /* Treat the special case of the root and account folders */
01084   if ((!fti->folder() || (fti->folder()->noContent()
01085     && !fti->parent())))
01086   {
01087     QString createChild = i18n("&New Subfolder...");
01088     if (!fti->folder()) createChild = i18n("&New Folder...");
01089 
01090     if ( ( fti->folder() || (fti->text(0) != i18n("Searches")) ) && !multiFolder)
01091         folderMenu->insertItem(SmallIconSet("folder_new"),
01092                                createChild, this,
01093                                SLOT(addChildFolder()));
01094 
01095     if (!fti->folder()) {
01096       mMainWidget->action("compact_all_folders")->plug(folderMenu);
01097       mMainWidget->action("expire_all_folders")->plug(folderMenu);
01098     } else if (fti->folder()->folderType() == KMFolderTypeImap) {
01099       folderMenu->insertItem(SmallIconSet("mail_get"), i18n("Check &Mail"),
01100         this,
01101         SLOT(slotCheckMail()));
01102     }
01103   } else { // regular folders
01104 
01105     folderMenu->insertSeparator();
01106     if ( !fti->folder()->noChildren() && !multiFolder ) {
01107       folderMenu->insertItem(SmallIconSet("folder_new"),
01108                              i18n("&New Subfolder..."), this,
01109                              SLOT(addChildFolder()));
01110     }
01111 
01112     // copy folder
01113     QPopupMenu *copyMenu = new QPopupMenu( folderMenu );
01114     folderToPopupMenu( CopyFolder, this, &mMenuToFolder, copyMenu );
01115     folderMenu->insertItem( i18n("&Copy Folder To"), copyMenu );
01116 
01117     if ( fti->folder()->isMoveable() && fti->folder()->canDeleteMessages() )
01118     {
01119       QPopupMenu *moveMenu = new QPopupMenu( folderMenu );
01120       folderToPopupMenu( MoveFolder, this, &mMenuToFolder, moveMenu );
01121       folderMenu->insertItem( i18n("&Move Folder To"), moveMenu );
01122     }
01123 
01124     // Want to be able to display properties for ALL folders,
01125     // so we can edit expiry properties.
01126     // -- smp.
01127     if (!fti->folder()->noContent())
01128     {
01129       if ( !multiFolder )
01130         mMainWidget->action("search_messages")->plug(folderMenu);
01131 
01132       mMainWidget->action( "archive_folder" )->plug( folderMenu );
01133 
01134       mMainWidget->action("compact")->plug(folderMenu);
01135 
01136       if ( GlobalSettings::self()->enableFavoriteFolderView() ) {
01137         folderMenu->insertItem( SmallIconSet("bookmark_add"), i18n("Add to Favorite Folders"),
01138                                 this, SLOT(slotAddToFavorites()) );
01139       }
01140 
01141       folderMenu->insertSeparator();
01142       mMainWidget->action("empty")->plug(folderMenu);
01143       if ( !fti->folder()->isSystemFolder() ) {
01144         mMainWidget->action("delete_folder")->plug(folderMenu);
01145       }
01146       folderMenu->insertSeparator();
01147     }
01148   }
01149 
01150   /* plug in IMAP and DIMAP specific things */
01151   if (fti->folder() &&
01152       (fti->folder()->folderType() == KMFolderTypeImap ||
01153        fti->folder()->folderType() == KMFolderTypeCachedImap ))
01154   {
01155     folderMenu->insertItem(SmallIconSet("bookmark_folder"),
01156         i18n("Serverside Subscription..."), mMainWidget,
01157         SLOT(slotSubscriptionDialog()));
01158     folderMenu->insertItem(SmallIcon("bookmark_folder"),
01159         i18n("Local Subscription..."), mMainWidget,
01160         SLOT(slotLocalSubscriptionDialog()));
01161 
01162     if (!fti->folder()->noContent())
01163     {
01164       mMainWidget->action("refresh_folder")->plug(folderMenu);
01165       if ( fti->folder()->folderType() == KMFolderTypeImap && !multiFolder ) {
01166         folderMenu->insertItem(SmallIconSet("reload"), i18n("Refresh Folder List"), this,
01167             SLOT(slotResetFolderList()));
01168       }
01169     }
01170     if ( fti->folder()->folderType() == KMFolderTypeCachedImap && !multiFolder ) {
01171       KMFolderCachedImap * folder = static_cast<KMFolderCachedImap*>( fti->folder()->storage() );
01172       folderMenu->insertItem( SmallIconSet("wizard"),
01173                               i18n("&Troubleshoot IMAP Cache..."),
01174                               folder, SLOT(slotTroubleshoot()) );
01175     }
01176     folderMenu->insertSeparator();
01177   }
01178 
01179   if ( fti->folder() && fti->folder()->isMailingListEnabled() && !multiFolder ) {
01180     mMainWidget->action("post_message")->plug(folderMenu);
01181   }
01182 
01183   if (fti->folder() && fti->parent() && !multiFolder)
01184   {
01185     folderMenu->insertItem(SmallIconSet("configure_shortcuts"),
01186         i18n("&Assign Shortcut..."),
01187         fti,
01188         SLOT(assignShortcut()));
01189 
01190     if ( !fti->folder()->noContent() && fti->folder()->canDeleteMessages() ) {
01191       folderMenu->insertItem( i18n("Expire..."), fti,
01192                               SLOT( slotShowExpiryProperties() ) );
01193     }
01194     mMainWidget->action("modify")->plug(folderMenu);
01195   }
01196 
01197 
01198   kmkernel->setContextMenuShown( true );
01199   folderMenu->exec (p, 0);
01200   kmkernel->setContextMenuShown( false );
01201   triggerUpdate();
01202   delete folderMenu;
01203   folderMenu = 0;
01204 }
01205 
01206 //-----------------------------------------------------------------------------
01207 void KMFolderTree::contentsMousePressEvent(QMouseEvent * e)
01208 {
01209   // KFolderTree messes around with the selection mode
01210   KListView::contentsMousePressEvent( e );
01211 }
01212 
01213 // If middle button and folder holds mailing-list, create a message to that list
01214 void KMFolderTree::contentsMouseReleaseEvent(QMouseEvent* me)
01215 {
01216   QListViewItem *lvi = currentItem(); // Needed for when branches are clicked on
01217   ButtonState btn = me->button();
01218   doFolderSelected(lvi, true);
01219 
01220   // get underlying folder
01221   KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>(lvi);
01222 
01223   if (!fti || !fti->folder()) {
01224     KFolderTree::contentsMouseReleaseEvent(me);
01225     return;
01226   }
01227 
01228   // react on middle-button only
01229   if (btn != Qt::MidButton) {
01230     KFolderTree::contentsMouseReleaseEvent(me);
01231     return;
01232   }
01233 
01234   if ( fti->folder()->isMailingListEnabled() ) {
01235     KMCommand *command = new KMMailingListPostCommand( this, fti->folder() );
01236     command->start();
01237   }
01238 
01239   KFolderTree::contentsMouseReleaseEvent(me);
01240 }
01241 
01242 // little static helper
01243 static bool folderHasCreateRights( const KMFolder *folder )
01244 {
01245   bool createRights = true; // we don't have acls for local folders yet
01246   if ( folder && folder->folderType() == KMFolderTypeImap ) {
01247     const KMFolderImap *imapFolder = static_cast<const KMFolderImap*>( folder->storage() );
01248     createRights = imapFolder->userRights() == 0 || // hack, we should get the acls
01249       ( imapFolder->userRights() > 0 && ( imapFolder->userRights() & KMail::ACLJobs::Create ) );
01250   } else if ( folder && folder->folderType() == KMFolderTypeCachedImap ) {
01251     const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
01252     createRights = dimapFolder->userRights() == 0 ||
01253       ( dimapFolder->userRights() > 0 && ( dimapFolder->userRights() & KMail::ACLJobs::Create ) );
01254   }
01255   return createRights;
01256 }
01257 
01258 //-----------------------------------------------------------------------------
01259 // Create a subfolder.
01260 // Requires creating the appropriate subdirectory and show a dialog
01261 void KMFolderTree::addChildFolder( KMFolder *folder, QWidget * parent )
01262 {
01263   KMFolder *aFolder = folder;
01264   if ( !aFolder ) {
01265     KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(currentItem());
01266     if (!fti)
01267       return;
01268     aFolder = fti->folder();
01269   }
01270   if (aFolder) {
01271     if (!aFolder->createChildFolder())
01272       return;
01273     if ( !folderHasCreateRights( aFolder ) ) {
01274       // FIXME: change this message to "Cannot create folder under ..." or similar
01275       const QString message = i18n( "<qt>Cannot create folder <b>%1</b> because of insufficient "
01276                                     "permissions on the server. If you think you should be able to create "
01277                                     "subfolders here, ask your administrator to grant you rights to do so."
01278                                     "</qt> " ).arg(aFolder->label());
01279       KMessageBox::error( this, message );
01280       return;
01281     }
01282   }
01283 
01284   if ( parent )
01285     ( new KMail::NewFolderDialog( parent, aFolder ) )->exec();
01286   else
01287     ( new KMail::NewFolderDialog( this, aFolder ) )->show();
01288   return;
01289 /*
01290   KMFolderDir *dir = &(kmkernel->folderMgr()->dir());
01291   if (aFolder)
01292     dir = aFolder->child();
01293 
01294   KMFolderDialog *d =
01295     new KMFolderDialog(0, dir, this, i18n("Create Subfolder") );
01296 
01297   if (d->exec()) { // fti may be deleted here
01298     QListViewItem *qlvi = indexOfFolder( aFolder );
01299     if (qlvi) {
01300       qlvi->setOpen(true);
01301       blockSignals( true );
01302       setCurrentItem( qlvi );
01303       blockSignals( false );
01304     }
01305   }
01306   delete d;
01307   // update if added to root Folder
01308   if (!aFolder || aFolder->noContent()) {
01309      doFolderListChanged();
01310   }
01311   */
01312 }
01313 
01314 //-----------------------------------------------------------------------------
01315 // Returns whether a folder directory should be open as specified in the
01316 // config file.
01317 bool KMFolderTree::readIsListViewItemOpen(KMFolderTreeItem *fti)
01318 {
01319   KConfig* config = KMKernel::config();
01320   KMFolder *folder = fti->folder();
01321   QString name;
01322   if (folder)
01323   {
01324     name = "Folder-" + folder->idString();
01325   } else if (fti->type() == KFolderTreeItem::Root)
01326   {
01327     if (fti->protocol() == KFolderTreeItem::NONE) // local root
01328       name = "Folder_local_root";
01329     else if (fti->protocol() == KFolderTreeItem::Search)
01330       name = "Folder_search";
01331     else
01332       return false;
01333   } else {
01334     return false;
01335   }
01336   KConfigGroupSaver saver(config, name);
01337 
01338   return config->readBoolEntry("isOpen", false);
01339 }
01340 
01341 //-----------------------------------------------------------------------------
01342 // Saves open/closed state of a folder directory into the config file
01343 void KMFolderTree::writeIsListViewItemOpen(KMFolderTreeItem *fti)
01344 {
01345   KConfig* config = KMKernel::config();
01346   KMFolder *folder = fti->folder();
01347   QString name;
01348   if (folder && !folder->idString().isEmpty())
01349   {
01350     name = "Folder-" + folder->idString();
01351   } else if (fti->type() == KFolderTreeItem::Root)
01352   {
01353     if (fti->protocol() == KFolderTreeItem::NONE) // local root
01354       name = "Folder_local_root";
01355     else if (fti->protocol() == KFolderTreeItem::Search)
01356       name = "Folder_search";
01357     else
01358       return;
01359   } else {
01360     return;
01361   }
01362   KConfigGroupSaver saver(config, name);
01363   config->writeEntry("isOpen", fti->isOpen() );
01364 }
01365 
01366 
01367 //-----------------------------------------------------------------------------
01368 void KMFolderTree::cleanupConfigFile()
01369 {
01370   if ( childCount() == 0 )
01371     return; // just in case reload wasn't called before
01372   KConfig* config = KMKernel::config();
01373   QStringList existingFolders;
01374   QListViewItemIterator fldIt(this);
01375   QMap<QString,bool> folderMap;
01376   KMFolderTreeItem *fti;
01377   for (QListViewItemIterator fldIt(this); fldIt.current(); fldIt++)
01378   {
01379     fti = static_cast<KMFolderTreeItem*>(fldIt.current());
01380     if (fti && fti->folder())
01381       folderMap.insert(fti->folder()->idString(), true);
01382   }
01383   QStringList groupList = config->groupList();
01384   QString name;
01385   for (QStringList::Iterator grpIt = groupList.begin();
01386     grpIt != groupList.end(); grpIt++)
01387   {
01388     if ((*grpIt).left(7) != "Folder-") continue;
01389     name = (*grpIt).mid(7);
01390     if (folderMap.find(name) == folderMap.end())
01391     {
01392       KMFolder* folder = kmkernel->findFolderById( name );
01393       if ( folder ) {
01394         if ( kmkernel->iCalIface().hideResourceFolder( folder )
01395            ||  kmkernel->iCalIface().hideResourceAccountRoot( folder ) )
01396           continue; // hidden IMAP resource folder, don't delete info
01397         if ( folder->noContent() )
01398           continue; // we hide nocontent folders if they have no child folders
01399         if ( folder == kmkernel->inboxFolder() )
01400           continue; // local inbox can be hidden as well
01401       }
01402 
01403       //KMessageBox::error( 0, "cleanupConfigFile: Deleting group " + *grpIt );
01404       config->deleteGroup(*grpIt, true);
01405       kdDebug(5006) << "Deleting information about folder " << name << endl;
01406     }
01407   }
01408 }
01409 
01410 
01411 //-----------------------------------------------------------------------------
01412 void KMFolderTree::openFolder()
01413 {
01414     autoopen_timer.stop();
01415     if ( dropItem && !dropItem->isOpen() ) {
01416         dropItem->setOpen( true );
01417         dropItem->repaint();
01418     }
01419 }
01420 
01421 static const int autoopenTime = 750;
01422 
01423 //-----------------------------------------------------------------------------
01424 void KMFolderTree::contentsDragEnterEvent( QDragEnterEvent *e )
01425 {
01426   oldCurrent = 0;
01427   oldSelected = 0;
01428 
01429   oldCurrent = currentItem();
01430   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
01431     if ( it.current()->isSelected() )
01432       oldSelected = it.current();
01433 
01434   setFocus();
01435 
01436   QListViewItem *i = itemAt( contentsToViewport(e->pos()) );
01437   if ( i ) {
01438     dropItem = i;
01439     autoopen_timer.start( autoopenTime );
01440   }
01441   else
01442     dropItem = 0;
01443 
01444   e->accept( acceptDrag(e) );
01445 }
01446 
01447 //-----------------------------------------------------------------------------
01448 void KMFolderTree::contentsDragMoveEvent( QDragMoveEvent *e )
01449 {
01450     QPoint vp = contentsToViewport(e->pos());
01451     QListViewItem *i = itemAt( vp );
01452     if ( i ) {
01453         bool dragAccepted = acceptDrag( e );
01454         if ( dragAccepted ) {
01455             setCurrentItem( i );
01456         }
01457 
01458         if ( i != dropItem ) {
01459             autoopen_timer.stop();
01460             dropItem = i;
01461             autoopen_timer.start( autoopenTime );
01462         }
01463 
01464         if ( dragAccepted ) {
01465             e->accept( itemRect(i) );
01466 
01467             switch ( e->action() ) {
01468                 case QDropEvent::Copy:
01469                 break;
01470                 case QDropEvent::Move:
01471                 e->acceptAction();
01472                 break;
01473                 case QDropEvent::Link:
01474                 e->acceptAction();
01475                 break;
01476                 default:
01477                 ;
01478             }
01479         } else {
01480             e->accept( false );
01481         }
01482     } else {
01483         e->accept( false );
01484         autoopen_timer.stop();
01485         dropItem = 0;
01486     }
01487 }
01488 
01489 //-----------------------------------------------------------------------------
01490 void KMFolderTree::contentsDragLeaveEvent( QDragLeaveEvent * )
01491 {
01492     if (!oldCurrent) return;
01493 
01494     autoopen_timer.stop();
01495     dropItem = 0;
01496 
01497     setCurrentItem( oldCurrent );
01498     if ( oldSelected )
01499       setSelected( oldSelected, true );
01500 }
01501 
01502 //-----------------------------------------------------------------------------
01503 void KMFolderTree::contentsDropEvent( QDropEvent *e )
01504 {
01505     autoopen_timer.stop();
01506 
01507     QListViewItem *item = itemAt( contentsToViewport(e->pos()) );
01508     KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01509     // Check that each pointer is not null
01510     for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = mCopySourceFolders.constBegin();
01511       it != mCopySourceFolders.constEnd(); ++it ) {
01512       if ( ! (*it) ) {
01513     fti = 0;
01514     break;
01515       }
01516     }
01517     if (fti && mCopySourceFolders.count() == 1)
01518     {
01519       KMFolder *source = mCopySourceFolders.first();
01520       // if we are dragging to ourselves or to our parent, set fti to 0 so nothing is done
01521       if (source == fti->folder() || source->parent()->owner() == fti->folder()) fti = 0;
01522     }
01523     if (fti && acceptDrag(e) && ( fti != oldSelected || e->source() != mMainWidget->headers()->viewport() ) )
01524     {
01525       if ( e->provides("application/x-qlistviewitem") ) {
01526         int action = dndMode( true /* always ask */ );
01527         if ( (action == DRAG_COPY || action == DRAG_MOVE) && !mCopySourceFolders.isEmpty() ) {
01528           for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = mCopySourceFolders.constBegin();
01529                 it != mCopySourceFolders.constEnd(); ++it ) {
01530             if ( ! (*it)->isMoveable() )
01531               action = DRAG_COPY;
01532           }
01533           moveOrCopyFolder( mCopySourceFolders, fti->folder(), (action == DRAG_MOVE) );
01534         }
01535       } else {
01536         if ( e->source() == mMainWidget->headers()->viewport() ) {
01537           int action;
01538           if ( mMainWidget->headers()->folder() && mMainWidget->headers()->folder()->isReadOnly() )
01539             action = DRAG_COPY;
01540           else
01541             action = dndMode();
01542           // KMHeaders does copy/move itself
01543           if ( action == DRAG_MOVE && fti->folder() )
01544             emit folderDrop( fti->folder() );
01545           else if ( action == DRAG_COPY && fti->folder() )
01546             emit folderDropCopy( fti->folder() );
01547         } else {
01548           handleMailListDrop( e, fti->folder() );
01549         }
01550       }
01551       e->accept( true );
01552     } else
01553       e->accept( false );
01554 
01555     dropItem = 0;
01556 
01557     setCurrentItem( oldCurrent );
01558     if ( oldCurrent) mLastItem = static_cast<KMFolderTreeItem*>(oldCurrent);
01559     if ( oldSelected )
01560     {
01561       clearSelection();
01562       setSelected( oldSelected, true );
01563     }
01564 
01565     mCopySourceFolders.clear();
01566 }
01567 
01568 //-----------------------------------------------------------------------------
01569 void KMFolderTree::slotFolderExpanded( QListViewItem * item )
01570 {
01571   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01572   if ( !fti || !fti->folder() || !fti->folder()->storage() ) return;
01573 
01574   fti->setFolderSize( fti->folder()->storage()->folderSize() );
01575 
01576   if( fti->folder()->folderType() == KMFolderTypeImap )
01577   {
01578     KMFolderImap *folder = static_cast<KMFolderImap*>( fti->folder()->storage() );
01579     // if we should list all folders we limit this to the root folder
01580     if ( !folder->account() || ( !folder->account()->listOnlyOpenFolders() &&
01581          fti->parent() ) )
01582       return;
01583     if ( folder->getSubfolderState() == KMFolderImap::imapNoInformation )
01584     {
01585       // check if all parents are expanded
01586       QListViewItem *parent = item->parent();
01587       while ( parent )
01588       {
01589         if ( !parent->isOpen() )
01590           return;
01591         parent = parent->parent();
01592       }
01593       // the tree will be reloaded after that
01594       bool success = folder->listDirectory();
01595       if (!success) fti->setOpen( false );
01596       if ( fti->childCount() == 0 && fti->parent() )
01597         fti->setExpandable( false );
01598     }
01599   }
01600 }
01601 
01602 
01603 //-----------------------------------------------------------------------------
01604 void KMFolderTree::slotFolderCollapsed( QListViewItem * item )
01605 {
01606   slotResetFolderList( item, false );
01607   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01608   if ( !fti || !fti->folder() || !fti->folder()->storage() ) return;
01609 
01610   fti->setFolderSize( fti->folder()->storage()->folderSize() );
01611 }
01612 
01613 //-----------------------------------------------------------------------------
01614 void KMFolderTree::slotRenameFolder(QListViewItem *item, int col,
01615                 const QString &text)
01616 {
01617 
01618   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01619 
01620   if ((!fti) || (fti && fti->folder() && col != 0 && !currentFolder()->child()))
01621           return;
01622 
01623   QString fldName, oldFldName;
01624 
01625   oldFldName = fti->name(0);
01626 
01627   if (!text.isEmpty())
01628           fldName = text;
01629   else
01630           fldName = oldFldName;
01631 
01632   fldName.replace("/", "");
01633   fldName.replace(QRegExp("^\\."), "");
01634 
01635   if (fldName.isEmpty())
01636           fldName = i18n("unnamed");
01637 
01638   fti->setText(0, fldName);
01639   fti->folder()->rename(fldName, &(kmkernel->folderMgr()->dir()));
01640 }
01641 
01642 //-----------------------------------------------------------------------------
01643 void KMFolderTree::slotUpdateCountsDelayed(KMFolder * folder)
01644 {
01645 //  kdDebug(5006) << "KMFolderTree::slotUpdateCountsDelayed()" << endl;
01646   if ( !mFolderToUpdateCount.contains( folder->idString() ) )
01647   {
01648 //    kdDebug( 5006 )<< "adding " << folder->idString() << " to updateCountList " << endl;
01649     mFolderToUpdateCount.insert( folder->idString(),folder );
01650   }
01651   if ( !mUpdateCountTimer->isActive() )
01652     mUpdateCountTimer->start( 500 );
01653 }
01654 
01655 
01656 void KMFolderTree::slotUpdateCountTimeout()
01657 {
01658 //  kdDebug(5006) << "KMFolderTree::slotUpdateCountTimeout()" << endl;
01659 
01660   QMap<QString,KMFolder*>::iterator it;
01661   for ( it= mFolderToUpdateCount.begin();
01662       it!=mFolderToUpdateCount.end();
01663       ++it )
01664   {
01665     slotUpdateCounts( it.data() );
01666   }
01667   mFolderToUpdateCount.clear();
01668   mUpdateCountTimer->stop();
01669 
01670 }
01671 
01672 void KMFolderTree::updatePopup() const
01673 {
01674    mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
01675    mPopup->setItemChecked( mTotalPop, isTotalActive() );
01676    mPopup->setItemChecked( mSizePop, isSizeActive() );
01677 }
01678 
01679 //-----------------------------------------------------------------------------
01680 void KMFolderTree::toggleColumn(int column, bool openFolders)
01681 {
01682   if (column == unread)
01683   {
01684     // switch unread
01685     if ( isUnreadActive() )
01686     {
01687       removeUnreadColumn();
01688       reload();
01689     } else {
01690       addUnreadColumn( i18n("Unread"), 70 );
01691       reload();
01692     }
01693     // toggle KPopupMenu
01694     mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
01695 
01696   } else if (column == total) {
01697     // switch total
01698     if ( isTotalActive() )
01699     {
01700       removeTotalColumn();
01701       reload();
01702     } else {
01703       addTotalColumn( i18n("Total"), 70 );
01704       reload(openFolders);
01705     }
01706     mPopup->setItemChecked( mTotalPop, isTotalActive() );
01707   } else if (column == foldersize) {
01708     // switch total
01709     if ( isSizeActive() )
01710     {
01711       removeSizeColumn();
01712       reload();
01713     } else {
01714       addSizeColumn( i18n("Size"), 70 );
01715       reload( openFolders );
01716     }
01717     // toggle KPopupMenu
01718     mPopup->setItemChecked( mSizePop, isSizeActive() );
01719 
01720   } else kdDebug(5006) << "unknown column:" << column << endl;
01721 
01722   // toggles the switches of the mainwin
01723   emit columnsChanged();
01724 }
01725 
01726 //-----------------------------------------------------------------------------
01727 void KMFolderTree::slotToggleUnreadColumn()
01728 {
01729   toggleColumn(unread);
01730 }
01731 
01732 //-----------------------------------------------------------------------------
01733 void KMFolderTree::slotToggleTotalColumn()
01734 {
01735   // activate the total-column and force the folders to be opened
01736   toggleColumn(total, true);
01737 }
01738 
01739 //-----------------------------------------------------------------------------
01740 void KMFolderTree::slotToggleSizeColumn()
01741 {
01742   // activate the size-column and force the folders to be opened
01743   toggleColumn(foldersize, true);
01744 }
01745 
01746 
01747 //-----------------------------------------------------------------------------
01748 bool KMFolderTree::eventFilter( QObject *o, QEvent *e )
01749 {
01750   if ( e->type() == QEvent::MouseButtonPress &&
01751       static_cast<QMouseEvent*>(e)->button() == RightButton &&
01752       o->isA("QHeader") )
01753   {
01754     mPopup->popup( static_cast<QMouseEvent*>(e)->globalPos() );
01755     return true;
01756   }
01757   return KFolderTree::eventFilter(o, e);
01758 }
01759 
01760 //-----------------------------------------------------------------------------
01761 void KMFolderTree::slotCheckMail()
01762 {
01763   if (!currentItem())
01764     return;
01765   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(currentItem());
01766   KMFolder* folder = fti->folder();
01767   if (folder && folder->storage() ) {
01768       if ( KMAccount* acct = folder->storage()->account() ) {
01769          kmkernel->acctMgr()->singleCheckMail(acct, true);
01770       }
01771   }
01772 }
01773 
01774 //-----------------------------------------------------------------------------
01775 void KMFolderTree::slotNewMessageToMailingList()
01776 {
01777   KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>( currentItem() );
01778   if ( !fti || !fti->folder() )
01779     return;
01780   KMCommand *command = new KMMailingListPostCommand( this, fti->folder() );
01781   command->start();
01782 }
01783 
01784 //-----------------------------------------------------------------------------
01785 void KMFolderTree::createFolderList( QStringList *str,
01786                                      QValueList<QGuardedPtr<KMFolder> > *folders,
01787                                      bool localFolders,
01788                                      bool imapFolders,
01789                                      bool dimapFolders,
01790                                      bool searchFolders,
01791                                      bool includeNoContent,
01792                                      bool includeNoChildren )
01793 {
01794   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
01795   {
01796     KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
01797     if (!fti || !fti->folder()) continue;
01798     // type checks
01799     KMFolder* folder = fti->folder();
01800     if (!imapFolders && folder->folderType() == KMFolderTypeImap) continue;
01801     if (!dimapFolders && folder->folderType() == KMFolderTypeCachedImap) continue;
01802     if (!localFolders && (folder->folderType() == KMFolderTypeMbox ||
01803                           folder->folderType() == KMFolderTypeMaildir)) continue;
01804     if (!searchFolders && folder->folderType() == KMFolderTypeSearch) continue;
01805     if (!includeNoContent && folder->noContent()) continue;
01806     if (!includeNoChildren && folder->noChildren()) continue;
01807     QString prefix;
01808     prefix.fill( ' ', 2 * fti->depth() );
01809     str->append(prefix + fti->text(0));
01810     folders->append(fti->folder());
01811   }
01812 }
01813 
01814 //-----------------------------------------------------------------------------
01815 void KMFolderTree::slotResetFolderList( QListViewItem* item, bool startList )
01816 {
01817   if ( !item )
01818     item = currentItem();
01819 
01820   KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>( item );
01821   if ( fti && fti->folder() &&
01822        fti->folder()->folderType() == KMFolderTypeImap )
01823   {
01824     KMFolderImap *folder = static_cast<KMFolderImap*>( fti->folder()->storage() );
01825     folder->setSubfolderState( KMFolderImap::imapNoInformation );
01826     if ( startList )
01827       folder->listDirectory();
01828   }
01829 }
01830 
01831 //-----------------------------------------------------------------------------
01832 void KMFolderTree::showFolder( KMFolder* folder )
01833 {
01834   if ( !folder ) return;
01835   QListViewItem* item = indexOfFolder( folder );
01836   if ( item )
01837   {
01838     doFolderSelected( item );
01839     ensureItemVisible( item );
01840   }
01841 }
01842 
01843 //-----------------------------------------------------------------------------
01844 void KMFolderTree::folderToPopupMenu( MenuAction action, QObject *receiver,
01845     KMMenuToFolder *aMenuToFolder, QPopupMenu *menu, QListViewItem *item )
01846 {
01847   while ( menu->count() )
01848   {
01849     QPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup();
01850     if ( popup )
01851       delete popup;
01852     else
01853       menu->removeItemAt( 0 );
01854   }
01855   // connect the signals
01856   if ( action == MoveMessage || action == MoveFolder )
01857   {
01858     disconnect( menu, SIGNAL(activated(int)), receiver,
01859         SLOT(moveSelectedToFolder(int)) );
01860     connect( menu, SIGNAL(activated(int)), receiver,
01861         SLOT(moveSelectedToFolder(int)) );
01862   } else {
01863     disconnect( menu, SIGNAL(activated(int)), receiver,
01864         SLOT(copySelectedToFolder(int)) );
01865     connect( menu, SIGNAL(activated(int)), receiver,
01866         SLOT(copySelectedToFolder(int)) );
01867   }
01868   if ( !item ) {
01869     item = firstChild();
01870 
01871     // avoid a popup menu with the single entry 'Local Folders' if there
01872     // are no IMAP accounts
01873     if ( childCount() == 2 && action != MoveFolder ) { // only 'Local Folders' and 'Searches'
01874       KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>( item );
01875       if ( fti->protocol() == KFolderTreeItem::Search ) {
01876         // skip 'Searches'
01877         item = item->nextSibling();
01878         fti = static_cast<KMFolderTreeItem*>( item );
01879       }
01880       folderToPopupMenu( action, receiver, aMenuToFolder, menu, fti->firstChild() );
01881       return;
01882     }
01883   }
01884 
01885   while ( item )
01886   {
01887     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( item );
01888     if ( fti->protocol() == KFolderTreeItem::Search )
01889     {
01890       // skip search folders
01891       item = item->nextSibling();
01892       continue;
01893     }
01894     QString label = fti->text( 0 );
01895     label.replace( "&","&&" );
01896     if ( fti->firstChild() )
01897     {
01898       // new level
01899       QPopupMenu* popup = new QPopupMenu( menu, "subMenu" );
01900       folderToPopupMenu( action, receiver, aMenuToFolder, popup, fti->firstChild() );
01901       bool subMenu = false;
01902       if ( ( action == MoveMessage || action == CopyMessage ) &&
01903            fti->folder() && !fti->folder()->noContent() )
01904         subMenu = true;
01905       if ( ( action == MoveFolder || action == CopyFolder )
01906           && ( !fti->folder() || ( fti->folder() && !fti->folder()->noChildren() ) ) )
01907         subMenu = true;
01908 
01909       QString sourceFolderName;
01910       KMFolderTreeItem* srcItem = dynamic_cast<KMFolderTreeItem*>( currentItem() );
01911       if ( srcItem )
01912         sourceFolderName = srcItem->text( 0 );
01913 
01914       if ( (action == MoveFolder || action == CopyFolder)
01915               && fti->folder() && fti->folder()->child()
01916               && fti->folder()->child()->hasNamedFolder( sourceFolderName ) ) {
01917         subMenu = false;
01918       }
01919 
01920       if ( subMenu )
01921       {
01922         int menuId;
01923         if ( action == MoveMessage || action == MoveFolder )
01924           menuId = popup->insertItem( i18n("Move to This Folder"), -1, 0 );
01925         else
01926           menuId = popup->insertItem( i18n("Copy to This Folder"), -1, 0 );
01927         popup->insertSeparator( 1 );
01928         aMenuToFolder->insert( menuId, fti->folder() );
01929       }
01930       menu->insertItem( label, popup );
01931     } else
01932     {
01933       // insert an item
01934       int menuId = menu->insertItem( label );
01935       if ( fti->folder() )
01936         aMenuToFolder->insert( menuId, fti->folder() );
01937       bool enabled = (fti->folder() ? true : false);
01938       if ( fti->folder() &&
01939            ( fti->folder()->isReadOnly() || fti->folder()->noContent() ) )
01940         enabled = false;
01941       menu->setItemEnabled( menuId, enabled );
01942     }
01943 
01944     item = item->nextSibling();
01945   }
01946 }
01947 
01948 //-----------------------------------------------------------------------------
01949 void KMFolderTree::moveSelectedToFolder( int menuId )
01950 {
01951   moveOrCopyFolder( selectedFolders(), mMenuToFolder[ menuId ], true /*move*/ );
01952 }
01953 
01954 //-----------------------------------------------------------------------------
01955 void KMFolderTree::copySelectedToFolder( int menuId )
01956 {
01957   moveOrCopyFolder( selectedFolders(), mMenuToFolder[ menuId ], false /*copy, don't move*/ );
01958 }
01959 
01960 //-----------------------------------------------------------------------------
01961 void KMFolderTree::moveOrCopyFolder( QValueList<QGuardedPtr<KMFolder> > sources, KMFolder* destination, bool move )
01962 {
01963   kdDebug(5006) << k_funcinfo << "source: " << sources << " destination: " << destination << " move: " << move << endl;
01964 
01965   // Disable drag during copy operation since it prevents from many crashes
01966   setDragEnabled( false );
01967 
01968   KMFolderDir* parent = &(kmkernel->folderMgr()->dir());
01969   if ( destination )
01970     parent = destination->createChildFolder();
01971 
01972   QStringList sourceFolderNames;
01973 
01974   // check if move/copy is possible at all
01975   for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); it != sources.constEnd(); ++it ) {
01976     KMFolder* source = *it;
01977 
01978     // check if folder with same name already exits
01979     QString sourceFolderName;
01980     if ( source )
01981       sourceFolderName = source->label();
01982 
01983     if ( parent->hasNamedFolder( sourceFolderName ) || sourceFolderNames.contains( sourceFolderName ) ) {
01984       KMessageBox::error( this, i18n("<qt>Cannot move or copy folder <b>%1</b> here because a folder with the same name already exists.</qt>")
01985           .arg( sourceFolderName ) );
01986       setDragEnabled( true );
01987       return;
01988     }
01989     sourceFolderNames.append( sourceFolderName );
01990 
01991     // don't move/copy a folder that's still not completely moved/copied
01992     KMFolder *f = source;
01993     while ( f ) {
01994       if ( f->moveInProgress() ) {
01995         KMessageBox::error( this, i18n("<qt>Cannot move or copy folder <b>%1</b> because it is not completely copied itself.</qt>")
01996             .arg( sourceFolderName ) );
01997         setDragEnabled( true );
01998         return;
01999       }
02000       if ( f->parent() )
02001         f = f->parent()->owner();
02002     }
02003 
02004     QString message =
02005       i18n( "<qt>Cannot move or copy folder <b>%1</b> into a subfolder below itself.</qt>" ).
02006           arg( sourceFolderName );
02007     KMFolderDir* folderDir = parent;
02008     // check that the folder can be moved
02009     if ( source && source->child() )
02010     {
02011       while ( folderDir && ( folderDir != &kmkernel->folderMgr()->dir() ) &&
02012           ( folderDir != source->parent() ) )
02013       {
02014         if ( folderDir->findRef( source ) != -1 )
02015         {
02016           KMessageBox::error( this, message );
02017           setDragEnabled( true );
02018           return;
02019         }
02020         folderDir = folderDir->parent();
02021       }
02022     }
02023 
02024     if( source && source->child() && parent &&
02025         ( parent->path().find( source->child()->path() + "/" ) == 0 ) ) {
02026       KMessageBox::error( this, message );
02027       setDragEnabled( true );
02028       return;
02029     }
02030 
02031     if( source && source->child()
02032         && ( parent == source->child() ) ) {
02033       KMessageBox::error( this, message );
02034       setDragEnabled( true );
02035       return;
02036     }
02037   }
02038 
02039   // check if the source folders are independent of each other
02040   for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); move && it != sources.constEnd(); ++it ) {
02041     KMFolderDir *parentDir = (*it)->child();
02042     if ( !parentDir )
02043       continue;
02044     for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it2 = sources.constBegin(); it2 != sources.constEnd(); ++it2 ) {
02045       if ( *it == *it2 )
02046         continue;
02047       KMFolderDir *childDir = (*it2)->parent();
02048       do {
02049         if ( parentDir == childDir || parentDir->findRef( childDir->owner() ) != -1 ) {
02050           KMessageBox::error( this, i18n("Moving the selected folders is not possible") );
02051           setDragEnabled( true );
02052           return;
02053         }
02054         childDir = childDir->parent();
02055       }
02056       while ( childDir && childDir != &kmkernel->folderMgr()->dir() );
02057     }
02058   }
02059 
02060   // de-select moved source folders (can cause crash due to unGetMsg() in KMHeaders)
02061   if ( move ) {
02062     doFolderSelected( indexOfFolder( destination ), false );
02063     oldCurrent = currentItem();
02064   }
02065 
02066   // do the actual move/copy
02067   for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); it != sources.constEnd(); ++it ) {
02068     KMFolder* source = *it;
02069     if ( move ) {
02070       kdDebug(5006) << "move folder " << (source ? source->label(): "Unknown") << " to "
02071         << ( destination ? destination->label() : "Local Folders" ) << endl;
02072       kmkernel->folderMgr()->moveFolder( source, parent );
02073     } else {
02074       kmkernel->folderMgr()->copyFolder( source, parent );
02075     }
02076   }
02077 }
02078 
02079 QDragObject * KMFolderTree::dragObject()
02080 {
02081   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>
02082       (itemAt(viewport()->mapFromGlobal(QCursor::pos())));
02083   if ( !item || !item->parent() || !item->folder() ) // top-level items or something invalid
02084     return 0;
02085   mCopySourceFolders = selectedFolders();
02086 
02087   QDragObject *drag = KFolderTree::dragObject();
02088   if ( drag )
02089     drag->setPixmap( SmallIcon("folder") );
02090   return drag;
02091 }
02092 
02093 void KMFolderTree::copyFolder()
02094 {
02095   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
02096   if ( item ) {
02097     mCopySourceFolders = selectedFolders();
02098     mCutFolder = false;
02099   }
02100   updateCopyActions();
02101 }
02102 
02103 void KMFolderTree::cutFolder()
02104 {
02105   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
02106   if ( item ) {
02107     mCopySourceFolders = selectedFolders();
02108     mCutFolder = true;
02109   }
02110   updateCopyActions();
02111 }
02112 
02113 void KMFolderTree::pasteFolder()
02114 {
02115   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
02116   if ( !mCopySourceFolders.isEmpty() && item && !mCopySourceFolders.contains( item->folder() ) ) {
02117     moveOrCopyFolder( mCopySourceFolders, item->folder(), mCutFolder );
02118     if ( mCutFolder )
02119       mCopySourceFolders.clear();
02120   }
02121   updateCopyActions();
02122 }
02123 
02124 void KMFolderTree::updateCopyActions()
02125 {
02126   KAction *copy = mMainWidget->action("copy_folder");
02127   KAction *cut = mMainWidget->action("cut_folder");
02128   KAction *paste = mMainWidget->action("paste_folder");
02129   KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
02130 
02131   if ( !item ||  !item->folder() ) {
02132     copy->setEnabled( false );
02133     cut->setEnabled( false );
02134   } else {
02135     copy->setEnabled( true );
02136     cut->setEnabled( item->folder()->isMoveable() );
02137   }
02138 
02139   if ( mCopySourceFolders.isEmpty() )
02140     paste->setEnabled( false );
02141   else
02142     paste->setEnabled( true );
02143 }
02144 
02145 void KMFolderTree::slotAddToFavorites()
02146 {
02147   KMail::FavoriteFolderView *favView = mMainWidget->favoriteFolderView();
02148   assert( favView );
02149   for ( QListViewItemIterator it( this ); it.current(); ++it ) {
02150     if ( it.current()->isSelected() )
02151       favView->addFolder( static_cast<KMFolderTreeItem*>( it.current() ) );
02152   }
02153 }
02154 
02155 void KMFolderTree::slotUnhideLocalInbox()
02156 {
02157   disconnect( kmkernel->inboxFolder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
02158               this, SLOT(slotUnhideLocalInbox()) );
02159   reload();
02160 }
02161 
02162 void KMFolderTree::delayedReload()
02163 {
02164   QTimer::singleShot( 0, this, SLOT(reload()) );
02165 }
02166 
02167 #include "kmfoldertree.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys