Sophie

Sophie

distrib > Mageia > 5 > i586 > by-pkgid > ddfeee3bedf84e44f20049fdcc070a8a > files > 38

kdepimlibs4-4.14.10-2.2.mga5.src.rpm

From 6eceaf5795dbaf60d6081824889504e89dac20f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Vr=C3=A1til?= <daniel.vratil@kdab.com>
Date: Thu, 24 Mar 2016 18:20:33 +0100
Subject: [PATCH 37/47] Extend ETM/ETV API to make drag&drop popup menu
 customizable

Users can now add custom actions to drag&drop popup menu by calling
ETV::addCustomDropAction(). When users activates the custom action
the ETM::customDropAction() signal is emitted. User can then handle
the action manually or just transform the dropped content and let
ETM to finish the drop.
---
 akonadi/dragdropmanager.cpp              | 64 ++++++++++++++++++++----
 akonadi/dragdropmanager_p.h              | 18 +++++++
 akonadi/entitytreemodel.cpp              | 33 +++++++++++++
 akonadi/entitytreemodel.h                | 49 +++++++++++++++++++
 akonadi/entitytreemodel_p.cpp            |  7 +++
 akonadi/entitytreemodel_p.h              |  2 +
 akonadi/entitytreeview.cpp               | 12 +++++
 akonadi/entitytreeview.h                 | 39 +++++++++++++++
 akonadi/pastehelper.cpp                  | 84 +++++++++++++++++---------------
 akonadi/pastehelper_p.h                  | 47 ++++++++++++++++++
 akonadi/tests/actionstatemanagertest.cpp |  2 +-
 11 files changed, 309 insertions(+), 48 deletions(-)

