1 /****************************************************************************
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
5 ** This file is part of the QxtCore module of the Qt eXTension library
7 ** This library is free software; you can redistribute it and/or modify it
8 ** under the terms of th Common Public License, version 1.0, as published by
11 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
12 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
13 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
14 ** FITNESS FOR A PARTICULAR PURPOSE.
16 ** You should have received a copy of the CPL along with this file.
17 ** See the LICENSE file and the cpl1.0.txt file included with the source
18 ** distribution for more information. If you did not receive a copy of the
19 ** license, contact the Qxt Foundation.
21 ** <http://libqxt.sourceforge.net> <foundation@libqxt.org>
23 ****************************************************************************/
25 \class QxtMetaObject QxtMetaObject
29 \brief provides extensions to QMetaObject
31 including QxtMetaObject::bind \n
34 #include "qxtmetaobject.h"
35 #include "qxtboundfunction.h"
36 #include "qxtboundcfunction.h"
37 #include "qxtmetatype.h"
40 #include <QMetaObject>
41 #include <QMetaMethod>
44 #ifndef QXT_DOXYGEN_RUN
45 class QxtBoundArgument
47 // This class intentionally left blank
49 Q_DECLARE_METATYPE(QxtBoundArgument)
51 class QxtBoundFunctionBase;
53 QxtBoundFunction::QxtBoundFunction(QObject* parent) : QObject(parent)
59 bool QxtBoundFunction::invoke(Qt::ConnectionType type, QXT_IMPL_10ARGS(QVariant))
61 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));
64 bool QxtBoundFunction::invoke(Qt::ConnectionType type, QGenericReturnArgument returnValue, QXT_IMPL_10ARGS(QVariant))
66 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));
69 QxtBoundFunctionBase::QxtBoundFunctionBase(QObject* parent, QGenericArgument* params[10], QByteArray types[10]) : QxtBoundFunction(parent)
71 for (int i=0; i<10; i++)
73 if (!params[i]) break;
74 if (QByteArray(params[i]->name()) == "QxtBoundArgument")
76 arg[i] = QGenericArgument("QxtBoundArgument", params[i]->data());
80 data[i] = qxtConstructFromGenericArgument(*params[i]);
81 arg[i] = p[i] = QGenericArgument(params[i]->name(), data[i]);
83 bindTypes[i] = types[i];
87 QxtBoundFunctionBase::~QxtBoundFunctionBase()
89 for (int i=0; i<10; i++)
91 if (arg[i].name() == 0) return;
92 if (QByteArray(arg[i].name()) != "QxtBoundArgument") qxtDestroyFromGenericArgument(arg[i]);
96 int QxtBoundFunctionBase::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
98 _id = QObject::qt_metacall(_c, _id, _a);
101 if (_c == QMetaObject::InvokeMetaMethod)
105 for (int i = 0; i < 10; i++)
107 if (QByteArray(arg[i].name()) == "QxtBoundArgument")
109 p[i] = QGenericArgument(bindTypes[i].constData(), _a[(quintptr)(arg[i].data())]);
112 invokeImpl(Qt::DirectConnection, QGenericReturnArgument(), p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
119 bool QxtBoundFunctionBase::invokeBase(Qt::ConnectionType type, QGenericReturnArgument returnValue, QXT_IMPL_10ARGS(QGenericArgument))
121 QGenericArgument* args[10] = { &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10 };
122 for (int i = 0; i < 10; i++)
124 if (QByteArray(arg[i].name()) == "QxtBoundArgument")
126 p[i] = *args[(quintptr)(arg[i].data())-1];
129 return invokeImpl(type, returnValue, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
132 bool QxtBoundFunction::invoke(Qt::ConnectionType type, QGenericReturnArgument returnValue, QXT_IMPL_10ARGS(QGenericArgument))
134 return reinterpret_cast<QxtBoundFunctionBase*>(this)->invokeBase(type, returnValue, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
137 #ifndef QXT_DOXYGEN_RUN
138 class QxtBoundSlot : public QxtBoundFunctionBase
143 QxtBoundSlot(QObject* receiver, const char* invokable, QGenericArgument* params[10], QByteArray types[10]) : QxtBoundFunctionBase(receiver, params, types), sig(invokable)
148 virtual bool invokeImpl(Qt::ConnectionType type, QGenericReturnArgument returnValue, QXT_IMPL_10ARGS(QGenericArgument))
150 if (!QMetaObject::invokeMethod(parent(), QxtMetaObject::methodName(sig.constData()), type, returnValue, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10))
152 qWarning() << "QxtBoundFunction: call to" << sig << "failed";
160 namespace QxtMetaObject
164 \relates QxtMetaObject
166 \fn methodName(const char* method)
168 Returns the name of the given method.
172 QByteArray method = QxtMetaObject::methodName(" int foo ( int bar, double baz )");
173 // method is now "foo"
176 QByteArray methodName(const char* method)
178 QByteArray name = methodSignature(method);
179 const int idx = name.indexOf("(");
186 \relates QxtMetaObject
188 \fn methodSignature(const char* method)
190 Returns the signature of the given method.
192 QByteArray methodSignature(const char* method)
194 QByteArray name = QMetaObject::normalizedSignature(method);
195 if (name.startsWith("1") || name.startsWith("2"))
201 \relates QxtMetaObject
203 \fn bool isSignalOrSlot(const char* method)
205 checks if \p method contains parantesis and begins with 1 or 2 */
206 bool isSignalOrSlot (const char* method)
208 QByteArray m(method);
209 return (m.count() && (m[0] == '1'||m[0] == '2') && m.contains('(') && m.contains(')'));
213 * \relates QxtMetaObject
214 * \sa QxtMetaObject::connect
215 * \sa QxtBoundFunction
217 * Creates a binding to the provided signal, slot, or Q_INVOKABLE method using the
218 * provided parameter list. The type of each argument is deduced from the type of
219 * the QVariant. This function cannot bind positional arguments; see the
220 * overload using QGenericArgument.
222 * If the provided QObject does not implement the requested method, or if the
223 * argument list is incompatible with the method's function signature, this
224 * function returns NULL.
226 * The returned QxtBoundFunction is created as a child of the receiver.
227 * Changing the parent will result in undefined behavior.
229 QxtBoundFunction* bind(QObject* recv, const char* invokable, QXT_IMPL_10ARGS(QVariant))
233 qWarning() << "QxtMetaObject::bind: cannot connect to null QObject";
237 QVariant* args[10] = { &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10 };
238 QByteArray connSlot("2"), recvSlot(QMetaObject::normalizedSignature(invokable));
239 const QMetaObject* meta = recv->metaObject();
240 int methodID = meta->indexOfMethod(QxtMetaObject::methodSignature(recvSlot.constData()));
243 qWarning() << "QxtMetaObject::bind: no such method " << recvSlot;
246 QMetaMethod method = meta->method(methodID);
247 int argCount = method.parameterTypes().count();
248 const QList<QByteArray> paramTypes = method.parameterTypes();
250 for (int i=0; i<argCount; i++)
252 if (paramTypes[i] == "QxtBoundArgument") continue;
253 int type = QMetaType::type(paramTypes[i].constData());
254 if (!args[i]->canConvert((QVariant::Type)type))
256 qWarning() << "QxtMetaObject::bind: incompatible parameter list for " << recvSlot;
261 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));
265 * \relates QxtMetaObject
266 * \sa QxtMetaObject::connect
267 * \sa QxtBoundFunction
270 * Creates a binding to the provided signal, slot, or Q_INVOKABLE method using the
271 * provided parameter list. Use the Q_ARG macro to specify constant parameters, or
272 * use the QXT_BIND macro to relay a parameter from a connected signal or passed
273 * via the QxtBoundFunction::invoke() method.
275 * If the provided QObject does not implement the requested method, or if the
276 * argument list is incompatible with the method's function signature, this
277 * function returns NULL.
279 * The returned QxtBoundFunction is created as a child of the receiver.
280 * Changing the parent will result in undefined behavior.
282 QxtBoundFunction* bind(QObject* recv, const char* invokable, QXT_IMPL_10ARGS(QGenericArgument))
286 qWarning() << "QxtMetaObject::bind: cannot connect to null QObject";
290 QGenericArgument* args[10] = { &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10 };
291 QByteArray connSlot("2"), recvSlot(QMetaObject::normalizedSignature(invokable)), bindTypes[10];
292 const QMetaObject* meta = recv->metaObject();
293 int methodID = meta->indexOfMethod(QxtMetaObject::methodSignature(recvSlot.constData()).constData());
296 qWarning() << "QxtMetaObject::bind: no such method " << recvSlot;
299 QMetaMethod method = meta->method(methodID);
300 int argCount = method.parameterTypes().count();
302 connSlot += QxtMetaObject::methodName(invokable) + "(";
303 for (int i=0; i<10; i++)
305 if (args[i]->name() == 0) break; // done
308 qWarning() << "QxtMetaObject::bind: too many arguments passed to " << invokable;
311 if (i > 0) connSlot += ","; // argument separator
312 if (QByteArray(args[i]->name()) == "QxtBoundArgument")
314 Q_ASSERT_X((quintptr)(args[i]->data()) > 0 && (quintptr)(args[i]->data()) <= 10, "QXT_BIND", "invalid argument number");
315 connSlot += method.parameterTypes()[i];
316 bindTypes[i] = method.parameterTypes()[i];
320 connSlot += args[i]->name(); // type name
323 connSlot = QMetaObject::normalizedSignature(connSlot += ")");
325 if (!QMetaObject::checkConnectArgs(recvSlot.constData(), connSlot.constData()))
327 qWarning() << "QxtMetaObject::bind: provided parameters " << connSlot.mid(connSlot.indexOf('(')) << " is incompatible with " << invokable;
331 return new QxtBoundSlot(recv, invokable, args, bindTypes);
335 \relates QxtMetaObject
336 \fn connect(QObject* sender, const char* signal, QxtBoundFunction* slot, Qt::ConnectionType type) {
338 connects a signal to a QxtBoundFunction \n
340 bool connect(QObject* sender, const char* signal, QxtBoundFunction* slot, Qt::ConnectionType type)
342 const QMetaObject* meta = sender->metaObject();
343 int methodID = meta->indexOfMethod(meta->normalizedSignature(signal).mid(1).constData());
346 qWarning() << "QxtMetaObject::connect: no such signal: " << QByteArray(signal).mid(1);
350 return QMetaObject::connect(sender, methodID, slot, QObject::staticMetaObject.methodCount(), (int)(type));