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