diff --git a/akonadi/dragdropmanager.cpp b/akonadi/dragdropmanager.cpp
index e0641bb29..9db56099a 100644
--- a/akonadi/dragdropmanager.cpp
+++ b/akonadi/dragdropmanager.cpp
@@ -208,27 +208,51 @@ bool DragDropManager::processDropEvent(QDropEvent *event, bool &menuCanceled, bo
 
     // otherwise show up a menu to allow the user to select an action
     QMenu popup(m_view);
-    QAction *moveDropAction = 0;
-    QAction *copyDropAction = 0;
-    QAction *linkAction = 0;
+    QList<QAction *> moveDropActions;
+    QList<QAction *> copyDropActions;
+    QList<QAction *> linkActions;
     QString sequence;
 
     if (moveAllowed) {
         sequence = QKeySequence(Qt::ShiftModifier).toString();
         sequence.chop(1);   // chop superfluous '+'
-        moveDropAction = popup.addAction(KIcon(QString::fromLatin1("go-jump")), i18n("&Move Here") + QLatin1Char('\t') + sequence);
+        moveDropActions << popup.addAction(KIcon(QString::fromLatin1("go-jump")), i18n("&Move Here") + QLatin1Char('\t') + sequence);
+        Q_FOREACH (const CustomAction &ca, mCustomActions) {
+            if (ca.dropAction != Qt::MoveAction) {
+                continue;
+            }
+            QAction *action = popup.addAction(ca.icon, ca.text);
+            action->setProperty("customActionId", ca.id);
+            moveDropActions << action;
+        }
     }
 
     if (copyAllowed) {
         sequence = QKeySequence(Qt::ControlModifier).toString();
         sequence.chop(1);   // chop superfluous '+'
-        copyDropAction = popup.addAction(KIcon(QString::fromLatin1("edit-copy")), i18n("&Copy Here") + QLatin1Char('\t') + sequence);
+        copyDropActions << popup.addAction(KIcon(QString::fromLatin1("edit-copy")), i18n("&Copy Here") + QLatin1Char('\t') + sequence);
+        Q_FOREACH (const CustomAction &ca, mCustomActions) {
+            if (ca.dropAction != Qt::CopyAction) {
+                continue;
+            }
+            QAction *action = popup.addAction(ca.icon, ca.text);
+            action->setProperty("customActionId", ca.id);
+            copyDropActions << action;
+        }
     }
 
     if (linkAllowed) {
         sequence = QKeySequence(Qt::ControlModifier + Qt::ShiftModifier).toString();
         sequence.chop(1);   // chop superfluous '+'
-        linkAction = popup.addAction(KIcon(QLatin1String("edit-link")), i18n("&Link Here") + QLatin1Char('\t') + sequence);
+        linkActions << popup.addAction(KIcon(QLatin1String("edit-link")), i18n("&Link Here") + QLatin1Char('\t') + sequence);
+        Q_FOREACH (const CustomAction &ca, mCustomActions) {
+            if (ca.dropAction != Qt::LinkAction) {
+                continue;
+            }
+            QAction *action = popup.addAction(ca.icon, ca.text);
+            action->setProperty("customActionId", ca.id);
+            linkActions << action;
+        }
     }
 
     popup.addSeparator();
@@ -238,16 +262,27 @@ bool DragDropManager::processDropEvent(QDropEvent *event, bool &menuCanceled, bo
     if (!activatedAction) {
         menuCanceled = true;
         return false;
-    } else if (activatedAction == moveDropAction) {
+    } else if (moveDropActions.contains(activatedAction)) {
         event->setDropAction(Qt::MoveAction);
-    } else if (activatedAction == copyDropAction) {
+    } else if (copyDropActions.contains(activatedAction)) {
         event->setDropAction(Qt::CopyAction);
-    } else if (activatedAction == linkAction) {
+    } else if (linkActions.contains(activatedAction)) {
         event->setDropAction(Qt::LinkAction);
     } else {
         menuCanceled = true;
         return false;
     }
+
+    // This is a custom action provided by user; we need to encode it into
+    // the QMimeData object so that model can correctly trigger user's handler
+    const QVariant customActionId = activatedAction->property("customActionId");
+    if (customActionId.isValid()) {
+        // FIXME: I know this is super-bad thing to do, but there's no other way
+        // to pass this information to the receiving model :(
+        QMimeData *md = const_cast<QMimeData*>(data);
+        md->setProperty("customActionId", customActionId);
+    }
+
     return true;
 }
 
@@ -331,3 +366,14 @@ void DragDropManager::setManualSortingActive(bool active)
 {
     mIsManualSortingActive = active;
 }
+
+void DragDropManager::addCustomAction(const QString &id, const KIcon &icon,
+                                      const QString &text, Qt::DropAction dropAction)
+{
+    CustomAction ca;
+    ca.id = id;
+    ca.icon = icon;
+    ca.text = text;
+    ca.dropAction = dropAction;
+    mCustomActions << ca;
+}
diff --git a/akonadi/dragdropmanager_p.h b/akonadi/dragdropmanager_p.h
index 0151c4d6a..c189feade 100644
--- a/akonadi/dragdropmanager_p.h
+++ b/akonadi/dragdropmanager_p.h
@@ -21,9 +21,14 @@
 #define AKONADI_DRAGDROPMANAGER_P_H
 
 #include <QAbstractItemView>
+#include <QVector>
 
 #include "akonadi/collection.h"
 
+#include <KIcon>
+
+class QObject;
+
 namespace Akonadi
 {
 
@@ -71,6 +76,9 @@ public:
      */
     void setManualSortingActive(bool active);
 
+    void addCustomAction(const QString &id, const KIcon &icon, const QString &text,
+                         Qt::DropAction dropAction);
+
 private:
     Collection currentDropTarget(QDropEvent *event) const;
 
@@ -78,6 +86,16 @@ private:
     bool mShowDropActionMenu;
     bool mIsManualSortingActive;
     QAbstractItemView *m_view;
+
+    struct CustomAction {
+        CustomAction() : dropAction(Qt::IgnoreAction) {}
+
+        QString id;
+        KIcon icon;
+        QString text;
+        Qt::DropAction dropAction;
+    };
+    QVector<CustomAction> mCustomActions;
 };
 
 }
diff --git a/akonadi/entitytreemodel.cpp b/akonadi/entitytreemodel.cpp
index a2e8f2d4a..046c83d69 100644
--- a/akonadi/entitytreemodel.cpp
+++ b/akonadi/entitytreemodel.cpp
@@ -39,6 +39,7 @@
 #include <akonadi/transactionsequence.h>
 #include <akonadi/itemmodifyjob.h>
 #include <akonadi/session.h>
+#include <akonadi/entitytreeview.h>
 #include "collectionfetchscope.h"
 
 #include "collectionutils_p.h"
@@ -583,6 +584,12 @@ bool EntityTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
                 return false;
             }
 
