Blame lang/qt/src/threadedjobmixin.h

Packit Service 672cf4
/*
Packit Service 672cf4
    threadedjobmixin.h
Packit Service 672cf4
Packit Service 672cf4
    This file is part of qgpgme, the Qt API binding for gpgme
Packit Service 672cf4
    Copyright (c) 2008 Klarälvdalens Datakonsult AB
Packit Service 672cf4
    Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik
Packit Service 672cf4
    Software engineering by Intevation GmbH
Packit Service 672cf4
Packit Service 672cf4
    QGpgME is free software; you can redistribute it and/or
Packit Service 672cf4
    modify it under the terms of the GNU General Public License as
Packit Service 672cf4
    published by the Free Software Foundation; either version 2 of the
Packit Service 672cf4
    License, or (at your option) any later version.
Packit Service 672cf4
Packit Service 672cf4
    QGpgME is distributed in the hope that it will be useful,
Packit Service 672cf4
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 672cf4
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 672cf4
    General Public License for more details.
Packit Service 672cf4
Packit Service 672cf4
    You should have received a copy of the GNU General Public License
Packit Service 672cf4
    along with this program; if not, write to the Free Software
Packit Service 672cf4
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit Service 672cf4
Packit Service 672cf4
    In addition, as a special exception, the copyright holders give
Packit Service 672cf4
    permission to link the code of this program with any edition of
Packit Service 672cf4
    the Qt library by Trolltech AS, Norway (or with modified versions
Packit Service 672cf4
    of Qt that use the same license as Qt), and distribute linked
Packit Service 672cf4
    combinations including the two.  You must obey the GNU General
Packit Service 672cf4
    Public License in all respects for all of the code used other than
Packit Service 672cf4
    Qt.  If you modify this file, you may extend this exception to
Packit Service 672cf4
    your version of the file, but you are not obligated to do so.  If
Packit Service 672cf4
    you do not wish to do so, delete this exception statement from
Packit Service 672cf4
    your version.
Packit Service 672cf4
*/
Packit Service 672cf4
Packit Service 672cf4
#ifndef __QGPGME_THREADEDJOBMIXING_H__
Packit Service 672cf4
#define __QGPGME_THREADEDJOBMIXING_H__
Packit Service 672cf4
Packit Service 672cf4
#include <QMutex>
Packit Service 672cf4
#include <QMutexLocker>
Packit Service 672cf4
#include <QThread>
Packit Service 672cf4
#include <QString>
Packit Service 672cf4
#include <QIODevice>
Packit Service 672cf4
Packit Service 672cf4
#ifdef BUILDING_QGPGME
Packit Service 672cf4
# include "context.h"
Packit Service 672cf4
# include "interfaces/progressprovider.h"
Packit Service 672cf4
#else
Packit Service 672cf4
# include <gpgme++/context.h>
Packit Service 672cf4
# include <gpgme++/interfaces/progressprovider.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
#include "job.h"
Packit Service 672cf4
Packit Service 672cf4
#include <cassert>
Packit Service 672cf4
#include <functional>
Packit Service 672cf4
Packit Service 672cf4
namespace QGpgME
Packit Service 672cf4
{
Packit Service 672cf4
namespace _detail
Packit Service 672cf4
{
Packit Service 672cf4
Packit Service 672cf4
QString audit_log_as_html(GpgME::Context *ctx, GpgME::Error &err;;
Packit Service 672cf4
Packit Service 672cf4
class PatternConverter
Packit Service 672cf4
{
Packit Service 672cf4
    const QList<QByteArray> m_list;
Packit Service 672cf4
    mutable const char **m_patterns;
Packit Service 672cf4
public:
Packit Service 672cf4
    explicit PatternConverter(const QByteArray &ba);
Packit Service 672cf4
    explicit PatternConverter(const QString &s);
Packit Service 672cf4
    explicit PatternConverter(const QList<QByteArray> &lba);
Packit Service 672cf4
    explicit PatternConverter(const QStringList &sl);
Packit Service 672cf4
    ~PatternConverter();
Packit Service 672cf4
Packit Service 672cf4
    const char **patterns() const;
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
class ToThreadMover
Packit Service 672cf4
{
Packit Service 672cf4
    QObject *const m_object;
Packit Service 672cf4
    QThread *const m_thread;
Packit Service 672cf4
public:
Packit Service 672cf4
    ToThreadMover(QObject *o, QThread *t) : m_object(o), m_thread(t) {}
Packit Service 672cf4
    ToThreadMover(QObject &o, QThread *t) : m_object(&o), m_thread(t) {}
Packit Service 672cf4
    ToThreadMover(const std::shared_ptr<QObject> &o, QThread *t) : m_object(o.get()), m_thread(t) {}
Packit Service 672cf4
    ~ToThreadMover()
Packit Service 672cf4
    {
Packit Service 672cf4
        if (m_object && m_thread) {
Packit Service 672cf4
            m_object->moveToThread(m_thread);
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
template <typename T_result>
Packit Service 672cf4
class Thread : public QThread
Packit Service 672cf4
{
Packit Service 672cf4
public:
Packit Service 672cf4
    explicit Thread(QObject *parent = Q_NULLPTR) : QThread(parent) {}
Packit Service 672cf4
Packit Service 672cf4
    void setFunction(const std::function<T_result()> &function)
Packit Service 672cf4
    {
Packit Service 672cf4
        const QMutexLocker locker(&m_mutex);
Packit Service 672cf4
        m_function = function;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
    T_result result() const
Packit Service 672cf4
    {
Packit Service 672cf4
        const QMutexLocker locker(&m_mutex);
Packit Service 672cf4
        return m_result;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
private:
Packit Service 672cf4
    void run() Q_DECL_OVERRIDE {
Packit Service 672cf4
        const QMutexLocker locker(&m_mutex);
Packit Service 672cf4
        m_result = m_function();
Packit Service 672cf4
    }
Packit Service 672cf4
private:
Packit Service 672cf4
    mutable QMutex m_mutex;
Packit Service 672cf4
    std::function<T_result()> m_function;
Packit Service 672cf4
    T_result m_result;
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
template <typename T_base, typename T_result = std::tuple<GpgME::Error, QString, GpgME::Error> >
Packit Service 672cf4
class ThreadedJobMixin : public T_base, public GpgME::ProgressProvider
Packit Service 672cf4
{
Packit Service 672cf4
public:
Packit Service 672cf4
    typedef ThreadedJobMixin<T_base, T_result> mixin_type;
Packit Service 672cf4
    typedef T_result result_type;
Packit Service 672cf4
Packit Service 672cf4
protected:
Packit Service 672cf4
    static_assert(std::tuple_size<T_result>::value > 2,
Packit Service 672cf4
                  "Result tuple too small");
Packit Service 672cf4
    static_assert(std::is_same <
Packit Service 672cf4
                  typename std::tuple_element <
Packit Service 672cf4
                  std::tuple_size<T_result>::value - 2,
Packit Service 672cf4
                  T_result
Packit Service 672cf4
                  >::type,
Packit Service 672cf4
                  QString
Packit Service 672cf4
                  >::value,
Packit Service 672cf4
                  "Second to last result type not a QString");
Packit Service 672cf4
    static_assert(std::is_same <
Packit Service 672cf4
                  typename std::tuple_element <
Packit Service 672cf4
                  std::tuple_size<T_result>::value - 1,
Packit Service 672cf4
                  T_result
Packit Service 672cf4
                  >::type,
Packit Service 672cf4
                  GpgME::Error
Packit Service 672cf4
                  >::value,
Packit Service 672cf4
                  "Last result type not a GpgME::Error");
Packit Service 672cf4
Packit Service 672cf4
    explicit ThreadedJobMixin(GpgME::Context *ctx)
Packit Service 6c01f9
        : T_base(0), m_ctx(ctx), m_thread(), m_auditLog(), m_auditLogError()
Packit Service 672cf4
    {
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
    void lateInitialization()
Packit Service 672cf4
    {
Packit Service 672cf4
        assert(m_ctx);
Packit Service 672cf4
        QObject::connect(&m_thread, &QThread::finished, this,
Packit Service 672cf4
                         &mixin_type::slotFinished);
Packit Service 672cf4
        m_ctx->setProgressProvider(this);
Packit Service 672cf4
        QGpgME::g_context_map.insert(this, m_ctx.get());
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
    ~ThreadedJobMixin()
Packit Service 672cf4
    {
Packit Service 672cf4
        QGpgME::g_context_map.remove(this);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
    template <typename T_binder>
Packit Service 672cf4
    void run(const T_binder &func)
Packit Service 672cf4
    {
Packit Service 672cf4
        m_thread.setFunction(std::bind(func, this->context()));
Packit Service 672cf4
        m_thread.start();
Packit Service 672cf4
    }
Packit Service 672cf4
    template <typename T_binder>
Packit Service 672cf4
    void run(const T_binder &func, const std::shared_ptr<QIODevice> &io)
Packit Service 672cf4
    {
Packit Service 672cf4
        if (io) {
Packit Service 672cf4
            io->moveToThread(&m_thread);
Packit Service 672cf4
        }
Packit Service 672cf4
        // the arguments passed here to the functor are stored in a QThread, and are not
Packit Service 672cf4
        // necessarily destroyed (living outside the UI thread) at the time the result signal
Packit Service 672cf4
        // is emitted and the signal receiver wants to clean up IO devices.
Packit Service 672cf4
        // To avoid such races, we pass std::weak_ptr's to the functor.
Packit Service 672cf4
        m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io)));
Packit Service 672cf4
        m_thread.start();
Packit Service 672cf4
    }
Packit Service 672cf4
    template <typename T_binder>
Packit Service 672cf4
    void run(const T_binder &func, const std::shared_ptr<QIODevice> &io1, const std::shared_ptr<QIODevice> &io2)
Packit Service 672cf4
    {
Packit Service 672cf4
        if (io1) {
Packit Service 672cf4
            io1->moveToThread(&m_thread);
Packit Service 672cf4
        }
Packit Service 672cf4
        if (io2) {
Packit Service 672cf4
            io2->moveToThread(&m_thread);
Packit Service 672cf4
        }
Packit Service 672cf4
        // the arguments passed here to the functor are stored in a QThread, and are not
Packit Service 672cf4
        // necessarily destroyed (living outside the UI thread) at the time the result signal
Packit Service 672cf4
        // is emitted and the signal receiver wants to clean up IO devices.
Packit Service 672cf4
        // To avoid such races, we pass std::weak_ptr's to the functor.
Packit Service 672cf4
        m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io1), std::weak_ptr<QIODevice>(io2)));
Packit Service 672cf4
        m_thread.start();
Packit Service 672cf4
    }
Packit Service 672cf4
    GpgME::Context *context() const
Packit Service 672cf4
    {
Packit Service 672cf4
        return m_ctx.get();
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
    virtual void resultHook(const result_type &) {}
Packit Service 672cf4
Packit Service 672cf4
    void slotFinished()
Packit Service 672cf4
    {
Packit Service 672cf4
        const T_result r = m_thread.result();
Packit Service 672cf4
        m_auditLog = std::get < std::tuple_size<T_result>::value - 2 > (r);
Packit Service 672cf4
        m_auditLogError = std::get < std::tuple_size<T_result>::value - 1 > (r);
Packit Service 672cf4
        resultHook(r);
Packit Service 672cf4
        Q_EMIT this->done();
Packit Service 672cf4
        doEmitResult(r);
Packit Service 672cf4
        this->deleteLater();
Packit Service 672cf4
    }
Packit Service 672cf4
    void slotCancel() Q_DECL_OVERRIDE {
Packit Service 672cf4
        if (m_ctx)
Packit Service 672cf4
        {
Packit Service 672cf4
            m_ctx->cancelPendingOperation();
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
    QString auditLogAsHtml() const Q_DECL_OVERRIDE
Packit Service 672cf4
    {
Packit Service 672cf4
        return m_auditLog;
Packit Service 672cf4
    }
Packit Service 672cf4
    GpgME::Error auditLogError() const Q_DECL_OVERRIDE
Packit Service 672cf4
    {
Packit Service 672cf4
        return m_auditLogError;
Packit Service 672cf4
    }
Packit Service 672cf4
    void showProgress(const char * /*what*/,
Packit Service 672cf4
                      int /*type*/, int current, int total) Q_DECL_OVERRIDE {
Packit Service 672cf4
        // will be called from the thread exec'ing the operation, so
Packit Service 672cf4
        // just bounce everything to the owning thread:
Packit Service 672cf4
        // ### hope this is thread-safe (meta obj is const, and
Packit Service 672cf4
        // ### portEvent is thread-safe, so should be ok)
Packit Service 672cf4
        QMetaObject::invokeMethod(this, "progress", Qt::QueuedConnection,
Packit Service 672cf4
        // TODO port
Packit Service 672cf4
        Q_ARG(QString, QString()),
Packit Service 672cf4
        Q_ARG(int, current),
Packit Service 672cf4
        Q_ARG(int, total));
Packit Service 672cf4
    }
Packit Service 672cf4
private:
Packit Service 672cf4
    template <typename T1, typename T2>
Packit Service 672cf4
    void doEmitResult(const std::tuple<T1, T2> &tuple)
Packit Service 672cf4
    {
Packit Service 672cf4
        Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple));
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
    template <typename T1, typename T2, typename T3>
Packit Service 672cf4
    void doEmitResult(const std::tuple<T1, T2, T3> &tuple)
Packit Service 672cf4
    {
Packit Service 672cf4
        Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple));
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
    template <typename T1, typename T2, typename T3, typename T4>
Packit Service 672cf4
    void doEmitResult(const std::tuple<T1, T2, T3, T4> &tuple)
Packit Service 672cf4
    {
Packit Service 672cf4
        Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple));
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
    template <typename T1, typename T2, typename T3, typename T4, typename T5>
Packit Service 672cf4
    void doEmitResult(const std::tuple<T1, T2, T3, T4, T5> &tuple)
Packit Service 672cf4
    {
Packit Service 672cf4
        Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple), std::get<4>(tuple));
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
private:
Packit Service 672cf4
    std::shared_ptr<GpgME::Context> m_ctx;
Packit Service 672cf4
    Thread<T_result> m_thread;
Packit Service 672cf4
    QString m_auditLog;
Packit Service 672cf4
    GpgME::Error m_auditLogError;
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
}
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
#endif /* __QGPGME_THREADEDJOBMIXING_H__ */