libQuotient
A Qt library for building matrix clients
qt_connection_util.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2019 Kitsune Ral <kitsune-ral@users.sf.net>
2 // SPDX-License-Identifier: LGPL-2.1-or-later
3 
4 #pragma once
5 
6 #include <QtCore/QObject>
7 #include <QtCore/QPointer>
8 
9 namespace Quotient {
10 
11 //! \brief Create a connection that self-disconnects when its slot returns true
12 //!
13 //! The "slot" signature accepted by connectUntil() is different from normal Qt slots in that its
14 //! return value must be bool, not void. Also, as of this writing, connectUntil() doesn't accept
15 //! member function pointers for slots as QObject::connect or Quotient::connectSingleShot do; if
16 //! you want to use a member function of the context object you should pass a lambda or bind
17 //! the context to the member function with std::bind_front before passing it to connectUntil().
18 //! \return whether the connection should be dropped; false means that the
19 //! connection remains; upon returning true, the slot is disconnected
20 //! from the signal.
21 template <typename SmartSlotT>
22 inline auto connectUntil(auto* sender, auto signal, QObject* context, SmartSlotT&& smartSlot,
23  Qt::ConnectionType connType = Qt::AutoConnection)
24 {
25  auto* cHolder = new QObject(context);
26  // Apart from checking the "smart slot" return type, the 'requires' clause below prevents Qt
27  // from eagerly trying to fill the lambda with more arguments than the "smart slot" can take
28  return QObject::connect(
29  sender, signal, cHolder,
30  [sl = std::forward<SmartSlotT>(smartSlot), cHolder]<typename... Ts>
31  requires std::invocable<SmartSlotT, Ts...>
32  (const Ts&... args) mutable {
33  static_assert(std::is_same_v<decltype(sl(args...)), bool>);
34  if (sl(args...))
35  delete cHolder; // break the connection
36  },
37  connType);
38 }
39 
40 //! Create a connection that self-disconnects after triggering on the signal
41 template <typename ContextT, typename SlotT>
42 [[deprecated("Use QObject::connect() with Qt::SingleShotConnection, or QtFuture::connect()")]] //
43 inline auto connectSingleShot(auto* sender, auto signal, ContextT* context, SlotT slot,
44  Qt::ConnectionType connType = Qt::AutoConnection)
45 {
46  return QObject::connect(sender, signal, context, slot,
47  Qt::ConnectionType(connType | Qt::SingleShotConnection));
48 }
49 
50 /*! \brief A guard pointer that disconnects an interested object upon destruction
51  *
52  * It's almost QPointer<> except that you have to initialise it with one
53  * more additional parameter - a pointer to a QObject that will be
54  * disconnected from signals of the underlying pointer upon the guard's
55  * destruction. Note that destructing the guard doesn't destruct either QObject.
56  */
57 template <typename T>
58 class ConnectionsGuard : public QPointer<T> {
59 public:
60  ConnectionsGuard(T* publisher, QObject* subscriber)
62  {}
64  {
65  if (*this)
66  (*this)->disconnect(subscriber);
67  }
71  using QPointer<T>::operator=;
72 
73 private:
74  QObject* subscriber;
75 };
76 
77 } // namespace Quotient