+            PasteHelperJob *pasteJob = qobject_cast<PasteHelperJob*>(job);
+            if (pasteJob && pasteJob->hasCustomActionId()) {
+                d->m_pendingDrops.insert(pasteJob->customActionId(), pasteJob);
+                connect(job, SIGNAL(customDropAction(QString,Akonadi::Item::List,Akonadi::Collection::List,Akonadi::Collection,Qt::DropAction)),
+                        this, SIGNAL(customDropAction(QString,Akonadi::Item::List,Akonadi::Collection::List,Akonadi::Collection,Qt::DropAction)));
+            }
             connect(job, SIGNAL(result(KJob*)), SLOT(pasteJobDone(KJob*)));
 
             // Accpet the event so that it doesn't propagate.
@@ -1264,4 +1271,30 @@ QModelIndexList EntityTreeModel::modelIndexesForItem(const QAbstractItemModel *m
     return proxyList;
 }
 
+void EntityTreeModel::customDropActionProcessed(const QString &actionId)
+{
+    Q_D(EntityTreeModel);
+    Q_ASSERT(d->m_pendingDrops.contains(actionId));
+    if (!d->m_pendingDrops.contains(actionId)) {
+        return;
+    }
+
+    d->m_pendingDrops.value(actionId)->customDropActionProcessed();
+}
+
+void EntityTreeModel::customDropActionProcessed(const QString &actionId,
+                                                const Item::List &items,
+                                                const Collection::List &collections,
+                                                Qt::DropAction dropAction)
+{
+    Q_D(EntityTreeModel);
+    Q_ASSERT(d->m_pendingDrops.contains(actionId));
+    if (!d->m_pendingDrops.contains(actionId)) {
+        return;
+    }
+
+    d->m_pendingDrops.value(actionId)->customDropActionProcessed(items, collections, dropAction);
+}
+
+
 #include "moc_entitytreemodel.cpp"
diff --git a/akonadi/entitytreemodel.h b/akonadi/entitytreemodel.h
index b6533ae6b..d002f67f6 100644
--- a/akonadi/entitytreemodel.h
+++ b/akonadi/entitytreemodel.h
@@ -637,6 +637,36 @@ public:
      */
     static QModelIndexList modelIndexesForItem(const QAbstractItemModel *model, const Item &item);
 
+
+    /** Call when customDropAction() is handled by listener.
+     *
+     * This overload allows passing back transformed Items and Collections as
+     * well as changing the final DropAction that ETM should perform. EntityTreeModel
+     * will continue handling the drop event as if it was a @p dropAction but
+     * will use @p items and @p collections provided by this method instead of
+     * the original ones.
+     *
+     * @param actionId ID of the handled action
+     * @param items Items that were dropped
+     * @param collections Colletions that were dropped
+     * @param dropAction Treat the drop as this dropAction
+     */
+    void customDropActionProcessed(const QString &actionId,
+                                   const Akonadi::Item::List &items,
+                                   const Akonadi::Collection::List &collections,
+                                   Qt::DropAction dropAction);
+
+    /**
+     * Call when customDropAction() is handled by listener.
+     *
+     * This overload indicates to ETM that the drop event has been handled
+     * completely and will not perform any additional action for this particular
+     * drop event.
+     *
+     * @p actionId ID of the handled action
+     */
+    void customDropActionProcessed(const QString &actionId);
+
 Q_SIGNALS:
     /**
      * Signal emitted when the collection tree has been fetched for the first time.
@@ -665,6 +695,25 @@ Q_SIGNALS:
      */
     void collectionFetched(int collectionId);
 
