PageRenderTime 146ms CodeModel.GetById 50ms app.highlight 78ms RepoModel.GetById 13ms app.codeStats 0ms

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