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