+    /**
+     * Emitted when custom drop action (@see EntityTreeView::addCustomDropAction) was triggered
+     *
+     * The listener can handle the drop action completely on its own and just call
+     * customDropActionProcessed(const QString &actionId), or it can transform the
+     * @p items and @p collections as needed and pass them back via the other
+     * customDropActionProcessed() overload and let EntityTreeModel to handle
+     *
+     * @param actionId ID of the activated action
+     * @param items Dropped items (if any)
+     * @param collections Dropped collections (if any)
+     * @param destination Drop destination collection
+     */
+    void customDropAction(const QString &actionId,
+                          const Akonadi::Item::List &items,
+                          const Akonadi::Collection::List &collections,
+                          const Akonadi::Collection &destination,
+                          Qt::DropAction dropAction);
+
 protected:
     /**
      * Clears and resets the model. Always call this instead of the reset method in the superclass.
diff --git a/akonadi/entitytreemodel_p.cpp b/akonadi/entitytreemodel_p.cpp
index 07b107841..d4802dfa7 100644
--- a/akonadi/entitytreemodel_p.cpp
+++ b/akonadi/entitytreemodel_p.cpp
@@ -24,6 +24,7 @@
 #include "dbusconnectionpool.h"
 #include "monitor_p.h" // For friend ref/deref
 #include "servermanager.h"
+#include "pastehelper_p.h"
 
 #include <KDE/KLocalizedString>
 #include <KDE/KMessageBox>
@@ -1402,6 +1403,12 @@ void EntityTreeModelPrivate::pasteJobDone(KJob *job)
 
 void EntityTreeModelPrivate::updateJobDone(KJob *job)
 {
+    PasteHelperJob *phj = qobject_cast<PasteHelperJob*>(job);
+    Q_ASSERT(phj);
+    if (phj->hasCustomActionId()) {
+        m_pendingDrops.remove(phj->customActionId());
+    }
+
     if (job->error()) {
         // TODO: handle job errors
         kWarning() << "Job error:" << job->errorString();
diff --git a/akonadi/entitytreemodel_p.h b/akonadi/entitytreemodel_p.h
index d29ad901d..500210591 100644
--- a/akonadi/entitytreemodel_p.h
+++ b/akonadi/entitytreemodel_p.h
@@ -36,6 +36,7 @@ namespace Akonadi
 class ItemFetchJob;
 class ChangeRecorder;
 class AgentInstance;
+class PasteHelperJob;
 }
 
 struct Node
@@ -141,6 +142,7 @@ public:
     Node *m_rootNode;
     QString m_rootCollectionDisplayName;
     QStringList m_mimeTypeFilter;
+    QMap<QString, PasteHelperJob*> m_pendingDrops;
     MimeTypeChecker m_mimeChecker;
     EntityTreeModel::CollectionFetchStrategy m_collectionFetchStrategy;
     EntityTreeModel::ItemPopulationStrategy m_itemPopulation;
diff --git a/akonadi/entitytreeview.cpp b/akonadi/entitytreeview.cpp
index 9873835c4..06cc21e3b 100644
--- a/akonadi/entitytreeview.cpp
+++ b/akonadi/entitytreeview.cpp
@@ -340,4 +340,16 @@ void EntityTreeView::setDefaultPopupMenu(const QString &name)
     d->mDefaultPopupMenu = name;
 }
 
+
+#ifndef QT_NO_DRAGANDDROP
+void EntityTreeView::addCustomDropAction(const QString &actionId,
+                                         const KIcon &icon,
+                                         const QString &text,
+                                         Qt::DropAction dropAction)
+{
+    d->mDragDropManager->addCustomAction(actionId, icon, text, dropAction);
+}
+#endif
+
+
 #include "moc_entitytreeview.cpp"
diff --git a/akonadi/entitytreeview.h b/akonadi/entitytreeview.h
index 7ab662ae3..e12ca8a88 100644
--- a/akonadi/entitytreeview.h
+++ b/akonadi/entitytreeview.h
@@ -25,9 +25,12 @@
 #include "akonadi_export.h"
 
 #include <QTreeView>
+#include <akonadi/collection.h>
+#include <akonadi/item.h>
 
 class KXMLGUIClient;
 class QDragMoveEvent;
+class KIcon;
 
 namespace Akonadi
 {
@@ -167,6 +170,21 @@ public:
      */
     void setDefaultPopupMenu(const QString &name);
 
+#ifndef QT_NO_DRAGANDDROP
+    /**
+     * Add custom action to the popup menu that appears when drag is finished.
+     *
+     * @param actionId Custom action identifier
+     * @param icon Action icon
+     * @param text Action label
+     * @param dropAction Type of the action
+     */
+    void addCustomDropAction(const QString &actionId,
+                             const KIcon &icon,
+                             const QString &text,
+                             Qt::DropAction dropAction);
+#endif
+
 Q_SIGNALS:
     /**
      * This signal is emitted whenever the user has clicked
@@ -216,6 +234,27 @@ Q_SIGNALS:
      */
     void currentChanged(const Akonadi::Item &item);
 
