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