Make KMMoveCommand emit a completed(bool success) signal by hooking the

command up to the target folder's msgAdded signals and ticking off each
serial number as it comes in. To make that possible, use the metaDataMap
for imap folders to restore serial numbers after the move (along with
status). Also connect to the folderCompleted(bool) signal of imap folders
to make sure we notice if not all messages make it to the other side.

Connect kmheaders to the abortRequested signal and make sure cancelling
moves behaves somewhat more gracefully and restores the state of messages
remaining in the folder, making them selectable and setting their transfer
status to false so they can be downloaded or moved again.

svn path=/trunk/kdepim/; revision=252676
wilder-work
Till Adam 23 years ago
parent 15034a99fd
commit b9aa52983f
  1. 76
      kmcommands.cpp
  2. 10
      kmcommands.h
  3. 16
      kmfolderimap.cpp
  4. 7
      kmfolderimap.h
  5. 2
      kmfoldermbox.cpp
  6. 48
      kmheaders.cpp
  7. 4
      kmheaders.h

@ -1335,6 +1335,7 @@ KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
const QPtrList<KMMsgBase> &msgList)
:mDestFolder( destFolder ), mMsgList( msgList )
{
setDeletesItself( true );
}
KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
@ -1359,6 +1360,12 @@ void KMMoveCommand::execute()
int index;
QPtrList<KMMessage> list;
int undoId = -1;
if (mDestFolder) {
connect (mDestFolder, SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
this, SLOT(slotMsgAddedToDestFolder(KMFolder*, Q_UINT32)));
}
for (msgBase=mMsgList.first(); msgBase && !rc; msgBase=mMsgList.next()) {
KMFolder *srcFolder = msgBase->parent();
if (srcFolder == mDestFolder)
@ -1380,9 +1387,16 @@ void KMMoveCommand::execute()
}
if (mDestFolder) {
mLostBoys.append(msg->getMsgSerNum());
if (mDestFolder->folderType() == KMFolderTypeImap) {
/* If we are moving to an imap folder, connect to it's completed
* siganl so we notice when all the mails should have showed up in it
* but haven't for some reason. */
connect (mDestFolder, SIGNAL(folderComplete( KMFolderImap*, bool )),
this, SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
list.append(msg);
} else {
// We are moving to a local folder.
rc = mDestFolder->moveMsg(msg, &index);
if (rc == 0 && index != -1) {
KMMsgBase *mb = mDestFolder->unGetMsg( mDestFolder->count() - 1 );
@ -1392,6 +1406,12 @@ void KMMoveCommand::execute()
undoId = kmkernel->undoStack()->newUndoAction( srcFolder, mDestFolder );
kmkernel->undoStack()->addMsgToAction( undoId, mb->getMsgSerNum() );
}
} else if (rc != 0) {
// Something went wrong. Stop processing here, it is likely that the
// other moves would fail as well.
emit completed( false);
deleteLater();
return;
}
}
} else {
@ -1406,17 +1426,57 @@ void KMMoveCommand::execute()
}
}
}
if (!list.isEmpty() && mDestFolder)
mDestFolder->moveMsg(list, &index);
if (!list.isEmpty() && mDestFolder) {
mDestFolder->moveMsg(list, &index);
} else {
FolderToMessageListMap::Iterator it;
for ( it = folderDeleteList.begin(); it != folderDeleteList.end(); ++it ) {
it.key()->removeMsg(*it.data());
delete it.data();
}
if ( !mDestFolder ) {
emit completed( true );
deleteLater();
}
}
}
FolderToMessageListMap::Iterator it;
for ( it = folderDeleteList.begin(); it != folderDeleteList.end(); ++it ) {
it.key()->removeMsg(*it.data());
delete it.data();
void KMMoveCommand::slotImapFolderCompleted(KMFolderImap *, bool success)
{
kdDebug(5006) << "KMMoveCommand::slotImapFolderCompleted: " << success << endl;
if ( success ) {
// the folder was checked successfully but we were still called, so check
// if we are still waiting for messages to show up. If so, uidValidity
// changed, or something else went wrong. Clean up.
/* Unfortunately older UW imap servers change uid validity for each put job.
* Yes, it is really that broken. *sigh* So we cannot report error here, I guess. */
if ( !mLostBoys.isEmpty() ) {
kdDebug(5006) << "### Not all moved messages reported back that they were " << endl
<< "### added to the target folder. Did uidValidity change? " << endl;
}
} else {
// Should we inform the user here or leave that to the caller?
}
emit completed( success );
deleteLater();
}
if (mDestFolder) {
mDestFolder->sync();
void KMMoveCommand::slotMsgAddedToDestFolder(KMFolder *folder, Q_UINT32 serNum)
{
if (folder != mDestFolder) {
kdDebug(5006) << "KMMoveCommand::msgAddedToDestFolder different "
"folder or invalid serial number." << endl;
return;
}
mLostBoys.remove(serNum);
if ( mLostBoys.isEmpty() ) {
// we are done. All messages transferred to the host succesfully
if (mDestFolder && mDestFolder->folderType() != KMFolderTypeImap) {
mDestFolder->sync();
}
emit completed( true );
deleteLater();
}
}

@ -14,6 +14,7 @@ class KProgressDialog;
class KMComposeWin;
class KMFilter;
class KMFolder;
class KMFolderImap;
class KMFolderNode;
class KMHeaders;
class KMMainWidget;
@ -75,6 +76,9 @@ private slots:
void slotTransferCancelled();
signals:
void messagesTransfered(bool);
/** Emitted when the command has completed.
* @success Success or error. */
void completed( bool success);
private:
// ProgressDialog for transferring messages
@ -543,12 +547,18 @@ public:
KMMoveCommand( KMFolder* destFolder, const QPtrList<KMMsgBase> &msgList );
KMMoveCommand( KMFolder* destFolder, KMMessage * msg );
private slots:
void slotImapFolderCompleted(KMFolderImap *folder, bool success);
void slotMsgAddedToDestFolder(KMFolder *folder, Q_UINT32 serNum);
private:
virtual void execute();
KMFolder *mDestFolder;
QPtrList<KMMsgBase> mMsgList;
// List of serial numbers that have to be transferred to a host.
// Ticked off as they come in via msgAdded signals.
QValueList<Q_UINT32> mLostBoys;
};
class KMDeleteMsgCommand : public KMMoveCommand

@ -71,6 +71,8 @@ KMFolderImap::~KMFolderImap()
{
writeConfig();
if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed(this);
mMetaDataMap.setAutoDelete( true );
mMetaDataMap.clear();
}
@ -242,15 +244,17 @@ void KMFolderImap::slotRenameResult( KIO::Job *job )
void KMFolderImap::addMsgQuiet(KMMessage* aMsg)
{
KMFolder *folder = aMsg->parent();
Q_UINT32 serNum = 0;
aMsg->setTransferInProgress( false );
if (folder) {
kmkernel->undoStack()->pushSingleAction( aMsg->getMsgSerNum(), folder, this );
serNum = aMsg->getMsgSerNum();
kmkernel->undoStack()->pushSingleAction( serNum, folder, this );
int idx = folder->find( aMsg );
assert( idx != -1 );
folder->take( idx );
}
// Remember the status, so it can be transfered to the new message.
mMetaDataMap.insert(aMsg->msgIdMD5(), new KMMsgMetaData(aMsg->status()));
mMetaDataMap.insert(aMsg->msgIdMD5(), new KMMsgMetaData(aMsg->status(), serNum));
delete aMsg;
aMsg = 0;
@ -261,6 +265,8 @@ void KMFolderImap::addMsgQuiet(KMMessage* aMsg)
void KMFolderImap::addMsgQuiet(QPtrList<KMMessage> msgList)
{
KMFolder *folder = msgList.first()->parent();
Q_UINT32 serNum = 0;
if (folder) serNum = msgList.first()->getMsgSerNum();
int undoId = -1;
for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
{
@ -268,7 +274,7 @@ void KMFolderImap::addMsgQuiet(QPtrList<KMMessage> msgList)
undoId = kmkernel->undoStack()->newUndoAction( folder, this );
kmkernel->undoStack()->addMsgToAction( undoId, msg->getMsgSerNum() );
// Remember the status, so it can be transfered to the new message.
mMetaDataMap.insert(msg->msgIdMD5(), new KMMsgMetaData(msg->status()));
mMetaDataMap.insert(msg->msgIdMD5(), new KMMsgMetaData(msg->status(), serNum));
msg->setTransferInProgress( false );
}
if (folder) folder->take(msgList);
@ -331,7 +337,7 @@ int KMFolderImap::addMsg(QPtrList<KMMessage>& msgList, int* aIndex_ret)
// we need the messages that belong to the current set to pass them to the ImapJob
QPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
imapJob = new ImapJob(temp_msgs, *it, ImapJob::tCopyMessage, this);
imapJob = new ImapJob(temp_msgs, *it, ImapJob::tMoveMessage, this);
connect(imapJob, SIGNAL(messageCopied(QPtrList<KMMessage>)),
SLOT(addMsgQuiet(QPtrList<KMMessage>)));
imapJob->start();
@ -962,6 +968,8 @@ void KMFolderImap::slotGetMessagesData(KIO::Job * job, const QByteArray & data)
if ( mMetaDataMap.find( id ) ) {
KMMsgMetaData *md = mMetaDataMap[id];
msg->setStatus( md->status() );
if ( md->serNum() != 0 )
msg->setMsgSerNum( md->serNum() );
mMetaDataMap.remove( id );
delete md;
}

@ -49,11 +49,16 @@ using KMail::ImapJob;
class KMMsgMetaData
{
public:
KMMsgMetaData(KMMsgStatus aStatus) { mStatus = aStatus; }
KMMsgMetaData(KMMsgStatus aStatus)
:mStatus(aStatus), mSerNum(0) {}
KMMsgMetaData(KMMsgStatus aStatus, Q_UINT32 aSerNum)
:mStatus(aStatus), mSerNum(aSerNum) {}
~KMMsgMetaData() {};
const KMMsgStatus status() const { return mStatus; }
const Q_UINT32 serNum() const { return mSerNum; }
private:
KMMsgStatus mStatus;
Q_UINT32 mSerNum;
};

@ -229,7 +229,7 @@ void KMFolderMbox::close(bool aForced)
mOpenCount = 1;
return;
}
if (mAutoCreateIndex)
{
if (KMFolderIndex::IndexOk != indexStatus()) {

@ -1580,6 +1580,10 @@ void KMHeaders::deleteMsg ()
KMMessageList msgList = *selectedMsgs(true);
KMCommand *command = new KMDeleteMsgCommand( mFolder, msgList );
connect (command, SIGNAL(completed( bool)),
this, SLOT(slotMoveCompleted( bool)));
connect(KMBroadcastStatus::instance(), SIGNAL(signalAbortRequested()),
this, SLOT(slotMoveAborted()));
command->start();
finalizeMove( nextItem, contentX, contentY );
@ -1692,15 +1696,57 @@ void KMHeaders::moveMsgToFolder (KMFolder* destFolder)
// remember the message to select afterwards
int contentX, contentY;
KMHeaderItem *nextItem = prepareMove( &contentX, &contentY );
msgList = *selectedMsgs(true);
KMCommand *command = new KMMoveCommand( destFolder, msgList );
connect (command, SIGNAL(completed( bool)),
this, SLOT(slotMoveCompleted( bool)));
connect(KMBroadcastStatus::instance(), SIGNAL(signalAbortRequested()),
this, SLOT(slotMoveAborted()));
command->start();
finalizeMove( nextItem, contentX, contentY );
}
void KMHeaders::slotMoveAborted( )
{
/* The user cancelled the move, reset the state of all messages involved and
* repaint. */
KMBroadcastStatus::instance()->setStatusMsg(i18n("Moving messages cancelled."));
disconnect(KMBroadcastStatus::instance(), SIGNAL(signalAbortRequested()),
this, SLOT(slotMoveAborted()));
for (QListViewItemIterator it(this); it.current(); it++) {
KMHeaderItem *item = static_cast<KMHeaderItem*>(it.current());
if ( item->aboutToBeDeleted() ) {
item->setAboutToBeDeleted ( false );
item->setSelectable ( true );
KMMsgBase *msgBase = mFolder->getMsgBase(item->msgId());
if ( msgBase->isMessage() ) {
KMMessage *msg = static_cast<KMMessage *>(msgBase);
if ( msg ) msg->setTransferInProgress( false, true );
}
}
}
triggerUpdate();
}
void KMHeaders::slotMoveCompleted( bool success )
{
kdDebug(5006) << "KMHeaders::slotMoveCompleted: " << success << endl;
if (success) {
KMBroadcastStatus::instance()->setStatusMsg(i18n("Messages moved succesfully."));
} else {
// FIXME dialog? Offer rollback?
KMBroadcastStatus::instance()->setStatusMsg(i18n("Moving messages failed."));
}
disconnect(KMBroadcastStatus::instance(), SIGNAL(signalAbortRequested()),
this, SLOT(slotMoveAborted()));
}
bool KMHeaders::canUndo() const
{
return ( kmkernel->undoStack()->size() > 0 );

@ -284,6 +284,10 @@ protected slots:
/** show context menu */
void rightButtonPressed( QListViewItem *, const QPoint &, int );
private slots:
void slotMoveCompleted( bool success );
void slotMoveAborted( );
private:
/** Is equivalent to clearing the list and inserting an item for
each message in the current folder */

Loading…
Cancel
Save