+#ifndef QT_NO_DRAGANDDROP
+    /**
+     * Emitted when custom drop action was triggered
+     *
+     * The listener can handle the drop action completely on its own and just call
+     * customDropActionProcessed(const QString &actionId), or it can transform the
+     * @p items and @p collections as needed and pass them back via the other
+     * customDropActionProcessed() overload and let EntityTreeModel to handle
+     *
+     * @param actionId ID of the activated action
+     * @param items Dropped items (if any)
+     * @param collections Dropped collections (if any)
+     * @param destination Drop destination collection
+     */
+    void customDropAction(const QString &actionId,
+                          const Akonadi::Item::List &items,
+                          const Akonadi::Collection::List &collections,
+                          const Akonadi::Collection &destination,
+                          Qt::DropAction dropAction);
+#endif
+
 protected:
     using QTreeView::currentChanged;
 #ifndef QT_NO_DRAGANDDROP
diff --git a/akonadi/pastehelper.cpp b/akonadi/pastehelper.cpp
index e9929d597..7b92f345d 100644
--- a/akonadi/pastehelper.cpp
+++ b/akonadi/pastehelper.cpp
@@ -28,7 +28,6 @@
 #include "itemmodifyjob.h"
 #include "itemmovejob.h"
 #include "linkjob.h"
-#include "transactionsequence.h"
 #include "session.h"
 #include "unlinkjob.h"
 
@@ -38,65 +37,78 @@
 #include <QtCore/QByteArray>
 #include <QtCore/QMimeData>
 #include <QtCore/QStringList>
-#include <QtCore/QMutexLocker>
+#include <QtCore/QTimer>
 
 #include <boost/bind.hpp>
 
 using namespace Akonadi;
 
-class PasteHelperJob: public Akonadi::TransactionSequence
-{
-    Q_OBJECT
-
-public:
-    explicit PasteHelperJob(Qt::DropAction action, const Akonadi::Item::List &items,
-                            const Akonadi::Collection::List &collections,
-                            const Akonadi::Collection &destination,
-                            QObject *parent = 0);
-    virtual ~PasteHelperJob();
-
-private Q_SLOTS:
-    void onDragSourceCollectionFetched(KJob *job);
-
-private:
-    void runActions();
-    void runItemsActions();
-    void runCollectionsActions();
-
-private:
-    Qt::DropAction mAction;
-    Akonadi::Item::List mItems;
-    Akonadi::Collection::List mCollections;
-    Akonadi::Collection mDestCollection;
-};
-
 PasteHelperJob::PasteHelperJob(Qt::DropAction action, const Item::List &items,
                                const Collection::List &collections,
                                const Collection &destination,
+                               const QString &customActionId,
                                QObject *parent)
     : TransactionSequence(parent)
     , mAction(action)
     , mItems(items)
     , mCollections(collections)
     , mDestCollection(destination)
