LCOV - code coverage report
Current view: top level - lang/qt/src - threadedjobmixin.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 64 78 82.1 %
Date: 2016-09-12 13:07:23 Functions: 73 388 18.8 %

          Line data    Source code
       1             : /*
       2             :     threadedjobmixin.h
       3             : 
       4             :     This file is part of qgpgme, the Qt API binding for gpgme
       5             :     Copyright (c) 2008 Klarälvdalens Datakonsult AB
       6             :     Copyright (c) 2016 Intevation GmbH
       7             : 
       8             :     QGpgME is free software; you can redistribute it and/or
       9             :     modify it under the terms of the GNU General Public License as
      10             :     published by the Free Software Foundation; either version 2 of the
      11             :     License, or (at your option) any later version.
      12             : 
      13             :     QGpgME is distributed in the hope that it will be useful,
      14             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :     General Public License for more details.
      17             : 
      18             :     You should have received a copy of the GNU General Public License
      19             :     along with this program; if not, write to the Free Software
      20             :     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      21             : 
      22             :     In addition, as a special exception, the copyright holders give
      23             :     permission to link the code of this program with any edition of
      24             :     the Qt library by Trolltech AS, Norway (or with modified versions
      25             :     of Qt that use the same license as Qt), and distribute linked
      26             :     combinations including the two.  You must obey the GNU General
      27             :     Public License in all respects for all of the code used other than
      28             :     Qt.  If you modify this file, you may extend this exception to
      29             :     your version of the file, but you are not obligated to do so.  If
      30             :     you do not wish to do so, delete this exception statement from
      31             :     your version.
      32             : */
      33             : 
      34             : #ifndef __QGPGME_THREADEDJOBMIXING_H__
      35             : #define __QGPGME_THREADEDJOBMIXING_H__
      36             : 
      37             : #include <QMutex>
      38             : #include <QMutexLocker>
      39             : #include <QThread>
      40             : #include <QString>
      41             : #include <QIODevice>
      42             : 
      43             : #ifdef BUILDING_QGPGME
      44             : # include "context.h"
      45             : # include "interfaces/progressprovider.h"
      46             : #else
      47             : # include <gpgme++/context.h>
      48             : # include <gpgme++/interfaces/progressprovider.h>
      49             : #endif
      50             : 
      51             : 
      52             : #include <cassert>
      53             : 
      54             : namespace QGpgME
      55             : {
      56             : namespace _detail
      57             : {
      58             : 
      59             : QString audit_log_as_html(GpgME::Context *ctx, GpgME::Error &err);
      60             : 
      61             : class PatternConverter
      62             : {
      63             :     const QList<QByteArray> m_list;
      64             :     mutable const char **m_patterns;
      65             : public:
      66             :     explicit PatternConverter(const QByteArray &ba);
      67             :     explicit PatternConverter(const QString &s);
      68             :     explicit PatternConverter(const QList<QByteArray> &lba);
      69             :     explicit PatternConverter(const QStringList &sl);
      70             :     ~PatternConverter();
      71             : 
      72             :     const char **patterns() const;
      73             : };
      74             : 
      75             : class ToThreadMover
      76             : {
      77             :     QObject *const m_object;
      78             :     QThread *const m_thread;
      79             : public:
      80             :     ToThreadMover(QObject *o, QThread *t) : m_object(o), m_thread(t) {}
      81             :     ToThreadMover(QObject &o, QThread *t) : m_object(&o), m_thread(t) {}
      82          40 :     ToThreadMover(const std::shared_ptr<QObject> &o, QThread *t) : m_object(o.get()), m_thread(t) {}
      83          40 :     ~ToThreadMover()
      84             :     {
      85          40 :         if (m_object && m_thread) {
      86           2 :             m_object->moveToThread(m_thread);
      87             :         }
      88          40 :     }
      89             : };
      90             : 
      91             : template <typename T_result>
      92          34 : class Thread : public QThread
      93             : {
      94             : public:
      95          34 :     explicit Thread(QObject *parent = Q_NULLPTR) : QThread(parent) {}
      96             : 
      97           6 :     void setFunction(const std::function<T_result()> &function)
      98             :     {
      99           6 :         const QMutexLocker locker(&m_mutex);
     100           6 :         m_function = function;
     101           6 :     }
     102             : 
     103           6 :     T_result result() const
     104             :     {
     105           6 :         const QMutexLocker locker(&m_mutex);
     106           6 :         return m_result;
     107             :     }
     108             : 
     109             : private:
     110           6 :     void run() Q_DECL_OVERRIDE {
     111           6 :         const QMutexLocker locker(&m_mutex);
     112           6 :         m_result = m_function();
     113           6 :     }
     114             : private:
     115             :     mutable QMutex m_mutex;
     116             :     std::function<T_result()> m_function;
     117             :     T_result m_result;
     118             : };
     119             : 
     120             : template <typename T_base, typename T_result = std::tuple<GpgME::Error, QString, GpgME::Error> >
     121          34 : class ThreadedJobMixin : public T_base, public GpgME::ProgressProvider
     122             : {
     123             : public:
     124             :     typedef ThreadedJobMixin<T_base, T_result> mixin_type;
     125             :     typedef T_result result_type;
     126             : 
     127             : protected:
     128             :     static_assert(std::tuple_size<T_result>::value > 2,
     129             :                   "Result tuple too small");
     130             :     static_assert(std::is_same <
     131             :                   typename std::tuple_element <
     132             :                   std::tuple_size<T_result>::value - 2,
     133             :                   T_result
     134             :                   >::type,
     135             :                   QString
     136             :                   >::value,
     137             :                   "Second to last result type not a QString");
     138             :     static_assert(std::is_same <
     139             :                   typename std::tuple_element <
     140             :                   std::tuple_size<T_result>::value - 1,
     141             :                   T_result
     142             :                   >::type,
     143             :                   GpgME::Error
     144             :                   >::value,
     145             :                   "Last result type not a GpgME::Error");
     146             : 
     147          34 :     explicit ThreadedJobMixin(GpgME::Context *ctx)
     148          34 :         : T_base(0), m_ctx(ctx), m_thread(), m_auditLog(), m_auditLogError()
     149             :     {
     150             : 
     151          34 :     }
     152             : 
     153          34 :     void lateInitialization()
     154             :     {
     155          34 :         assert(m_ctx);
     156          34 :         QObject::connect(&m_thread, SIGNAL(finished()), this, SLOT(slotFinished()));
     157          34 :         m_ctx->setProgressProvider(this);
     158          34 :     }
     159             : 
     160             :     template <typename T_binder>
     161           5 :     void run(const T_binder &func)
     162             :     {
     163           5 :         m_thread.setFunction(std::bind(func, this->context()));
     164           5 :         m_thread.start();
     165           5 :     }
     166             :     template <typename T_binder>
     167           0 :     void run(const T_binder &func, const std::shared_ptr<QIODevice> &io)
     168             :     {
     169           0 :         if (io) {
     170           0 :             io->moveToThread(&m_thread);
     171             :         }
     172             :         // the arguments passed here to the functor are stored in a QThread, and are not
     173             :         // necessarily destroyed (living outside the UI thread) at the time the result signal
     174             :         // is emitted and the signal receiver wants to clean up IO devices.
     175             :         // To avoid such races, we pass std::weak_ptr's to the functor.
     176           0 :         m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io)));
     177           0 :         m_thread.start();
     178           0 :     }
     179             :     template <typename T_binder>
     180           1 :     void run(const T_binder &func, const std::shared_ptr<QIODevice> &io1, const std::shared_ptr<QIODevice> &io2)
     181             :     {
     182           1 :         if (io1) {
     183           1 :             io1->moveToThread(&m_thread);
     184             :         }
     185           1 :         if (io2) {
     186           1 :             io2->moveToThread(&m_thread);
     187             :         }
     188             :         // the arguments passed here to the functor are stored in a QThread, and are not
     189             :         // necessarily destroyed (living outside the UI thread) at the time the result signal
     190             :         // is emitted and the signal receiver wants to clean up IO devices.
     191             :         // To avoid such races, we pass std::weak_ptr's to the functor.
     192           1 :         m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io1), std::weak_ptr<QIODevice>(io2)));
     193           1 :         m_thread.start();
     194           1 :     }
     195          36 :     GpgME::Context *context() const
     196             :     {
     197          36 :         return m_ctx.get();
     198             :     }
     199             : 
     200           3 :     virtual void resultHook(const result_type &) {}
     201             : 
     202           6 :     void slotFinished()
     203             :     {
     204           6 :         const T_result r = m_thread.result();
     205           6 :         m_auditLog = std::get < std::tuple_size<T_result>::value - 2 > (r);
     206           6 :         m_auditLogError = std::get < std::tuple_size<T_result>::value - 1 > (r);
     207           6 :         resultHook(r);
     208           6 :         Q_EMIT this->done();
     209           6 :         doEmitResult(r);
     210           6 :         this->deleteLater();
     211           6 :     }
     212           0 :     void slotCancel() Q_DECL_OVERRIDE {
     213           0 :         if (m_ctx)
     214             :         {
     215           0 :             m_ctx->cancelPendingOperation();
     216             :         }
     217           0 :     }
     218           0 :     QString auditLogAsHtml() const Q_DECL_OVERRIDE
     219             :     {
     220           0 :         return m_auditLog;
     221             :     }
     222           0 :     GpgME::Error auditLogError() const Q_DECL_OVERRIDE
     223             :     {
     224           0 :         return m_auditLogError;
     225             :     }
     226          22 :     void showProgress(const char *what, int type, int current, int total) Q_DECL_OVERRIDE {
     227             :         // will be called from the thread exec'ing the operation, so
     228             :         // just bounce everything to the owning thread:
     229             :         // ### hope this is thread-safe (meta obj is const, and
     230             :         // ### portEvent is thread-safe, so should be ok)
     231          22 :         QMetaObject::invokeMethod(this, "progress", Qt::QueuedConnection,
     232             :         // TODO port
     233             :         Q_ARG(QString, QString()),
     234             :         Q_ARG(int, current),
     235          44 :         Q_ARG(int, total));
     236          22 :     }
     237             : private:
     238             :     template <typename T1, typename T2>
     239             :     void doEmitResult(const std::tuple<T1, T2> &tuple)
     240             :     {
     241             :         Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple));
     242             :     }
     243             : 
     244             :     template <typename T1, typename T2, typename T3>
     245           2 :     void doEmitResult(const std::tuple<T1, T2, T3> &tuple)
     246             :     {
     247           2 :         Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple));
     248           2 :     }
     249             : 
     250             :     template <typename T1, typename T2, typename T3, typename T4>
     251           3 :     void doEmitResult(const std::tuple<T1, T2, T3, T4> &tuple)
     252             :     {
     253           3 :         Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple));
     254           3 :     }
     255             : 
     256             :     template <typename T1, typename T2, typename T3, typename T4, typename T5>
     257           1 :     void doEmitResult(const std::tuple<T1, T2, T3, T4, T5> &tuple)
     258             :     {
     259           1 :         Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple), std::get<4>(tuple));
     260           1 :     }
     261             : 
     262             : private:
     263             :     std::shared_ptr<GpgME::Context> m_ctx;
     264             :     Thread<T_result> m_thread;
     265             :     QString m_auditLog;
     266             :     GpgME::Error m_auditLogError;
     267             : };
     268             : 
     269             : }
     270             : }
     271             : 
     272             : #endif /* __QGPGME_THREADEDJOBMIXING_H__ */

Generated by: LCOV version 1.11