QGpgME 16.1.0.0000496
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#ifdef BUILDING_QGPGME
45# include "context.h"
46# include "interfaces/progressprovider.h"
47#else
48# include <gpgme++/context.h>
49# include <gpgme++/interfaces/progressprovider.h>
50#endif
51
52#include "job.h"
53
54#include <cassert>
55#include <functional>
56
57namespace QGpgME
58{
59namespace _detail
60{
61
62QString audit_log_as_html(GpgME::Context *ctx, GpgME::Error &err);
63
65{
66 const QList<QByteArray> m_list;
67 mutable const char **m_patterns;
68public:
69 explicit PatternConverter(const QByteArray &ba);
70 explicit PatternConverter(const QString &s);
71 explicit PatternConverter(const QList<QByteArray> &lba);
72 explicit PatternConverter(const QStringList &sl);
74
75 const char **patterns() const;
76};
77
79{
80 QObject *const m_object;
81 QThread *const m_thread;
82public:
83 ToThreadMover(QObject *o, QThread *t) : m_object(o), m_thread(t) {}
84 ToThreadMover(QObject &o, QThread *t) : m_object(&o), m_thread(t) {}
85 ToThreadMover(const std::shared_ptr<QObject> &o, QThread *t) : m_object(o.get()), m_thread(t) {}
87 {
88 if (m_object && m_thread) {
89 m_object->moveToThread(m_thread);
90 }
91 }
92};
93
94template <typename T_result>
95class Thread : public QThread
96{
97public:
98 explicit Thread(QObject *parent = Q_NULLPTR) : QThread(parent) {}
99
100 void setFunction(const std::function<T_result()> &function)
101 {
102 const QMutexLocker locker(&m_mutex);
103 m_function = function;
104 }
105
106 T_result result() const
107 {
108 const QMutexLocker locker(&m_mutex);
109 return m_result;
110 }
111
112private:
113 void run() Q_DECL_OVERRIDE {
114 const QMutexLocker locker(&m_mutex);
115 m_result = m_function();
116 }
117private:
118 mutable QMutex m_mutex;
119 std::function<T_result()> m_function;
120 T_result m_result;
121};
122
123template <typename T_base, typename T_result = std::tuple<GpgME::Error, QString, GpgME::Error> >
124class ThreadedJobMixin : public T_base, public GpgME::ProgressProvider
125{
126public:
128 typedef T_result result_type;
129
130protected:
131 static_assert(std::tuple_size<T_result>::value > 2,
132 "Result tuple too small");
133 static_assert(std::is_same <
134 typename std::tuple_element <
135 std::tuple_size<T_result>::value - 2,
137 >::type,
138 QString
139 >::value,
140 "Second to last result type not a QString");
141 static_assert(std::is_same <
142 typename std::tuple_element <
143 std::tuple_size<T_result>::value - 1,
145 >::type,
146 GpgME::Error
147 >::value,
148 "Last result type not a GpgME::Error");
149
150 explicit ThreadedJobMixin(GpgME::Context *ctx)
151 : T_base(nullptr), m_ctx(ctx), m_thread(), m_auditLog(), m_auditLogError()
152 {
153 }
154
155 void lateInitialization()
156 {
157 assert(m_ctx);
158 QObject::connect(&m_thread, &QThread::finished, this,
159 &mixin_type::slotFinished);
160 m_ctx->setProgressProvider(this);
161 QGpgME::g_context_map.insert(this, m_ctx.get());
162 }
163
165 {
166 QGpgME::g_context_map.remove(this);
167 }
168
169 template <typename T_binder>
170 void run(const T_binder &func)
171 {
172 m_thread.setFunction(std::bind(func, this->context()));
173 m_thread.start();
174 }
175 template <typename T_binder>
176 void run(const T_binder &func, const std::shared_ptr<QIODevice> &io)
177 {
178 if (io) {
179 io->moveToThread(&m_thread);
180 }
181 // the arguments passed here to the functor are stored in a QThread, and are not
182 // necessarily destroyed (living outside the UI thread) at the time the result signal
183 // is emitted and the signal receiver wants to clean up IO devices.
184 // To avoid such races, we pass std::weak_ptr's to the functor.
185 m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io)));
186 m_thread.start();
187 }
188 template <typename T_binder>
189 void run(const T_binder &func, const std::shared_ptr<QIODevice> &io1, const std::shared_ptr<QIODevice> &io2)
190 {
191 if (io1) {
192 io1->moveToThread(&m_thread);
193 }
194 if (io2) {
195 io2->moveToThread(&m_thread);
196 }
197 // the arguments passed here to the functor are stored in a QThread, and are not
198 // necessarily destroyed (living outside the UI thread) at the time the result signal
199 // is emitted and the signal receiver wants to clean up IO devices.
200 // To avoid such races, we pass std::weak_ptr's to the functor.
201 m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io1), std::weak_ptr<QIODevice>(io2)));
202 m_thread.start();
203 }
204 GpgME::Context *context() const
205 {
206 return m_ctx.get();
207 }
208
209 virtual void resultHook(const result_type &) {}
210
211 void slotFinished()
212 {
213 const T_result r = m_thread.result();
214 m_auditLog = std::get < std::tuple_size<T_result>::value - 2 > (r);
215 m_auditLogError = std::get < std::tuple_size<T_result>::value - 1 > (r);
216 resultHook(r);
217 Q_EMIT this->done();
218 doEmitResult(r);
219 this->deleteLater();
220 }
221 void slotCancel() Q_DECL_OVERRIDE {
222 if (m_ctx)
223 {
224 m_ctx->cancelPendingOperation();
225 }
226 }
227 QString auditLogAsHtml() const Q_DECL_OVERRIDE
228 {
229 return m_auditLog;
230 }
231 GpgME::Error auditLogError() const Q_DECL_OVERRIDE
232 {
233 return m_auditLogError;
234 }
235 void showProgress(const char * /*what*/,
236 int /*type*/, int current, int total) Q_DECL_OVERRIDE {
237 // will be called from the thread exec'ing the operation, so
238 // just bounce everything to the owning thread:
239 // ### hope this is thread-safe (meta obj is const, and
240 // ### portEvent is thread-safe, so should be ok)
241 QMetaObject::invokeMethod(this, "progress", Qt::QueuedConnection,
242 // TODO port
244 Q_ARG(int, current),
245 Q_ARG(int, total));
246 }
247private:
248 template <typename T1, typename T2>
249 void doEmitResult(const std::tuple<T1, T2> &tuple)
250 {
251 Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple));
252 }
253
254 template <typename T1, typename T2, typename T3>
255 void doEmitResult(const std::tuple<T1, T2, T3> &tuple)
256 {
257 Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple));
258 }
259
260 template <typename T1, typename T2, typename T3, typename T4>
261 void doEmitResult(const std::tuple<T1, T2, T3, T4> &tuple)
262 {
263 Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple));
264 }
265
266 template <typename T1, typename T2, typename T3, typename T4, typename T5>
267 void doEmitResult(const std::tuple<T1, T2, T3, T4, T5> &tuple)
268 {
269 Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple), std::get<4>(tuple));
270 }
271
272private:
273 std::shared_ptr<GpgME::Context> m_ctx;
274 Thread<T_result> m_thread;
275 QString m_auditLog;
276 GpgME::Error m_auditLogError;
277};
278
279}
280}
281
282#endif /* __QGPGME_THREADEDJOBMIXING_H__ */
Definition threadedjobmixin.h:65
Definition threadedjobmixin.h:96
Definition threadedjobmixin.h:125
Definition threadedjobmixin.h:79
Definition qgpgmebackend.h:43