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