QGpgME  17.2.1.0000000
Qt API for GpgME
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 
57 namespace QGpgME
58 {
59 namespace _detail
60 {
61 
62 QString audit_log_as_html(GpgME::Context *ctx, GpgME::Error &err);
63 
65 {
66  const QList<QByteArray> m_list;
67  mutable const char **m_patterns;
68 public:
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;
82 public:
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) {}
86  ~ToThreadMover()
87  {
88  if (m_object && m_thread) {
89  m_object->moveToThread(m_thread);
90  }
91  }
92 };
93 
94 template <typename T_result>
95 class Thread : public QThread
96 {
97 public:
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  bool hasFunction()
107  {
108  const QMutexLocker locker(&m_mutex);
109  return static_cast<bool>(m_function);
110  }
111 
112  T_result result() const
113  {
114  const QMutexLocker locker(&m_mutex);
115  return m_result;
116  }
117 
118 private:
119  void run() override {
120  const QMutexLocker locker(&m_mutex);
121  m_result = m_function();
122  }
123 private:
124  mutable QMutex m_mutex;
125  std::function<T_result()> m_function;
126  T_result m_result;
127 };
128 
129 template <typename T_base, typename T_result = std::tuple<GpgME::Error, QString, GpgME::Error> >
130 class ThreadedJobMixin : public T_base, public GpgME::ProgressProvider
131 {
132 public:
134  typedef T_result result_type;
135 
136  void run()
137  {
138  Q_ASSERT(m_thread.hasFunction() && "Call setWorkerFunction() before run()");
139  m_thread.start();
140  }
141 
142 protected:
143  static_assert(std::tuple_size<T_result>::value > 2,
144  "Result tuple too small");
145  static_assert(std::is_same <
146  typename std::tuple_element <
147  std::tuple_size<T_result>::value - 2,
148  T_result
149  >::type,
150  QString
151  >::value,
152  "Second to last result type not a QString");
153  static_assert(std::is_same <
154  typename std::tuple_element <
155  std::tuple_size<T_result>::value - 1,
156  T_result
157  >::type,
158  GpgME::Error
159  >::value,
160  "Last result type not a GpgME::Error");
161 
162  explicit ThreadedJobMixin(GpgME::Context *ctx)
163  : T_base(nullptr), m_ctx(ctx), m_thread(), m_auditLog(), m_auditLogError()
164  {
165  }
166 
167  void lateInitialization()
168  {
169  assert(m_ctx);
170  QObject::connect(&m_thread, &QThread::finished, this,
171  &mixin_type::slotFinished);
172  m_ctx->setProgressProvider(this);
173  QGpgME::g_context_map.insert(this, m_ctx.get());
174  }
175 
177  {
178  QGpgME::g_context_map.remove(this);
179  }
180 
181  template <typename T_binder>
182  void setWorkerFunction(const T_binder &func)
183  {
184  m_thread.setFunction([this, func]() { return func(this->context()); });
185  }
186 
187  template <typename T_binder>
188  void run(const T_binder &func)
189  {
190  m_thread.setFunction(std::bind(func, this->context()));
191  m_thread.start();
192  }
193  template <typename T_binder>
194  void run(const T_binder &func, const std::shared_ptr<QIODevice> &io)
195  {
196  if (io) {
197  io->moveToThread(&m_thread);
198  }
199  // the arguments passed here to the functor are stored in a QThread, and are not
200  // necessarily destroyed (living outside the UI thread) at the time the result signal
201  // is emitted and the signal receiver wants to clean up IO devices.
202  // To avoid such races, we pass std::weak_ptr's to the functor.
203  m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io)));
204  m_thread.start();
205  }
206  template <typename T_binder>
207  void run(const T_binder &func, const std::shared_ptr<QIODevice> &io1, const std::shared_ptr<QIODevice> &io2)
208  {
209  if (io1) {
210  io1->moveToThread(&m_thread);
211  }
212  if (io2) {
213  io2->moveToThread(&m_thread);
214  }
215  // the arguments passed here to the functor are stored in a QThread, and are not
216  // necessarily destroyed (living outside the UI thread) at the time the result signal
217  // is emitted and the signal receiver wants to clean up IO devices.
218  // To avoid such races, we pass std::weak_ptr's to the functor.
219  m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io1), std::weak_ptr<QIODevice>(io2)));
220  m_thread.start();
221  }
222  GpgME::Context *context() const
223  {
224  return m_ctx.get();
225  }
226 
227  virtual void resultHook(const result_type &) {}
228 
229  void slotFinished()
230  {
231  const T_result r = m_thread.result();
232  m_auditLog = std::get < std::tuple_size<T_result>::value - 2 > (r);
233  m_auditLogError = std::get < std::tuple_size<T_result>::value - 1 > (r);
234  resultHook(r);
235  Q_EMIT this->done();
236  doEmitResult(r);
237  this->deleteLater();
238  }
239  void slotCancel() override {
240  if (m_ctx)
241  {
242  m_ctx->cancelPendingOperation();
243  }
244  }
245  QString auditLogAsHtml() const override
246  {
247  return m_auditLog;
248  }
249  GpgME::Error auditLogError() const override
250  {
251  return m_auditLogError;
252  }
253  void showProgress(const char *what,
254  int type, int current, int total) override {
255  QMetaObject::invokeMethod(this, [this, current, total]() {
256  Q_EMIT this->jobProgress(current, total);
257  }, Qt::QueuedConnection);
258  const QString what_ = QString::fromUtf8(what);
259  QMetaObject::invokeMethod(this, [this, what_, type, current, total]() {
260  Q_EMIT this->rawProgress(what_, type, current, total);
261  }, Qt::QueuedConnection);
262  QMetaObject::invokeMethod(this, [this, what_, current, total]() {
263  QT_WARNING_PUSH
264  QT_WARNING_DISABLE_DEPRECATED
265  Q_EMIT this->progress(what_, current, total);
266  QT_WARNING_POP
267  }, Qt::QueuedConnection);
268  }
269 private:
270  template <typename T1, typename T2>
271  void doEmitResult(const std::tuple<T1, T2> &tuple)
272  {
273  Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple));
274  }
275 
276  template <typename T1, typename T2, typename T3>
277  void doEmitResult(const std::tuple<T1, T2, T3> &tuple)
278  {
279  Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple));
280  }
281 
282  template <typename T1, typename T2, typename T3, typename T4>
283  void doEmitResult(const std::tuple<T1, T2, T3, T4> &tuple)
284  {
285  Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple));
286  }
287 
288  template <typename T1, typename T2, typename T3, typename T4, typename T5>
289  void doEmitResult(const std::tuple<T1, T2, T3, T4, T5> &tuple)
290  {
291  Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple), std::get<4>(tuple));
292  }
293 
294 private:
295  std::shared_ptr<GpgME::Context> m_ctx;
296  Thread<T_result> m_thread;
297  QString m_auditLog;
298  GpgME::Error m_auditLogError;
299 };
300 
301 }
302 }
303 
304 #endif /* __QGPGME_THREADEDJOBMIXING_H__ */
Definition: threadedjobmixin.h:65
Definition: threadedjobmixin.h:96
Definition: threadedjobmixin.h:131
Definition: threadedjobmixin.h:79