diff --git a/Makefile.am b/Makefile.am index f904acd4f..c1e8f1e11 100644 --- a/Makefile.am +++ b/Makefile.am @@ -96,7 +96,7 @@ libkmailprivate_la_SOURCES = kmmessage.cpp kmmainwin.cpp configuredialog.cpp \ headerlistquicksearch.cpp acljobs.cpp folderdiaacltab.cpp \ partnodebodypart.cpp \ expirejob.cpp compactionjob.cpp jobscheduler.cpp callback.cpp \ - listjob.cpp \ + listjob.cpp renamejob.cpp copyfolderjob.cpp \ composercryptoconfiguration.ui \ warningconfiguration.ui smimeconfiguration.ui annotationjobs.cpp \ accountcombobox.cpp diff --git a/copyfolderjob.cpp b/copyfolderjob.cpp new file mode 100644 index 000000000..855de3f40 --- /dev/null +++ b/copyfolderjob.cpp @@ -0,0 +1,203 @@ +/** + * Copyright (c) 2005 Till Adam + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of this program with any edition of + * the Qt library by Trolltech AS, Norway (or with modified versions + * of Qt that use the same license as Qt), and distribute linked + * combinations including the two. You must obey the GNU General + * Public License in all respects for all of the code used other than + * Qt. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from + * your version. + */ + +#include "copyfolderjob.h" +#include "folderstorage.h" +#include "kmfolder.h" +#include "kmfolderdir.h" +#include "kmfoldertype.h" +#include "kmfoldermgr.h" +#include "kmcommands.h" +#include "kmmsgbase.h" +#include "undostack.h" + +#include +#include +#include + +using namespace KMail; + +CopyFolderJob::CopyFolderJob( const FolderStorage* const storage, KMFolderDir* const newParent ) + : FolderJob( 0, tOther, (storage ? storage->folder() : 0) ), + mStorage( storage ), mNewParent( newParent ), + mNewFolder( 0 ), mChildFolderNodeIterator( *mStorage->folder()->createChildFolder() ), + mNextChildFolder( 0 ) +{ +} + +CopyFolderJob::~CopyFolderJob() +{ + kdDebug(5006) << k_funcinfo << endl; +} + +/* + * The basic strategy is to first create the target folder, then copy all the mail + * from the source to the target folder, then recurse for each of the folder's children + */ +void CopyFolderJob::execute() +{ + createTargetDir(); + copyMessagesToTargetDir(); +} + +void CopyFolderJob::copyMessagesToTargetDir() +{ + // Hmmmm. Tasty hack. Can I have fries with that? + const_cast( mStorage )->blockSignals( true ); + // move all messages to the new folder + QPtrList msgList; + for ( int i = 0; i < mStorage->count(); i++ ) + { + const KMMsgBase* msgBase = mStorage->getMsgBase( i ); + assert( msgBase ); + msgList.append( msgBase ); + } + if ( msgList.count() == 0 ) { + slotCopyNextChild(); // no contents, check subfolders + const_cast( mStorage )->blockSignals( false ); + } else { + KMCommand *command = new KMCopyCommand( mNewFolder, msgList ); + connect( command, SIGNAL( completed( KMCommand * ) ), + this, SLOT( slotCopyCompleted( KMCommand * ) ) ); + command->start(); + } +} + +void CopyFolderJob::slotCopyCompleted( KMCommand* command ) +{ + kdDebug(5006) << k_funcinfo << (command?command->result():0) << endl; + disconnect( command, SIGNAL( completed( KMCommand * ) ), + this, SLOT( slotCopyCompleted( KMCommand * ) ) ); + + const_cast( mStorage )->blockSignals( false ); + + if ( command && command->result() != KMCommand::OK ) { + rollback(); + } + // if we have children, recurse + if ( mStorage->folder()->child() ) { + slotCopyNextChild(); + } else { + emit folderCopyComplete( true ); + deleteLater(); + } +} + +void CopyFolderJob::slotCopyNextChild( bool success ) +{ + //kdDebug(5006) << k_funcinfo << endl; + if ( mNextChildFolder ) + mNextChildFolder->close(); // refcount + // previous sibling failed + if ( !success ) { + kdDebug(5006) << "Failed to copy one subfolder, let's not continue: " << mNewFolder->prettyURL() << endl; + rollback(); + emit folderCopyComplete( false ); + deleteLater(); + } + + KMFolderNode* node = mChildFolderNodeIterator.current(); + while ( node && node->isDir() ) { + ++mChildFolderNodeIterator; + node = mChildFolderNodeIterator.current(); + } + if ( node ) { + mNextChildFolder = static_cast(node); + ++mChildFolderNodeIterator; + } else { + // no more children, we are done + emit folderCopyComplete( true ); + deleteLater(); + return; + } + + KMFolderDir * const dir = mNewFolder->createChildFolder(); + if ( !dir ) { + kdDebug(5006) << "Failed to create subfolders of: " << mNewFolder->prettyURL() << endl; + emit folderCopyComplete( false ); + deleteLater(); + return; + } + // let it do its thing and report back when we are ready to do the next sibling + mNextChildFolder->open(); // refcount + FolderJob* job = new CopyFolderJob( mNextChildFolder->storage(), dir); + connect( job, SIGNAL( folderCopyComplete( bool ) ), + this, SLOT( slotCopyNextChild( bool ) ) ); + job->start(); +} + + +// FIXME factor into CreateFolderJob and make async, so it works with online imap +// FIXME this is the same in renamejob. Refactor RenameJob to use a copy job and then delete +void CopyFolderJob::createTargetDir() +{ + KMFolderMgr* folderMgr = kmkernel->folderMgr(); + if ( mNewParent->type() == KMImapDir ) { + folderMgr = kmkernel->imapFolderMgr(); + } else if ( mNewParent->type() == KMDImapDir ) { + folderMgr = kmkernel->dimapFolderMgr(); + } + + // get the default mailbox type + KConfig * const config = KMKernel::config(); + KConfigGroupSaver saver(config, "General"); + int deftype = config->readNumEntry("default-mailbox-format", 1); + if ( deftype < 0 || deftype > 1 ) deftype = 1; + + // the type of the new folder + KMFolderType typenew = + ( deftype == 0 ) ? KMFolderTypeMbox : KMFolderTypeMaildir; + if ( mNewParent->owner() ) + typenew = mNewParent->owner()->folderType(); + + mNewFolder = folderMgr->createFolder( mStorage->name(), false, typenew, mNewParent ); + if ( !mNewFolder ) + { + kdWarning(5006) << k_funcinfo << "could not create folder" << endl; + emit folderCopyComplete( false ); + deleteLater(); + return; + } + // inherit the folder type + // FIXME we should probably copy over most if not all settings + mNewFolder->storage()->setContentsType( mStorage->contentsType() ); + mNewFolder->storage()->writeConfig(); + kdDebug(5006)<< "CopyJob::createTargetDir - " << mStorage->folder()->idString() + << " |=> " << mNewFolder->idString() << endl; +} + + +void CopyFolderJob::rollback() +{ + // FIXME do something + KMFolderMgr * const folderMgr = mNewFolder->createChildFolder()->manager(); + folderMgr->remove( mNewFolder ); + emit folderCopyComplete( false ); + deleteLater(); +} +#include "copyfolderjob.moc" diff --git a/copyfolderjob.h b/copyfolderjob.h new file mode 100644 index 000000000..0a6479ee2 --- /dev/null +++ b/copyfolderjob.h @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2005 Till Adam + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of this program with any edition of + * the Qt library by Trolltech AS, Norway (or with modified versions + * of Qt that use the same license as Qt), and distribute linked + * combinations including the two. You must obey the GNU General + * Public License in all respects for all of the code used other than + * Qt. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from + * your version. + */ +#ifndef COPYFOLDERJOB_H +#define COPYFOLDERJOB_H + +#include "folderjob.h" + +class FolderStorage; +class KMFolderDir; +class KMFolder; +class KMCommand; + +class KMFolderNode; + +namespace KMail { + +/** + * Copy a hierarchy of folders somewhere else in the folder tree. Currently + * online imap folders are not supported as target folders, and the same is + * true for search folders where it does not make much sense for them to be + * target folders. + */ +class CopyFolderJob : public FolderJob +{ + Q_OBJECT +public: + /** + * Create a new job + * @param storage of the folder that should be copied + * @param newParent the target parent folder + */ + CopyFolderJob( const FolderStorage* const storage, KMFolderDir* const newParent = 0 ); + + virtual ~CopyFolderJob(); + + virtual void execute(); + +protected slots: + + /** Create the target directory under the new parent. */ + void createTargetDir(); + + /** Copy all messages from the original folder to mNewFolder */ + void copyMessagesToTargetDir(); + + /** Called when the CopyCommand has either succesfully completed copying + * the contents of our folder to the new location or failed. */ + void slotCopyCompleted( KMCommand *command ); + + /** Called when the previous sibling's copy operation completed. + * @param success indicates whether the last copy was successful. */ + void slotCopyNextChild( bool success = true ); + + /** Called when one of the operations of the foldre itself or one of it's + * child folders failed and the already created target folder needs to be + * removed again. */ + void rollback(); + +signals: + /** Emitted when the job is done, check the success bool */ + void folderCopyComplete( bool success ); + +protected: + const FolderStorage* const mStorage; + KMFolderDir* const mNewParent; + KMFolder* mNewFolder; + QPtrListIterator mChildFolderNodeIterator; + KMFolder* mNextChildFolder; +}; + +} // namespace KMail + +#endif /* COPYFOLDERJOB_H */ diff --git a/kmacctcachedimap.cpp b/kmacctcachedimap.cpp index 00df169df..eadf10ac8 100644 --- a/kmacctcachedimap.cpp +++ b/kmacctcachedimap.cpp @@ -387,7 +387,7 @@ void KMAcctCachedImap::addDeletedFolder( KMFolder* folder ) if ( folder->folderType() != KMFolderTypeCachedImap ) return; KMFolderCachedImap* storage = static_cast(folder->storage()); - mDeletedFolders << storage->imapPath(); + addDeletedFolder( storage->imapPath() ); kdDebug(5006) << k_funcinfo << storage->imapPath() << endl; // Add all child folders too @@ -402,6 +402,11 @@ void KMAcctCachedImap::addDeletedFolder( KMFolder* folder ) } } +void KMAcctCachedImap::addDeletedFolder( const QString& imapPath ) +{ + mDeletedFolders << imapPath; +} + QStringList KMAcctCachedImap::deletedFolderPaths( const QString& subFolderPath ) const { QStringList lst; diff --git a/kmacctcachedimap.h b/kmacctcachedimap.h index 0e9155309..0ed484673 100644 --- a/kmacctcachedimap.h +++ b/kmacctcachedimap.h @@ -116,6 +116,12 @@ public: */ void addDeletedFolder( KMFolder* folder ); + /** + * Remember that a folder got explicitely deleted - NOT including all child folders + * This is used when renaming a folder. + */ + void addDeletedFolder( const QString& imapPath ); + /** * Ask if a folder was explicitely deleted in this session */ diff --git a/kmfolder.cpp b/kmfolder.cpp index 821e8e1b5..108466340 100644 --- a/kmfolder.cpp +++ b/kmfolder.cpp @@ -805,4 +805,9 @@ void KMFolder::reallyAddCopyOfMsg( KMMessage* aMsg ) mStorage->reallyAddCopyOfMsg( aMsg ); } +bool KMFolder::isMoveable() const +{ + return !isSystemFolder(); +} + #include "kmfolder.moc" diff --git a/kmfolder.h b/kmfolder.h index 5a0998caa..b7902826b 100644 --- a/kmfolder.h +++ b/kmfolder.h @@ -497,6 +497,9 @@ public: bool ignoreNewMail() const { return mIgnoreNewMail; } void setIgnoreNewMail( bool b ) { mIgnoreNewMail = b; } + /** Returns true if this folder can be moved */ + bool isMoveable() const; + signals: /** Emitted when the status, name, or associated accounts of this folder changed. */ diff --git a/kmfolderdir.h b/kmfolderdir.h index 15976fe95..c77d90724 100644 --- a/kmfolderdir.h +++ b/kmfolderdir.h @@ -52,7 +52,7 @@ public: /** Returns the folder whose children we are holding */ KMFolder* owner() const { return mOwner; } - virtual KMFolderDirType type() { return mDirType; } + virtual KMFolderDirType folderDirType() const { return mDirType; } protected: KMFolder * mOwner; diff --git a/kmfolderimap.h b/kmfolderimap.h index 75241b2f2..40965bb1d 100644 --- a/kmfolderimap.h +++ b/kmfolderimap.h @@ -98,7 +98,7 @@ public: virtual KMMessage* getMsg(int idx); /** The path to the imap folder on the server */ void setImapPath(const QString &path) { mImapPath = path; } - QString imapPath() { return mImapPath; } + QString imapPath() const { return mImapPath; } /** The highest UID in the folder */ ulong lastUid(); diff --git a/kmfoldermgr.cpp b/kmfoldermgr.cpp index 9f6c6ed50..452219c92 100644 --- a/kmfoldermgr.cpp +++ b/kmfoldermgr.cpp @@ -30,6 +30,11 @@ #include "undostack.h" #include "kmmsgdict.h" #include "folderstorage.h" +#include "renamejob.h" +#include "copyfolderjob.h" + +using KMail::RenameJob; +using KMail::CopyFolderJob; //----------------------------------------------------------------------------- KMFolderMgr::KMFolderMgr(const QString& aBasePath, KMFolderDirType dirType): @@ -577,4 +582,34 @@ uint KMFolderMgr::createId() return newId; } +//----------------------------------------------------------------------------- +void KMFolderMgr::moveFolder( KMFolder* folder, KMFolderDir *newParent ) +{ + renameFolder( folder, folder->name(), newParent ); +} + +//----------------------------------------------------------------------------- +void KMFolderMgr::renameFolder( KMFolder* folder, const QString& newName, + KMFolderDir *newParent ) +{ + RenameJob* job = new RenameJob( folder->storage(), newName, newParent ); + connect( job, SIGNAL( renameDone( QString, bool ) ), + this, SLOT( slotRenameDone( QString, bool ) ) ); + job->start(); +} + +//----------------------------------------------------------------------------- +void KMFolderMgr::copyFolder( KMFolder* folder, KMFolderDir *newParent ) +{ + kdDebug(5006) << "Copy folder: " << folder->prettyURL() << endl; + CopyFolderJob* job = new CopyFolderJob( folder->storage(), newParent ); + job->start(); +} + +//----------------------------------------------------------------------------- +void KMFolderMgr::slotRenameDone( QString, bool success ) +{ + kdDebug(5006) << k_funcinfo << success << endl; +} + #include "kmfoldermgr.moc" diff --git a/kmfoldermgr.h b/kmfoldermgr.h index f357b5c69..6493ab95a 100644 --- a/kmfoldermgr.h +++ b/kmfoldermgr.h @@ -124,6 +124,15 @@ public: /** Create a new unique ID */ uint createId(); + /** Move a folder */ + void moveFolder( KMFolder* folder, KMFolderDir* newParent ); + + /** Rename or move a folder */ + void renameFolder( KMFolder* folder, const QString& newName, + KMFolderDir* newParent = 0 ); + /** Copy a folder */ + void copyFolder( KMFolder* folder, KMFolderDir* newParent ); + public slots: /** GUI action: compact all folders that need to be compacted */ void compactAll() { compactAllFolders( true ); } @@ -134,6 +143,9 @@ public slots: /** Called from KMFolder::remove when the folderstorage was removed */ void removeFolderAux(KMFolder* obsoleteFolder, bool success); + /** Called when the renaming of a folder is done */ + void slotRenameDone( QString newName, bool success ); + signals: /** Emitted when the list of folders has changed. This signal is a hook where clients like the KMFolderTree tree-view can connect. The signal diff --git a/kmfoldertree.cpp b/kmfoldertree.cpp index 8eabaf177..0c8429a55 100644 --- a/kmfoldertree.cpp +++ b/kmfoldertree.cpp @@ -923,6 +923,22 @@ void KMFolderTree::slotContextMenuRequested( QListViewItem *lvi, i18n("&New Subfolder..."), this, SLOT(addChildFolder())); } +#ifdef DISABLED_BECAUSE_IT_IS_BUGGY + if ( fti->folder()->isMoveable() ) + { + QPopupMenu *moveMenu = new QPopupMenu( folderMenu ); + folderToPopupMenu( MoveFolder, this, &mMenuToFolder, moveMenu ); + folderMenu->insertItem( i18n("&Move Folder To"), moveMenu ); + } +#endif + if ( fti->folder() + && fti->folder()->folderType() != KMFolderTypeImap ) { +// && fti->folder()->folderType() != KMFolderTypeSearch ) { + // copy folder + QPopupMenu *copyMenu = new QPopupMenu( folderMenu ); + folderToPopupMenu( CopyFolder, this, &mMenuToFolder, copyMenu ); + folderMenu->insertItem( i18n("&Copy Folder To"), copyMenu ); + } // Want to be able to display properties for ALL folders, // so we can edit expiry properties. @@ -1623,5 +1639,158 @@ void KMFolderTree::showFolder( KMFolder* folder ) } } +//----------------------------------------------------------------------------- +void KMFolderTree::folderToPopupMenu( MenuAction action, QObject *receiver, + KMMenuToFolder *aMenuToFolder, QPopupMenu *menu, QListViewItem *item ) +{ + while ( menu->count() ) + { + QPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup(); + if ( popup ) + delete popup; + else + menu->removeItemAt( 0 ); + } + // connect the signals + if ( action == MoveMessage || action == MoveFolder ) + { + disconnect( menu, SIGNAL(activated(int)), receiver, + SLOT(moveSelectedToFolder(int)) ); + connect( menu, SIGNAL(activated(int)), receiver, + SLOT(moveSelectedToFolder(int)) ); + } else { + disconnect( menu, SIGNAL(activated(int)), receiver, + SLOT(copySelectedToFolder(int)) ); + connect( menu, SIGNAL(activated(int)), receiver, + SLOT(copySelectedToFolder(int)) ); + } + if ( !item ) { + item = firstChild(); + + // avoid a popup menu with the single entry 'Local Folders' if there + // are no IMAP accounts + if ( childCount() == 2 && action != MoveFolder ) { // only 'Local Folders' and 'Searches' + KMFolderTreeItem *fti = static_cast( item ); + if ( fti->protocol() == KFolderTreeItem::Search ) { + // skip 'Searches' + item = item->nextSibling(); + fti = static_cast( item ); + } + folderToPopupMenu( action, receiver, aMenuToFolder, menu, fti->firstChild() ); + return; + } + } + + while ( item ) + { + KMFolderTreeItem* fti = static_cast( item ); + if ( fti->protocol() == KFolderTreeItem::Search ) + { + // skip search folders + item = item->nextSibling(); + continue; + } + QString label = fti->text( 0 ); + label.replace( "&","&&" ); + if ( fti->firstChild() ) + { + // new level + QPopupMenu* popup = new QPopupMenu( menu, "subMenu" ); + folderToPopupMenu( action, receiver, aMenuToFolder, popup, fti->firstChild() ); + bool subMenu = false; + if ( ( action == MoveMessage || action == CopyMessage ) && + fti->folder() && !fti->folder()->noContent() ) + subMenu = true; + if ( ( action == MoveFolder || action == CopyFolder ) + && ( !fti->folder() || ( fti->folder() && !fti->folder()->noChildren() ) ) ) + subMenu = true; + if ( subMenu ) + { + int menuId; + if ( action == MoveMessage || action == MoveFolder ) + menuId = popup->insertItem( i18n("Move to This Folder"), -1, 0 ); + else + menuId = popup->insertItem( i18n("Copy to This Folder"), -1, 0 ); + popup->insertSeparator( 1 ); + aMenuToFolder->insert( menuId, fti->folder() ); + } + menu->insertItem( label, popup ); + } else + { + // insert an item + int menuId = menu->insertItem( label ); + if ( fti->folder() ) + aMenuToFolder->insert( menuId, fti->folder() ); + bool enabled = (fti->folder() ? true : false); + if ( fti->folder() && + ( fti->folder()->isReadOnly() || fti->folder()->noContent() ) ) + enabled = false; + menu->setItemEnabled( menuId, enabled ); + } + + item = item->nextSibling(); + } +} + +//----------------------------------------------------------------------------- +void KMFolderTree::moveSelectedToFolder( int menuId ) +{ + moveOrCopyCurrentFolder( mMenuToFolder[ menuId ], true /*move*/ ); +} + +//----------------------------------------------------------------------------- +void KMFolderTree::copySelectedToFolder( int menuId ) +{ + moveOrCopyCurrentFolder( mMenuToFolder[ menuId ], false /*copy, don't move*/ ); +} + +//----------------------------------------------------------------------------- +void KMFolderTree::moveOrCopyCurrentFolder( KMFolder* destination, bool move ) +{ + KMFolder* folder = currentFolder(); + KMFolderDir* parent = &(kmkernel->folderMgr()->dir()); + if ( destination ) + parent = destination->createChildFolder(); + QString message = + i18n( "Cannot move or copy folder %1 into a subfolder below itself." ). + arg( folder->label() ); + + KMFolderDir* folderDir = parent; + // check that the folder can be moved + if ( folder && folder->child() ) + { + while ( folderDir && ( folderDir != &kmkernel->folderMgr()->dir() ) && + ( folderDir != folder->parent() ) ) + { + if ( folderDir->findRef( folder ) != -1 ) + { + KMessageBox::error( this, message ); + return; + } + folderDir = folderDir->parent(); + } + } + + if( folder && folder->child() && parent && + ( parent->path().find( folder->child()->path() + "/" ) == 0 ) ) { + KMessageBox::error( this, message ); + return; + } + + if( folder && folder->child() + && ( parent == folder->child() ) ) { + KMessageBox::error( this, message ); + return; + } + + if ( move ) { + kdDebug(5006) << "move folder " << currentFolder()->label() << " to " + << ( destination ? destination->label() : "Local Folders" ) << endl; + kmkernel->folderMgr()->moveFolder( folder, parent ); + } else { + kmkernel->folderMgr()->copyFolder( folder, parent ); + } +} + #include "kmfoldertree.moc" diff --git a/kmfoldertree.h b/kmfoldertree.h index 446344892..137f40586 100644 --- a/kmfoldertree.h +++ b/kmfoldertree.h @@ -172,6 +172,18 @@ public: { mFolderToItem.remove( folder ); } + + /** Valid actions for the folderToPopup method */ + enum MenuAction { + CopyMessage, + MoveMessage, + CopyFolder, + MoveFolder + }; + + /** Generate a popup menu that contains all folders that can have content */ + void folderToPopupMenu( MenuAction action, QObject *receiver, KMMenuToFolder *, + QPopupMenu *menu, QListViewItem *start = 0 ); signals: /** The selected folder has changed */ @@ -269,6 +281,11 @@ protected slots: void slotNewMessageToMailingList(); + /** For RMB move folder */ + virtual void moveSelectedToFolder( int menuId ); + /** For RMB copy folder */ + virtual void copySelectedToFolder( int menuId ); + protected: /** Catch palette changes */ virtual bool event(QEvent *e); @@ -307,6 +324,9 @@ protected: /** connect all signals */ void connectSignals(); + /** Move or copy the current folder to destination */ + void moveOrCopyCurrentFolder( KMFolder* destination, bool move=false ); + private: /** total column */ QListViewItemIterator mUpdateIterator; @@ -321,6 +341,9 @@ private: KMMainWidget *mMainWidget; bool mReloading; QMap mFolderToItem; + + /** Map menu id into a folder */ + KMMenuToFolder mMenuToFolder; }; #endif diff --git a/renamejob.cpp b/renamejob.cpp index d02b4e91a..dfe8c4b8b 100644 --- a/renamejob.cpp +++ b/renamejob.cpp @@ -53,7 +53,7 @@ using namespace KMail; -RenameJob::RenameJob( FolderStorage* storage, const QString& newName, +RenameJob::RenameJob( FolderStorage* storage, const QString& newName, KMFolderDir* newParent ) : FolderJob( 0, tOther, (storage ? storage->folder() : 0) ), mStorage( storage ), mNewParent( newParent ), @@ -101,7 +101,7 @@ void RenameJob::execute() if ( deftype < 0 || deftype > 1 ) deftype = 1; // the type of the new folder - KMFolderType typenew = + KMFolderType typenew = ( deftype == 0 ) ? KMFolderTypeMbox : KMFolderTypeMaildir; if ( mNewParent->owner() ) typenew = mNewParent->owner()->folderType(); @@ -123,7 +123,7 @@ void RenameJob::execute() // create it on the server and wait for the folderAdded signal connect( kmkernel->imapFolderMgr(), SIGNAL( changed() ), this, SLOT( slotMoveMessages() ) ); - KMFolderImap* imapFolder = + KMFolderImap* imapFolder = static_cast(mNewParent->owner()->storage()); imapFolder->createFolder( mNewName ); } else if ( mNewParent->type() == KMDImapDir ) @@ -149,12 +149,12 @@ void RenameJob::execute() return; } if ( mOldImapPath.isEmpty() ) - { + { // sanity emit renameDone( mNewName, false ); deleteLater(); return; - } else if ( mOldName == mNewName || mOldImapPath == "/INBOX/" ) { + } else if ( mOldName == mNewName ) { emit renameDone( mNewName, true ); // noop deleteLater(); return; @@ -225,7 +225,7 @@ void RenameJob::slotMoveMessages() assert( msgBase ); msgList.append( msgBase ); } - if ( msgList.count() == 0 ) + if ( msgList.count() == 0 ) { slotMoveCompleted( 0 ); } else @@ -242,7 +242,7 @@ void RenameJob::slotMoveCompleted( KMCommand* command ) kdDebug(5006) << k_funcinfo << (command?command->result():0) << endl; disconnect( command, SIGNAL( completed( KMCommand * ) ), this, SLOT( slotMoveCompleted( KMCommand * ) ) ); - if ( !command || command->result() == KMCommand::OK ) + if ( !command || command->result() == KMCommand::OK ) { kdDebug(5006) << "deleting old folder" << endl; // move complete or not necessary @@ -251,38 +251,38 @@ void RenameJob::slotMoveCompleted( KMCommand* command ) KConfig* config = KMKernel::config(); QMap entries = config->entryMap( oldconfig ); KConfigGroupSaver saver(config, "Folder-" + mNewFolder->idString()); - for ( QMap::Iterator it = entries.begin(); - it != entries.end(); ++it ) + for ( QMap::Iterator it = entries.begin(); + it != entries.end(); ++it ) { - if ( it.key() == "Id" || it.key() == "ImapPath" || + if ( it.key() == "Id" || it.key() == "ImapPath" || it.key() == "UidValidity" ) continue; config->writeEntry( it.key(), it.data() ); } mNewFolder->readConfig( config ); - + // delete the old folder mStorage->blockSignals( false ); if ( mStorage->folderType() == KMFolderTypeImap ) { kmkernel->imapFolderMgr()->remove( mStorage->folder() ); - } else if ( mStorage->folderType() == KMFolderTypeCachedImap ) + } else if ( mStorage->folderType() == KMFolderTypeCachedImap ) { // tell the account (see KMFolderCachedImap::listDirectory2) KMAcctCachedImap* acct = static_cast(mStorage)->account(); if ( acct ) acct->addDeletedFolder( mOldImapPath ); kmkernel->dimapFolderMgr()->remove( mStorage->folder() ); - } else if ( mStorage->folderType() == KMFolderTypeSearch ) + } else if ( mStorage->folderType() == KMFolderTypeSearch ) { // invalid kdWarning(5006) << k_funcinfo << "cannot remove a search folder" << endl; } else { kmkernel->folderMgr()->remove( mStorage->folder() ); } - + emit renameDone( mNewName, true ); - } else + } else { kdDebug(5006) << "rollback - deleting folder" << endl; // move failed - rollback the last transaction @@ -291,7 +291,7 @@ void RenameJob::slotMoveCompleted( KMCommand* command ) if ( mNewFolder->folderType() == KMFolderTypeImap ) { kmkernel->imapFolderMgr()->remove( mNewFolder ); - } else if ( mNewFolder->folderType() == KMFolderTypeCachedImap ) + } else if ( mNewFolder->folderType() == KMFolderTypeCachedImap ) { // tell the account (see KMFolderCachedImap::listDirectory2) KMFolderCachedImap* folder = static_cast(mNewFolder->storage()); @@ -299,14 +299,14 @@ void RenameJob::slotMoveCompleted( KMCommand* command ) if ( acct ) acct->addDeletedFolder( folder->imapPath() ); kmkernel->dimapFolderMgr()->remove( mNewFolder ); - } else if ( mNewFolder->folderType() == KMFolderTypeSearch ) + } else if ( mNewFolder->folderType() == KMFolderTypeSearch ) { // invalid kdWarning(5006) << k_funcinfo << "cannot remove a search folder" << endl; } else { kmkernel->folderMgr()->remove( mNewFolder ); } - + emit renameDone( mNewName, false ); } deleteLater();