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