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