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