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