LeechCraft  0.6.70-15082-g543737046d
Modular cross-platform feature rich live environment.
basehookinterconnector.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * LeechCraft - modular cross-platform feature rich internet client.
3  * Copyright (C) 2006-2014 Georg Rudoy
4  *
5  * Distributed under the Boost Software License, Version 1.0.
6  * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7  **********************************************************************/
8 
10 #include <QMetaMethod>
11 #include <QtDebug>
12 
13 namespace LC
14 {
15 namespace Util
16 {
18  : QObject (parent)
19  {
20  }
21 
22  BaseHookInterconnector::~BaseHookInterconnector ()
23  {
24  }
25 
26  namespace
27  {
28  bool IsHookMethod (const QMetaMethod& method)
29  {
30  return method.parameterTypes ().value (0) == "LC::IHookProxy_ptr";
31  }
32 
33  auto BuildHookSlots (const QObject *obj)
34  {
35  const auto objMo = obj->metaObject ();
36 
37  QHash<QByteArray, QList<QMetaMethod>> hookSlots;
38  for (int i = 0, size = objMo->methodCount (); i < size; ++i)
39  {
40  const auto& method = objMo->method (i);
41  if (IsHookMethod (method))
42  hookSlots [method.name ()] << method;
43  }
44 
45  return hookSlots;
46  }
47 
48  bool ShouldBeVerbose ()
49  {
50  static bool result = qEnvironmentVariableIsSet ("LC_VERBOSE_HOOK_CHECKS");
51  return result;
52  }
53 
54  void CheckMatchingSigs (const QObject *snd, const QObject *rcv)
55  {
56  if (!ShouldBeVerbose ())
57  return;
58 
59  const auto& hookSlots = BuildHookSlots (snd);
60 
61  const auto rcvMo = rcv->metaObject ();
62 
63  for (int i = 0, size = rcvMo->methodCount (); i < size; ++i)
64  {
65  const auto& rcvMethod = rcvMo->method (i);
66  if (!IsHookMethod (rcvMethod))
67  continue;
68 
69  const auto& rcvName = rcvMethod.name ();
70  if (!hookSlots.contains (rcvName))
71  {
72  qWarning () << Q_FUNC_INFO
73  << "no method matching method"
74  << rcvName
75  << "(receiver"
76  << rcv
77  << ") in sender object"
78  << snd;
79  continue;
80  }
81 
82  const auto& sndMethods = hookSlots [rcvName];
83  if (std::none_of (sndMethods.begin (), sndMethods.end (),
84  [&rcvMethod] (const QMetaMethod& sndMethod)
85  {
86  return QMetaObject::checkConnectArgs (sndMethod, rcvMethod);
87  }))
88  qWarning () << Q_FUNC_INFO
89  << "incompatible signatures for hook"
90  << rcvName
91  << "in"
92  << snd
93  << "and"
94  << rcv;
95  }
96  }
97 
98 #define LC_N(a) (QMetaObject::normalizedSignature(a))
99 #define LC_TOSLOT(a) ('1' + QByteArray(a))
100 #define LC_TOSIGNAL(a) ('2' + QByteArray(a))
101  void ConnectHookSignals (QObject *sender, QObject *receiver, bool destSlot)
102  {
103  if (destSlot)
104  CheckMatchingSigs (sender, receiver);
105 
106  const QMetaObject *mo = sender->metaObject ();
107  for (int i = 0, size = mo->methodCount (); i < size; ++i)
108  {
109  QMetaMethod method = mo->method (i);
110  if (method.methodType () != QMetaMethod::Signal)
111  continue;
112 
113  if (!IsHookMethod (method))
114  continue;
115 
116  const auto& signature = method.methodSignature ();
117  if (receiver->metaObject ()->indexOfMethod (LC_N (signature)) == -1)
118  {
119  if (!destSlot)
120  {
121  qWarning () << Q_FUNC_INFO
122  << "not found meta method for"
123  << signature
124  << "in receiver object"
125  << receiver;
126  }
127  continue;
128  }
129 
130  if (!QObject::connect (sender,
131  LC_TOSIGNAL (signature),
132  receiver,
133  destSlot ? LC_TOSLOT (signature) : LC_TOSIGNAL (signature),
134  Qt::UniqueConnection))
135  qWarning () << Q_FUNC_INFO
136  << "connect for"
137  << sender
138  << "->"
139  << receiver
140  << ":"
141  << signature
142  << "failed";
143  else if (ShouldBeVerbose ())
144  qDebug () << Q_FUNC_INFO
145  << "connecting"
146  << sender
147  << "->"
148  << receiver
149  << "for"
150  << signature;
151  }
152  }
153 #undef LC_TOSIGNAL
154 #undef LC_TOSLOT
155 #undef LC_N
156  }
157 
158  void BaseHookInterconnector::AddPlugin (QObject *plugin)
159  {
160  Plugins_.push_back (plugin);
161 
162  ConnectHookSignals (this, plugin, true);
163  }
164 
165  void BaseHookInterconnector::RegisterHookable (QObject *object)
166  {
167  ConnectHookSignals (object, this, false);
168  }
169 }
170 }
LC::Util::BaseHookInterconnector::BaseHookInterconnector
BaseHookInterconnector(QObject *parent=0)
Creates the interconnector with the given parent.
Definition: basehookinterconnector.cpp:29
basehookinterconnector.h
LC_TOSLOT
#define LC_TOSLOT(a)
Definition: basehookinterconnector.cpp:111
LC
Definition: constants.h:14
LC_N
#define LC_N(a)
Definition: basehookinterconnector.cpp:110
LC_TOSIGNAL
#define LC_TOSIGNAL(a)
Definition: basehookinterconnector.cpp:112