From d9d5d6de3e50e3efb2584120015bf43e59a1f649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Vr=C3=A1til?= <daniel.vratil@kdab.com> Date: Wed, 3 Feb 2016 13:50:59 +0100 Subject: [PATCH 35/74] Add "Copy Decrypted Message To..." action to messagelist context menu REVIEW: 126971 --- kmail/kmail_part.rc | 4 ++- kmail/kmcommands.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++++----- kmail/kmcommands.h | 17 +++++++++-- kmail/kmmainwidget.cpp | 61 ++++++++++++++++++++++++++++++++++--- kmail/kmmainwidget.h | 13 ++++++-- kmail/kmmainwin.rc | 4 ++- 6 files changed, 163 insertions(+), 18 deletions(-) diff --git a/kmail/kmail_part.rc b/kmail/kmail_part.rc index db3c27b082..d349990573 100644 --- a/kmail/kmail_part.rc +++ b/kmail/kmail_part.rc @@ -2,7 +2,7 @@ the same menu entries at the same place in KMail and Kontact --> <!DOCTYPE kpartgui> -<kpartgui version="502" name="kmmainwin" > +<kpartgui version="503" name="kmmainwin" > <MenuBar> <Menu noMerge="1" name="file" > <text>&File</text> @@ -157,6 +157,7 @@ <Action name="mailing_list"/> <Separator/> <Action name="akonadi_item_copy_to_menu" /> + <Action name="copy_decrypted_message_to" /> <Action name="akonadi_item_move_to_menu" /> <Separator/> <Action name="set_status" /> @@ -280,6 +281,7 @@ <Action name="move_thread_to_trash"/> <Separator/> <Action name="akonadi_item_move_to_menu"/> + <Action name="copy_decrypted_message_to" /> <Action name="akonadi_item_copy_to_menu"/> <Separator/> <Action name="create_todo"/> diff --git a/kmail/kmcommands.cpp b/kmail/kmcommands.cpp index f7f06e92fb..59367b70c4 100644 --- a/kmail/kmcommands.cpp +++ b/kmail/kmcommands.cpp @@ -83,6 +83,7 @@ #ifndef QT_NO_CURSOR #include "messageviewer/utils/kcursorsaver.h" #endif +#include "messageviewer/viewer/objecttreeemptysource.h" #include "messageviewer/viewer/objecttreeparser.h" #include "messageviewer/viewer/csshelper.h" #include "messageviewer/utils/util.h" @@ -105,6 +106,7 @@ using KMail::SecondaryWindow; #include <akonadi/itemmovejob.h> #include <akonadi/itemcopyjob.h> #include <akonadi/itemdeletejob.h> +#include <akonadi/itemcreatejob.h> #include <akonadi/tag.h> #include <akonadi/tagcreatejob.h> #include <mailtransport/transportattribute.h> @@ -1379,13 +1381,15 @@ KMCommand::Result KMMailingListFilterCommand::execute() } KMCopyCommand::KMCopyCommand( const Akonadi::Collection& destFolder, - const QList<Akonadi::Item> &msgList) - :KMCommand( 0, msgList ), mDestFolder( destFolder ) + const QList<Akonadi::Item> &msgList, + CopyOptions options ) + :KMCommand( 0, msgList ), mDestFolder( destFolder ), mJobCount( 0 ), mOptions( options ) { } -KMCopyCommand::KMCopyCommand( const Akonadi::Collection& destFolder, const Akonadi::Item& msg) - :KMCommand( 0,msg ), mDestFolder( destFolder ) +KMCopyCommand::KMCopyCommand( const Akonadi::Collection& destFolder, const Akonadi::Item& msg, + CopyOptions options ) + :KMCommand( 0,msg ), mDestFolder( destFolder ), mJobCount( 0 ), mOptions( options ) { } @@ -1394,20 +1398,84 @@ KMCommand::Result KMCopyCommand::execute() setDeletesItself( true ); QList<Akonadi::Item> listItem = retrievedMsgs(); - Akonadi::ItemCopyJob *job = new Akonadi::ItemCopyJob( listItem, Akonadi::Collection(mDestFolder.id()),this ); - connect( job, SIGNAL(result(KJob*)), this, SLOT(slotCopyResult(KJob*)) ); + if ( mOptions & Decrypt ) { + Akonadi::ItemFetchJob *fetch = createFetchJob( listItem ); + fetch->fetchScope().fetchFullPayload(true); + fetch->fetchScope().fetchAllAttributes(true); + fetch->fetchScope().setFetchRemoteIdentification(false); + connect(fetch, SIGNAL(result(KJob*)), this, SLOT(slotFetchResult(KJob*)) ); + } else { + Akonadi::ItemCopyJob *job = new Akonadi::ItemCopyJob( listItem, Akonadi::Collection(mDestFolder.id()),this ); + connect( job, SIGNAL(result(KJob*)), this, SLOT(slotCopyResult(KJob*)) ); + ++mJobCount; + } return OK; } +void KMCopyCommand::slotFetchResult( KJob * job ) +{ + if ( job->error() ) { + showJobError(job); + setResult( Failed ); + deleteLater(); + return; + } + + const QList<Akonadi::Item> items = qobject_cast<Akonadi::ItemFetchJob*>(job)->items(); + Q_FOREACH ( Akonadi::Item item, items ) { + KMime::Message::Ptr msg = MessageCore::Util::message( item ); + if ( !msg ) { + // Error handling? + continue; + } + + Akonadi::Job *job = 0; + if ( decrypt( msg ) ) { + item.setPayload( msg ); + job = new Akonadi::ItemCreateJob( item, Akonadi::Collection(mDestFolder.id()), this ); + } else { + job = new Akonadi::ItemCopyJob( item, Akonadi::Collection(mDestFolder.id()), this ); + } + connect( job, SIGNAL(result(KJob*)), this, SLOT(slotCopyResult(KJob*)) ); + ++mJobCount; + } + + if (mJobCount == 0) { + slotCopyResult( job ); + } +} + void KMCopyCommand::slotCopyResult( KJob * job ) { if ( job->error() ) { // handle errors showJobError(job); setResult( Failed ); + mJobCount = 0; } - deleteLater(); + + --mJobCount; + if ( mJobCount <= 0 ) { + deleteLater(); + } +} + +bool KMCopyCommand::decrypt( KMime::Message::Ptr &msg ) const +{ + if ( !KMime::isEncrypted( msg.get() ) ) { + return false; + } + + MessageViewer::EmptySource source; + source.setAllowDecryption(true); + MessageViewer::NodeHelper nodeHelper; + + MessageViewer::ObjectTreeParser otp( &source, &nodeHelper, 0 , true, false, true ); + otp.parseObjectTree( msg->topLevel() ); + + msg = nodeHelper.unencryptedMessage( msg ); + return true; } KMMoveCommand::KMMoveCommand( const Akonadi::Collection& destFolder, diff --git a/kmail/kmcommands.h b/kmail/kmcommands.h index 1208da1259..3b0115dc1e 100644 --- a/kmail/kmcommands.h +++ b/kmail/kmcommands.h @@ -506,17 +506,30 @@ class KMAIL_EXPORT KMCopyCommand : public KMCommand Q_OBJECT public: - KMCopyCommand( const Akonadi::Collection &destFolder, const QList<Akonadi::Item> &msgList ); - KMCopyCommand( const Akonadi::Collection& destFolder, const Akonadi::Item &msg ); + enum CopyOptions { + NoOptions = 0x0, + Decrypt = 0x1 + }; + + KMCopyCommand( const Akonadi::Collection &destFolder, const QList<Akonadi::Item> &msgList, + CopyOptions options = NoOptions ); + KMCopyCommand( const Akonadi::Collection& destFolder, const Akonadi::Item &msg, + CopyOptions options = NoOptions ); protected slots: + void slotFetchResult( KJob * job); void slotCopyResult( KJob * job ); + private: virtual Result execute(); + bool decrypt( KMime::Message::Ptr &message ) const; Akonadi::Collection mDestFolder; + int mJobCount; + CopyOptions mOptions; }; + namespace KPIM { class ProgressItem; } diff --git a/kmail/kmmainwidget.cpp b/kmail/kmmainwidget.cpp index 02bedaa522..3d518f7667 100644 --- a/kmail/kmmainwidget.cpp +++ b/kmail/kmmainwidget.cpp @@ -1786,12 +1786,13 @@ void KMMainWidget::moveSelectedMessagesToFolder( const Akonadi::Collection & des } -void KMMainWidget::copyMessageSelected( const QList<Akonadi::Item> &selectMsg, const Akonadi::Collection &dest ) +void KMMainWidget::copyMessageSelected( const QList<Akonadi::Item> &selectMsg, const Akonadi::Collection &dest, + KMCopyCommand::CopyOptions options ) { if ( selectMsg.isEmpty() ) return; // And stuff them into a KMCopyCommand :) - KMCommand *command = new KMCopyCommand( dest, selectMsg ); + KMCommand *command = new KMCopyCommand( dest, selectMsg, options ); QObject::connect( command, SIGNAL(completed(KMCommand*)), this, SLOT(slotCopyMessagesCompleted(KMCommand*)) @@ -1817,6 +1818,16 @@ void KMMainWidget::slotCopyMessagesCompleted( KMCommand *command ) } void KMMainWidget::slotCopySelectedMessagesToFolder() +{ + copySelectedMessagesToFolder( KMCopyCommand::NoOptions ); +} + +void KMMainWidget::slotCopyDecryptedSelectedMessagesToFolder() +{ + copySelectedMessagesToFolder( KMCopyCommand::Decrypt ); +} + +void KMMainWidget::copySelectedMessagesToFolder( KMCopyCommand::CopyOptions options ) { QPointer<MailCommon::FolderSelectionDialog> dialog( moveOrCopyToDialog() ); dialog->setCaption( i18n( "Copy Messages to Folder" ) ); @@ -1824,16 +1835,17 @@ void KMMainWidget::slotCopySelectedMessagesToFolder() if ( dialog->exec() && dialog ) { const Akonadi::Collection dest = dialog->selectedCollection(); if ( dest.isValid() ) { - copySelectedMessagesToFolder( dest ); + copySelectedMessagesToFolder( dest, options ); } } } -void KMMainWidget::copySelectedMessagesToFolder( const Akonadi::Collection& dest ) +void KMMainWidget::copySelectedMessagesToFolder( const Akonadi::Collection& dest, + KMCopyCommand::CopyOptions options ) { const QList<Akonadi::Item > lstMsg = mMessagePane->selectionAsMessageItemList(); if ( !lstMsg.isEmpty() ) { - copyMessageSelected( lstMsg, dest ); + copyMessageSelected( lstMsg, dest, options ); } } @@ -2715,6 +2727,7 @@ void KMMainWidget::showMessagePopup(const Akonadi::Item&msg ,const KUrl&url,cons menu->addSeparator(); menu->addAction( mCopyActionMenu ); + menu->addAction( mCopyDecryptActionMenu ); menu->addAction( mMoveActionMenu ); menu->addSeparator(); @@ -3045,6 +3058,15 @@ void KMMainWidget::setupActions() { KAction *action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CopyItemToMenu ); action->setText(i18n("Copy Message To...") ); + + mCopyDecryptActionMenu = new KActionMenu( i18n("Copy Decrypted Mesage To..."), actionCollection() ); + mCopyDecryptActionMenu->setDelayed( true ); + mCopyDecryptActionMenu->menu()->setProperty( "actionType", Akonadi::StandardActionManager::CopyItemToMenu ); + connect(mAkonadiStandardActionManager->standardActionManager(), SIGNAL(actionStateUpdated()), + this, SLOT(slotUpdateCopyDecryptedActionMenu())); + actionCollection()->addAction( QLatin1String("copy_decrypted_message_to"), mCopyDecryptActionMenu ); + slotUpdateCopyDecryptedActionMenu(); + action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::MoveItemToMenu ); action->setText(i18n("Move Message To...") ); } @@ -3381,6 +3403,12 @@ void KMMainWidget::setupActions() SLOT(slotCopySelectedMessagesToFolder()) ); action->setShortcut( QKeySequence( Qt::Key_C ) ); } + { + KAction *action = new KAction( i18n("Copy Decrypted Message to Folder"), this ); + actionCollection()->addAction(QLatin1String( "copy_decrypted_message_to_folder" ), action ); + connect( action, SIGNAL(triggered(bool)), + SLOT(slotCopyDecryptedSelectedMessagesToFolder()) ); + } { KAction *action = new KAction( i18n("Jump to Folder..."), this ); actionCollection()->addAction( QLatin1String("jump_to_folder"), action ); @@ -3521,6 +3549,29 @@ void KMMainWidget::slotAddFavoriteFolder() } } +void KMMainWidget::slotUpdateCopyDecryptedActionMenu() +{ + KMenu *menu = mCopyDecryptActionMenu->menu(); + delete menu; + menu = new KMenu(); + // Will populate our menu with folders + connect(menu, SIGNAL(aboutToShow()), + mAkonadiStandardActionManager->standardActionManager(), SLOT(aboutToShowMenu())); + connect(menu, SIGNAL(triggered(QAction*)), + this, SLOT(slotCopyDecryptedActionTriggered(QAction*))); + mCopyDecryptActionMenu->setMenu(menu); +} + +void KMMainWidget::slotCopyDecryptedActionTriggered(QAction *action) +{ + const QModelIndex index = action->data().value<QModelIndex>(); + Q_ASSERT(index.isValid()); + + const Collection collection = index.data(EntityTreeModel::CollectionRole).value<Collection>(); + + copySelectedMessagesToFolder( collection, KMCopyCommand::Decrypt ); +} + //----------------------------------------------------------------------------- void KMMainWidget::slotEditNotifications() { diff --git a/kmail/kmmainwidget.h b/kmail/kmmainwidget.h index 68f57a1bb3..a2d195418a 100644 --- a/kmail/kmmainwidget.h +++ b/kmail/kmmainwidget.h @@ -24,6 +24,7 @@ #include "kmail_export.h" #include "kmreaderwin.h" //for inline actions #include "kmkernel.h" // for access to config +#include "kmcommands.h" #include "foldertreewidget.h" @@ -180,6 +181,7 @@ public slots: * messages (in MessageListView) into it. */ void slotCopySelectedMessagesToFolder(); + void slotCopyDecryptedSelectedMessagesToFolder(); /** * Implements the "move to trash" action @@ -275,7 +277,9 @@ protected: void layoutSplitters(); void newFromTemplate( const Akonadi::Item& ); void moveSelectedMessagesToFolder( const Akonadi::Collection & dest ); - void copySelectedMessagesToFolder( const Akonadi::Collection& dest ); + void copySelectedMessagesToFolder( KMCopyCommand::CopyOptions options ); + void copySelectedMessagesToFolder( const Akonadi::Collection& dest, + KMCopyCommand::CopyOptions options ); virtual void showEvent( QShowEvent *event ); @@ -428,7 +432,8 @@ private: void moveMessageSelected( MessageList::Core::MessageItemSetReference ref, const Akonadi::Collection &dest, bool confirmOnDeletion = true ); - void copyMessageSelected( const QList<Akonadi::Item> &selectMsg, const Akonadi::Collection &dest ); + void copyMessageSelected( const QList<Akonadi::Item> &selectMsg, const Akonadi::Collection &dest, + KMCopyCommand::CopyOptions options ); /** @@ -513,6 +518,9 @@ private slots: void slotChangeDisplayMessageFormat(MessageViewer::Viewer::DisplayFormatMessage format); void slotCollectionRemoved(const Akonadi::Collection &col); + + void slotUpdateCopyDecryptedActionMenu(); + void slotCopyDecryptedActionTriggered(QAction *action); private: // Message actions KAction *mDeleteAction, *mTrashThreadAction, @@ -531,6 +539,7 @@ private: KActionMenu *mThreadStatusMenu, *mApplyFilterActionsMenu; KAction *mCopyActionMenu; + KActionMenu *mCopyDecryptActionMenu; KAction *mMoveActionMenu; KAction *mMarkThreadAsReadAction; KAction *mMarkThreadAsUnreadAction; diff --git a/kmail/kmmainwin.rc b/kmail/kmmainwin.rc index db3c27b082..4fc7aab72c 100644 --- a/kmail/kmmainwin.rc +++ b/kmail/kmmainwin.rc @@ -2,7 +2,7 @@ the same menu entries at the same place in KMail and Kontact --> <!DOCTYPE kpartgui> -<kpartgui version="502" name="kmmainwin" > +<kpartgui version="503" name="kmmainwin" > <MenuBar> <Menu noMerge="1" name="file" > <text>&File</text> @@ -157,6 +157,7 @@ <Action name="mailing_list"/> <Separator/> <Action name="akonadi_item_copy_to_menu" /> + <Action name="copy_decrypted_message_to" /> <Action name="akonadi_item_move_to_menu" /> <Separator/> <Action name="set_status" /> @@ -280,6 +281,7 @@ <Action name="move_thread_to_trash"/> <Separator/> <Action name="akonadi_item_move_to_menu"/> + <Action name="copy_decrypted_message_to"/> <Action name="akonadi_item_copy_to_menu"/> <Separator/> <Action name="create_todo"/> -- 2.14.1