+    , mCustomActionId(customActionId)
 {
     //FIXME: The below code disables transactions in otder to avoid data loss due to nested
     //transactions (copy and colcopy in the server doesn't see the items retrieved into the cache and copies empty payloads).
     //Remove once this is fixed properly, see the other FIXME comments.
     setProperty("transactionsDisabled", true);
 
+    if (mCustomActionId.isEmpty()) {
+        processDropAction();
+    } else{
+        setAutoDelete(false);
+        QTimer::singleShot(0, this, SLOT(emitCustomDropAction()));
+    }
+}
+
+PasteHelperJob::~PasteHelperJob()
+{
+}
+
+void PasteHelperJob::emitCustomDropAction()
+{
+    Q_EMIT customDropAction(mCustomActionId, mItems, mCollections, mDestCollection, mAction);
+}
+
+void PasteHelperJob::customDropActionProcessed()
+{
+    commit();
+    return;
+}
+
+void PasteHelperJob::customDropActionProcessed(const Akonadi::Item::List &items,
+                                               const Akonadi::Collection::List &collections,
+                                               Qt::DropAction dropAction)
+{
+    setAutoDelete(true);
+    mItems = items;
+    mCollections = collections;
+    mAction = dropAction;
+
+    processDropAction();
+}
+
+void PasteHelperJob::processDropAction()
+{
     Collection dragSourceCollection;
-    if (!items.isEmpty() && items.first().parentCollection().isValid()) {
+    if (!mItems.isEmpty() && mItems.first().parentCollection().isValid()) {
         // Check if all items have the same parent collection ID
-        const Collection parent = items.first().parentCollection();
-        if (std::find_if(items.constBegin(), items.constEnd(),
+        const Collection parent = mItems.first().parentCollection();
+        if (std::find_if(mItems.constBegin(), mItems.constEnd(),
                          boost::bind(&Entity::operator!=, boost::bind(static_cast<Collection (Item::*)() const>(&Item::parentCollection), _1), parent))
-             == items.constEnd())
+             == mItems.constEnd())
         {
             dragSourceCollection = parent;
         }
 
-        kDebug() << items.first().parentCollection().id() << dragSourceCollection.id();
+        kDebug() << mItems.first().parentCollection().id() << dragSourceCollection.id();
     }
 
     if (dragSourceCollection.isValid()) {
@@ -114,10 +126,6 @@ PasteHelperJob::PasteHelperJob(Qt::DropAction action, const Item::List &items,
     }
 }
 
-PasteHelperJob::~PasteHelperJob()
-{
-}
-
 void PasteHelperJob::onDragSourceCollectionFetched(KJob *job)
 {
     CollectionFetchJob *fetch = qobject_cast<CollectionFetchJob*>(job);
@@ -332,9 +340,9 @@ KJob *PasteHelper::pasteUriList(const QMimeData *mimeData, const Collection &des
         // TODO: handle non Akonadi URLs?
     }
 
-
     PasteHelperJob *job = new PasteHelperJob(action, items,
                                              collections, destination,
+                                             mimeData->property("customActionId").toString(),
                                              session);
 
     return job;
diff --git a/akonadi/pastehelper_p.h b/akonadi/pastehelper_p.h
index 8dcec3518..9dd564b82 100644
--- a/akonadi/pastehelper_p.h
+++ b/akonadi/pastehelper_p.h
@@ -21,6 +21,8 @@
 #define AKONADI_PASTEHELPER_P_H
 
 #include <akonadi/collection.h>
+#include <akonadi/item.h>
+#include <akonadi/transactionsequence.h>
 
 #include <QtCore/QList>
 
@@ -31,6 +33,51 @@ namespace Akonadi {
 
 class Session;
 
+class PasteHelperJob: public Akonadi::TransactionSequence
+{
+    Q_OBJECT
+
+public:
+    explicit PasteHelperJob(Qt::DropAction action, const Akonadi::Item::List &items,
+                            const Akonadi::Collection::List &collections,
+                            const Akonadi::Collection &destination,
+                            const QString &customActionId,
+                            QObject *parent = 0);
+    virtual ~PasteHelperJob();
+
+    void customDropActionProcessed();
+    void customDropActionProcessed(const Akonadi::Item::List &items,
+                                   const Akonadi::Collection::List &collections,
+                                   Qt::DropAction dropAction);
+
+    bool hasCustomActionId() const { return !mCustomActionId.isEmpty(); }
+    QString customActionId() const { return mCustomActionId; }
+
+Q_SIGNALS:
+    void customDropAction(const QString &actionId, const Akonadi::Item::List &items,
+                          const Akonadi::Collection::List &collections,
+                          const Akonadi::Collection &collection,
+                          Qt::DropAction dropAction);
+
+private Q_SLOTS:
+    void emitCustomDropAction();
+    void onDragSourceCollectionFetched(KJob *job);
+
+private:
+    void processDropAction();
+    void runActions();
+    void runItemsActions();
+    void runCollectionsActions();
+
+private:
+    Qt::DropAction mAction;
+    Akonadi::Item::List mItems;
+    Akonadi::Collection::List mCollections;
+    Akonadi::Collection mDestCollection;
+    QString mCustomActionId;
+};
+
+
 /**
   @internal
 
diff --git a/akonadi/tests/actionstatemanagertest.cpp b/akonadi/tests/actionstatemanagertest.cpp
index 74acdf3ba..14a15af27 100644
--- a/akonadi/tests/actionstatemanagertest.cpp
+++ b/akonadi/tests/actionstatemanagertest.cpp
@@ -27,7 +27,7 @@
 #include "../actionstatemanager.cpp"
 #undef QT_NO_CLIPBOARD
 
-#include "../pastehelper.cpp"
+#include "../pastehelper_p.h"
 
 typedef QHash<Akonadi::StandardActionManager::Type, bool> StateMap;
 Q_DECLARE_METATYPE( StateMap )
-- 
2.14.1