/thirdparty/qxt/qxtweb-standalone/qxtweb/qxtmetaobject.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 376 lines · 243 code · 33 blank · 100 comment · 50 complexity · ee8b86a10748e7fb663323b67e8bc796 MD5 · raw file

  1. /****************************************************************************
  2. **
  3. ** Copyright (C) Qxt Foundation. Some rights reserved.
  4. **
  5. ** This file is part of the QxtCore module of the Qxt library.
  6. **
  7. ** This library is free software; you can redistribute it and/or modify it
  8. ** under the terms of the Common Public License, version 1.0, as published
  9. ** by IBM, and/or under the terms of the GNU Lesser General Public License,
  10. ** version 2.1, as published by the Free Software Foundation.
  11. **
  12. ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
  13. ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
  14. ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
  15. ** FITNESS FOR A PARTICULAR PURPOSE.
  16. **
  17. ** You should have received a copy of the CPL and the LGPL along with this
  18. ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
  19. ** included with the source distribution for more information.
  20. ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
  21. **
  22. ** <http://libqxt.org> <foundation@libqxt.org>
  23. **
  24. ****************************************************************************/
  25. /*!
  26. \namespace QxtMetaObject
  27. \inmodule QxtCore
  28. \brief The QxtMetaObject namespace provides extensions to QMetaObject
  29. including QxtMetaObject::bind
  30. */
  31. #include "qxtmetaobject.h"
  32. #include "qxtboundfunction.h"
  33. #include "qxtboundcfunction.h"
  34. #include "qxtmetatype.h"
  35. #include <QByteArray>
  36. #include <QMetaObject>
  37. #include <QMetaMethod>
  38. #include <QtDebug>
  39. #ifndef QXT_DOXYGEN_RUN
  40. class QxtBoundArgument
  41. {
  42. // This class intentionally left blank
  43. };
  44. Q_DECLARE_METATYPE(QxtBoundArgument)
  45. class QxtBoundFunctionBase;
  46. QxtBoundFunction::QxtBoundFunction(QObject* parent) : QObject(parent)
  47. {
  48. // initializer only
  49. }
  50. #endif
  51. bool QxtBoundFunction::invoke(Qt::ConnectionType type, QXT_IMPL_10ARGS(QVariant))
  52. {
  53. return invoke(type, QXT_VAR_ARG(1), QXT_VAR_ARG(2), QXT_VAR_ARG(3), QXT_VAR_ARG(4), QXT_VAR_ARG(5), QXT_VAR_ARG(6), QXT_VAR_ARG(7), QXT_VAR_ARG(8), QXT_VAR_ARG(9), QXT_VAR_ARG(10));
  54. }
  55. bool QxtBoundFunction::invoke(Qt::ConnectionType type, QGenericReturnArgument returnValue, QXT_IMPL_10ARGS(QVariant))
  56. {
  57. return invoke(type, returnValue, QXT_VAR_ARG(1), QXT_VAR_ARG(2), QXT_VAR_ARG(3), QXT_VAR_ARG(4), QXT_VAR_ARG(5), QXT_VAR_ARG(6), QXT_VAR_ARG(7), QXT_VAR_ARG(8), QXT_VAR_ARG(9), QXT_VAR_ARG(10));
  58. }
  59. QxtBoundFunctionBase::QxtBoundFunctionBase(QObject* parent, QGenericArgument* params[10], QByteArray types[10]) : QxtBoundFunction(parent)
  60. {
  61. for (int i = 0; i < 10; i++)
  62. {
  63. if (!params[i]) break;
  64. if (QByteArray(params[i]->name()) == "QxtBoundArgument")
  65. {
  66. arg[i] = QGenericArgument("QxtBoundArgument", params[i]->data());
  67. }
  68. else
  69. {
  70. data[i] = qxtConstructFromGenericArgument(*params[i]);
  71. arg[i] = p[i] = QGenericArgument(params[i]->name(), data[i]);
  72. }
  73. bindTypes[i] = types[i];
  74. }
  75. }
  76. QxtBoundFunctionBase::~QxtBoundFunctionBase()
  77. {
  78. for (int i = 0; i < 10; i++)
  79. {
  80. if (arg[i].name() == 0) return;
  81. if (QByteArray(arg[i].name()) != "QxtBoundArgument") qxtDestroyFromGenericArgument(arg[i]);
  82. }
  83. }
  84. int QxtBoundFunctionBase::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
  85. {
  86. _id = QObject::qt_metacall(_c, _id, _a);
  87. if (_id < 0)
  88. return _id;
  89. if (_c == QMetaObject::InvokeMetaMethod)
  90. {
  91. if (_id == 0)
  92. {
  93. for (int i = 0; i < 10; i++)
  94. {
  95. if (QByteArray(arg[i].name()) == "QxtBoundArgument")
  96. {
  97. p[i] = QGenericArgument(bindTypes[i].constData(), _a[(quintptr)(arg[i].data())]);
  98. }
  99. }
  100. invokeImpl(Qt::DirectConnection, QGenericReturnArgument(), p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
  101. }
  102. _id = -1;
  103. }
  104. return _id;
  105. }
  106. bool QxtBoundFunctionBase::invokeBase(Qt::ConnectionType type, QGenericReturnArgument returnValue, QXT_IMPL_10ARGS(QGenericArgument))
  107. {
  108. QGenericArgument* args[10] = { &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10 };
  109. for (int i = 0; i < 10; i++)
  110. {
  111. if (QByteArray(arg[i].name()) == "QxtBoundArgument")
  112. {
  113. p[i] = *args[(quintptr)(arg[i].data()) - 1];
  114. }
  115. }
  116. return invokeImpl(type, returnValue, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
  117. }
  118. bool QxtBoundFunction::invoke(Qt::ConnectionType type, QGenericReturnArgument returnValue, QXT_IMPL_10ARGS(QGenericArgument))
  119. {
  120. return reinterpret_cast<QxtBoundFunctionBase*>(this)->invokeBase(type, returnValue, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
  121. }
  122. #ifndef QXT_DOXYGEN_RUN
  123. class QxtBoundSlot : public QxtBoundFunctionBase
  124. {
  125. public:
  126. QByteArray sig;
  127. QxtBoundSlot(QObject* receiver, const char* invokable, QGenericArgument* params[10], QByteArray types[10]) : QxtBoundFunctionBase(receiver, params, types), sig(invokable)
  128. {
  129. // initializers only
  130. }
  131. virtual bool invokeImpl(Qt::ConnectionType type, QGenericReturnArgument returnValue, QXT_IMPL_10ARGS(QGenericArgument))
  132. {
  133. if (!QMetaObject::invokeMethod(parent(), QxtMetaObject::methodName(sig.constData()), type, returnValue, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10))
  134. {
  135. qWarning() << "QxtBoundFunction: call to" << sig << "failed";
  136. return false;
  137. }
  138. return true;
  139. }
  140. };
  141. #endif
  142. namespace QxtMetaObject
  143. {
  144. /*!
  145. Returns the name of the given method.
  146. Example usage:
  147. \code
  148. QByteArray method = QxtMetaObject::methodName(" int foo ( int bar, double baz )");
  149. // method is now "foo"
  150. \endcode
  151. */
  152. QByteArray methodName(const char* method)
  153. {
  154. QByteArray name = methodSignature(method);
  155. const int idx = name.indexOf("(");
  156. if (idx != -1)
  157. name.truncate(idx);
  158. return name;
  159. }
  160. /*!
  161. Returns the signature of the given method.
  162. */
  163. QByteArray methodSignature(const char* method)
  164. {
  165. QByteArray name = QMetaObject::normalizedSignature(method);
  166. if(name[0] >= '0' && name[0] <= '9')
  167. return name.mid(1);
  168. return name;
  169. }
  170. /*!
  171. Checks if \a method contains parentheses and begins with 1 or 2.
  172. */
  173. bool isSignalOrSlot(const char* method)
  174. {
  175. QByteArray m(method);
  176. return (m.count() && (m[0] >= '0' && m[0] <= '9') && m.contains('(') && m.contains(')'));
  177. }
  178. /*!
  179. * Creates a binding to the provided signal, slot, or Q_INVOKABLE method using the
  180. * provided parameter list. The type of each argument is deduced from the type of
  181. * the QVariant. This function cannot bind positional arguments; see the
  182. * overload using QGenericArgument.
  183. *
  184. * If the provided QObject does not implement the requested method, or if the
  185. * argument list is incompatible with the method's function signature, this
  186. * function returns NULL.
  187. *
  188. * The returned QxtBoundFunction is created as a child of the receiver.
  189. * Changing the parent will result in undefined behavior.
  190. *
  191. * \sa QxtMetaObject::connect, QxtBoundFunction
  192. */
  193. QxtBoundFunction* bind(QObject* recv, const char* invokable, QXT_IMPL_10ARGS(QVariant))
  194. {
  195. if (!recv)
  196. {
  197. qWarning() << "QxtMetaObject::bind: cannot connect to null QObject";
  198. return 0;
  199. }
  200. QVariant* args[10] = { &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10 };
  201. QByteArray connSlot("2"), recvSlot(QMetaObject::normalizedSignature(invokable));
  202. const QMetaObject* meta = recv->metaObject();
  203. int methodID = meta->indexOfMethod(QxtMetaObject::methodSignature(recvSlot.constData()));
  204. if (methodID == -1)
  205. {
  206. qWarning() << "QxtMetaObject::bind: no such method " << recvSlot;
  207. return 0;
  208. }
  209. QMetaMethod method = meta->method(methodID);
  210. int argCount = method.parameterTypes().count();
  211. const QList<QByteArray> paramTypes = method.parameterTypes();
  212. for (int i = 0; i < argCount; i++)
  213. {
  214. if (paramTypes[i] == "QxtBoundArgument") continue;
  215. int type = QMetaType::type(paramTypes[i].constData());
  216. if (!args[i]->canConvert((QVariant::Type)type))
  217. {
  218. qWarning() << "QxtMetaObject::bind: incompatible parameter list for " << recvSlot;
  219. return 0;
  220. }
  221. }
  222. return QxtMetaObject::bind(recv, invokable, QXT_ARG(1), QXT_ARG(2), QXT_ARG(3), QXT_ARG(4), QXT_ARG(5), QXT_ARG(6), QXT_ARG(7), QXT_ARG(8), QXT_ARG(9), QXT_ARG(10));
  223. }
  224. /*!
  225. * Creates a binding to the provided signal, slot, or Q_INVOKABLE method using the
  226. * provided parameter list. Use the Q_ARG macro to specify constant parameters, or
  227. * use the QXT_BIND macro to relay a parameter from a connected signal or passed
  228. * via the QxtBoundFunction::invoke() method.
  229. *
  230. * If the provided QObject does not implement the requested method, or if the
  231. * argument list is incompatible with the method's function signature, this
  232. * function returns NULL.
  233. *
  234. * The returned QxtBoundFunction is created as a child of the receiver.
  235. * Changing the parent will result in undefined behavior.
  236. *
  237. * \sa QxtMetaObject::connect, QxtBoundFunction, QXT_BIND
  238. */
  239. QxtBoundFunction* bind(QObject* recv, const char* invokable, QXT_IMPL_10ARGS(QGenericArgument))
  240. {
  241. if (!recv)
  242. {
  243. qWarning() << "QxtMetaObject::bind: cannot connect to null QObject";
  244. return 0;
  245. }
  246. QGenericArgument* args[10] = { &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10 };
  247. QByteArray connSlot("2"), recvSlot(QMetaObject::normalizedSignature(invokable)), bindTypes[10];
  248. const QMetaObject* meta = recv->metaObject();
  249. int methodID = meta->indexOfMethod(QxtMetaObject::methodSignature(recvSlot.constData()).constData());
  250. if (methodID == -1)
  251. {
  252. qWarning() << "QxtMetaObject::bind: no such method " << recvSlot;
  253. return 0;
  254. }
  255. QMetaMethod method = meta->method(methodID);
  256. int argCount = method.parameterTypes().count();
  257. connSlot += QxtMetaObject::methodName(invokable) + '(';
  258. for (int i = 0; i < 10; i++)
  259. {
  260. if (args[i]->name() == 0) break; // done
  261. if (i >= argCount)
  262. {
  263. qWarning() << "QxtMetaObject::bind: too many arguments passed to " << invokable;
  264. return 0;
  265. }
  266. if (i > 0) connSlot += ','; // argument separator
  267. if (QByteArray(args[i]->name()) == "QxtBoundArgument")
  268. {
  269. Q_ASSERT_X((quintptr)(args[i]->data()) > 0 && (quintptr)(args[i]->data()) <= 10, "QXT_BIND", "invalid argument number");
  270. connSlot += method.parameterTypes()[i];
  271. bindTypes[i] = method.parameterTypes()[i];
  272. }
  273. else
  274. {
  275. connSlot += args[i]->name(); // type name
  276. }
  277. }
  278. connSlot = QMetaObject::normalizedSignature(connSlot += ')');
  279. if (!QMetaObject::checkConnectArgs(recvSlot.constData(), connSlot.constData()))
  280. {
  281. qWarning() << "QxtMetaObject::bind: provided parameters " << connSlot.mid(connSlot.indexOf('(')) << " is incompatible with " << invokable;
  282. return 0;
  283. }
  284. return new QxtBoundSlot(recv, invokable, args, bindTypes);
  285. }
  286. /*!
  287. Connects a signal to a QxtBoundFunction.
  288. */
  289. bool connect(QObject* sender, const char* signal, QxtBoundFunction* slot, Qt::ConnectionType type)
  290. {
  291. if (!sender)
  292. {
  293. qWarning() << "Got connect() with a null sender!";
  294. return false;
  295. }
  296. const QMetaObject* meta = sender->metaObject();
  297. int methodID = meta->indexOfMethod(meta->normalizedSignature(signal).mid(1).constData());
  298. if (methodID < 0)
  299. {
  300. qWarning() << "QxtMetaObject::connect: no such signal: " << QByteArray(signal).mid(1);
  301. return false;
  302. }
  303. return QMetaObject::connect(sender, methodID, slot, QObject::staticMetaObject.methodCount(), (int)(type));
  304. }
  305. /*!
  306. \relates QxtMetaObject
  307. This overload always invokes the member using the connection type Qt::AutoConnection.
  308. \sa QMetaObject::invokeMethod()
  309. */
  310. bool invokeMethod(QObject* object, const char* member, const QVariant& arg0,
  311. const QVariant& arg1, const QVariant& arg2, const QVariant& arg3,
  312. const QVariant& arg4, const QVariant& arg5, const QVariant& arg6,
  313. const QVariant& arg7, const QVariant& arg8, const QVariant& arg9)
  314. {
  315. return invokeMethod(object, member, Qt::AutoConnection,
  316. arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
  317. }
  318. /*!
  319. \relates QxtMetaObject
  320. Invokes the \a member (a signal or a slot name) on the \a object.
  321. Returns \c true if the member could be invoked. Returns \c false
  322. if there is no such member or the parameters did not match.
  323. \sa QMetaObject::invokeMethod()
  324. */
  325. bool invokeMethod(QObject* object, const char* member, Qt::ConnectionType type,
  326. const QVariant& arg0, const QVariant& arg1, const QVariant& arg2,
  327. const QVariant& arg3, const QVariant& arg4, const QVariant& arg5,
  328. const QVariant& arg6, const QVariant& arg7, const QVariant& arg8, const QVariant& arg9)
  329. {
  330. #define QXT_MO_ARG(i) QGenericArgument(arg ## i.typeName(), arg ## i.constData())
  331. return QMetaObject::invokeMethod(object, methodName(member), type,
  332. QXT_MO_ARG(0), QXT_MO_ARG(1), QXT_MO_ARG(2), QXT_MO_ARG(3), QXT_MO_ARG(4),
  333. QXT_MO_ARG(5), QXT_MO_ARG(6), QXT_MO_ARG(7), QXT_MO_ARG(8), QXT_MO_ARG(9));
  334. }
  335. }