Unify the code used to do QObject meta calls.
This commit is contained in:
parent
15ceed791f
commit
67d6455fa5
3 changed files with 97 additions and 110 deletions
|
|
@ -21,6 +21,7 @@
|
||||||
*/
|
*/
|
||||||
#include <sbkpython.h>
|
#include <sbkpython.h>
|
||||||
#include "pysidemetafunction.h"
|
#include "pysidemetafunction.h"
|
||||||
|
#include "pysidemetafunction_p.h"
|
||||||
|
|
||||||
#include <shiboken.h>
|
#include <shiboken.h>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
@ -98,67 +99,10 @@ void functionFree(void *self)
|
||||||
PyObject* functionCall(PyObject* self, PyObject* args, PyObject* kw)
|
PyObject* functionCall(PyObject* self, PyObject* args, PyObject* kw)
|
||||||
{
|
{
|
||||||
PySideMetaFunction* function = reinterpret_cast<PySideMetaFunction*>(self);
|
PySideMetaFunction* function = reinterpret_cast<PySideMetaFunction*>(self);
|
||||||
QMetaMethod method = function->d->method;
|
|
||||||
QList<QByteArray> argTypes = method.parameterTypes();
|
|
||||||
|
|
||||||
// args given plus return type
|
PyObject* retVal;
|
||||||
int numArgs = PyTuple_GET_SIZE(args) + 1;
|
if (!PySide::MetaFunction::call(function->d->qobject, function->d->method.methodIndex(), args, &retVal))
|
||||||
|
|
||||||
if (numArgs - 1 != argTypes.count()) {
|
|
||||||
PyErr_Format(PyExc_TypeError, "%s only accepts %d arguments, %d given!", method.signature(), argTypes.count(), numArgs);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
QVariant* methValues = new QVariant[numArgs];
|
|
||||||
void** methArgs = new void*[numArgs];
|
|
||||||
|
|
||||||
// Prepare room for return type
|
|
||||||
const char* returnType = method.typeName();
|
|
||||||
if (returnType)
|
|
||||||
argTypes.prepend(returnType);
|
|
||||||
else
|
|
||||||
argTypes.prepend(QByteArray());
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < numArgs; ++i) {
|
|
||||||
const QByteArray& typeName = argTypes[i];
|
|
||||||
// This must happen only when the method hasn't return type.
|
|
||||||
if (typeName.isEmpty()) {
|
|
||||||
methArgs[i] = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Shiboken::TypeResolver* typeResolver = Shiboken::TypeResolver::get(typeName);
|
|
||||||
if (typeResolver) {
|
|
||||||
if (Shiboken::TypeResolver::getType(typeName) == Shiboken::TypeResolver::ValueType) {
|
|
||||||
int typeId = QMetaType::type(typeName);
|
|
||||||
if (!typeId) {
|
|
||||||
PyErr_Format(PyExc_TypeError, "Value type used on signal needs to be registered on meta type: %s", typeName.data());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
methValues[i] = QVariant(typeId, (void*) 0);
|
|
||||||
}
|
|
||||||
methArgs[i] = methValues[i].data();
|
|
||||||
if (i != 0) // Don't do this for return type
|
|
||||||
typeResolver->toCpp(PyTuple_GET_ITEM(args, i - 1), &methArgs[i]);
|
|
||||||
} else {
|
|
||||||
PyErr_Format(PyExc_TypeError, "Unknown type used to emit a signal: %s", argTypes[i].constData());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok = i == numArgs;
|
|
||||||
if (ok)
|
|
||||||
QMetaObject::metacall(function->d->qobject, QMetaObject::InvokeMetaMethod, method.methodIndex(), methArgs);
|
|
||||||
|
|
||||||
static Shiboken::TypeResolver* qVariantTypeResolver = Shiboken::TypeResolver::get("QVariant");
|
|
||||||
Q_ASSERT(qVariantTypeResolver);
|
|
||||||
|
|
||||||
PyObject* retVal = qVariantTypeResolver->toPython(&methValues[0]);
|
|
||||||
|
|
||||||
delete[] methArgs;
|
|
||||||
delete[] methValues;
|
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,6 +135,84 @@ PySideMetaFunction* newObject(QObject* source, int methodIndex)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool call(QObject* self, int methodIndex, PyObject* args, PyObject** retVal)
|
||||||
|
{
|
||||||
|
|
||||||
|
QMetaMethod method = self->metaObject()->method(methodIndex);
|
||||||
|
QList<QByteArray> argTypes = method.parameterTypes();
|
||||||
|
|
||||||
|
// args given plus return type
|
||||||
|
Shiboken::AutoDecRef sequence(PySequence_Fast(args, 0));
|
||||||
|
int numArgs = PySequence_Fast_GET_SIZE(sequence.object()) + 1;
|
||||||
|
|
||||||
|
if (numArgs - 1 != argTypes.count()) {
|
||||||
|
PyErr_Format(PyExc_TypeError, "%s only accepts %d arguments, %d given!", method.signature(), argTypes.count(), numArgs);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant* methValues = new QVariant[numArgs];
|
||||||
|
void** methArgs = new void*[numArgs];
|
||||||
|
|
||||||
|
// Prepare room for return type
|
||||||
|
const char* returnType = method.typeName();
|
||||||
|
if (returnType)
|
||||||
|
argTypes.prepend(returnType);
|
||||||
|
else
|
||||||
|
argTypes.prepend(QByteArray());
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < numArgs; ++i) {
|
||||||
|
const QByteArray& typeName = argTypes[i];
|
||||||
|
// This must happen only when the method hasn't return type.
|
||||||
|
if (typeName.isEmpty()) {
|
||||||
|
methArgs[i] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shiboken::TypeResolver* typeResolver = Shiboken::TypeResolver::get(typeName);
|
||||||
|
if (typeResolver) {
|
||||||
|
if (Shiboken::TypeResolver::getType(typeName) == Shiboken::TypeResolver::ValueType) {
|
||||||
|
int typeId = QMetaType::type(typeName);
|
||||||
|
if (!typeId) {
|
||||||
|
PyErr_Format(PyExc_TypeError, "Value types used on meta functions (including signals) need to be "
|
||||||
|
"registered on meta type: %s", typeName.data());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
methValues[i] = QVariant(typeId, (void*) 0);
|
||||||
|
}
|
||||||
|
methArgs[i] = methValues[i].data();
|
||||||
|
if (i != 0) // Don't do this for return type
|
||||||
|
typeResolver->toCpp(PySequence_Fast_GET_ITEM(sequence.object(), i - 1), &methArgs[i]);
|
||||||
|
} else {
|
||||||
|
PyErr_Format(PyExc_TypeError, "Unknown type used to call meta function (that may be a signal): %s", argTypes[i].constData());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = i == numArgs;
|
||||||
|
if (ok) {
|
||||||
|
QMetaObject::metacall(self, QMetaObject::InvokeMetaMethod, method.methodIndex(), methArgs);
|
||||||
|
|
||||||
|
if (retVal) {
|
||||||
|
if (methArgs[0]) {
|
||||||
|
static Shiboken::TypeResolver* qVariantTypeResolver = Shiboken::TypeResolver::get("QVariant");
|
||||||
|
Q_ASSERT(qVariantTypeResolver);
|
||||||
|
|
||||||
|
*retVal = qVariantTypeResolver->toPython(&methValues[0]);
|
||||||
|
} else {
|
||||||
|
*retVal = Py_None;
|
||||||
|
Py_INCREF(*retVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] methArgs;
|
||||||
|
delete[] methValues;
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} //namespace MetaFunction
|
} //namespace MetaFunction
|
||||||
} //namespace PySide
|
} //namespace PySide
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,18 @@
|
||||||
#define PYSIDE_METAFUNCTION_P_H
|
#define PYSIDE_METAFUNCTION_P_H
|
||||||
|
|
||||||
#include <sbkpython.h>
|
#include <sbkpython.h>
|
||||||
|
#include <QList>
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
|
class QObject;
|
||||||
|
|
||||||
namespace PySide { namespace MetaFunction {
|
namespace PySide { namespace MetaFunction {
|
||||||
|
|
||||||
void init(PyObject* module);
|
void init(PyObject* module);
|
||||||
|
/**
|
||||||
|
* Does a Qt metacall on a QObject
|
||||||
|
*/
|
||||||
|
bool call(QObject* self, int methodIndex, PyObject* args, PyObject** retVal = 0);
|
||||||
|
|
||||||
} //namespace MetaFunction
|
} //namespace MetaFunction
|
||||||
} //namespace PySide
|
} //namespace PySide
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "pysideproperty_p.h"
|
#include "pysideproperty_p.h"
|
||||||
#include "pyside.h"
|
#include "pyside.h"
|
||||||
#include "dynamicqmetaobject.h"
|
#include "dynamicqmetaobject.h"
|
||||||
|
#include "pysidemetafunction_p.h"
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
@ -34,6 +35,7 @@
|
||||||
#include <gilstate.h>
|
#include <gilstate.h>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <algorithm>
|
||||||
#include <typeresolver.h>
|
#include <typeresolver.h>
|
||||||
#include <basewrapper.h>
|
#include <basewrapper.h>
|
||||||
#include <conversions.h>
|
#include <conversions.h>
|
||||||
|
|
@ -54,7 +56,6 @@ namespace {
|
||||||
static int callMethod(QObject* object, int id, void** args);
|
static int callMethod(QObject* object, int id, void** args);
|
||||||
static PyObject* parseArguments(QList<QByteArray> paramTypese, void** args);
|
static PyObject* parseArguments(QList<QByteArray> paramTypese, void** args);
|
||||||
static bool emitShortCircuitSignal(QObject* source, int signalIndex, PyObject* args);
|
static bool emitShortCircuitSignal(QObject* source, int signalIndex, PyObject* args);
|
||||||
static bool emitNormalSignal(QObject* source, int signalIndex, const char* signal, PyObject* args, const QStringList& argTypes);
|
|
||||||
|
|
||||||
#ifdef IS_PY3K
|
#ifdef IS_PY3K
|
||||||
static void destroyMetaObject(PyObject* obj)
|
static void destroyMetaObject(PyObject* obj)
|
||||||
|
|
@ -338,13 +339,14 @@ bool SignalManager::emitSignal(QObject* source, const char* signal, PyObject* ar
|
||||||
|
|
||||||
int signalIndex = source->metaObject()->indexOfSignal(signal);
|
int signalIndex = source->metaObject()->indexOfSignal(signal);
|
||||||
if (signalIndex != -1) {
|
if (signalIndex != -1) {
|
||||||
bool isShortCircuit;
|
// cryptic but works!
|
||||||
QStringList argTypes = Signal::getArgsFromSignature(signal, &isShortCircuit);
|
// if the signature doesn't have a '(' it's a shor circuited signal, i.e. std::find
|
||||||
|
// returned the string null terminator.
|
||||||
|
bool isShortCircuit = !*std::find(signal, signal + std::strlen(signal), '(');
|
||||||
if (isShortCircuit)
|
if (isShortCircuit)
|
||||||
return emitShortCircuitSignal(source, signalIndex, args);
|
return emitShortCircuitSignal(source, signalIndex, args);
|
||||||
else
|
else
|
||||||
return emitNormalSignal(source, signalIndex, signal, args, argTypes);
|
return MetaFunction::call(source, signalIndex, args);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -572,49 +574,4 @@ static bool emitShortCircuitSignal(QObject* source, int signalIndex, PyObject* a
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool emitNormalSignal(QObject* source, int signalIndex, const char* signal, PyObject* args, const QStringList& argTypes)
|
|
||||||
{
|
|
||||||
Shiboken::AutoDecRef sequence(PySequence_Fast(args, 0));
|
|
||||||
int argsGiven = PySequence_Fast_GET_SIZE(sequence.object());
|
|
||||||
|
|
||||||
if (argsGiven != argTypes.count()) {
|
|
||||||
PyErr_Format(PyExc_TypeError, "%s only accepts %d arguments, %d given!", signal, argTypes.count(), argsGiven);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant* signalValues = new QVariant[argsGiven];
|
|
||||||
void** signalArgs = new void*[argsGiven + 1];
|
|
||||||
signalArgs[0] = 0;
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < argsGiven; ++i) {
|
|
||||||
QByteArray typeName = argTypes[i].toAscii();
|
|
||||||
Shiboken::TypeResolver* typeResolver = Shiboken::TypeResolver::get(typeName);
|
|
||||||
if (typeResolver) {
|
|
||||||
if (Shiboken::TypeResolver::getType(typeName) == Shiboken::TypeResolver::ValueType) {
|
|
||||||
int typeId = QMetaType::type(typeName);
|
|
||||||
if (!typeId) {
|
|
||||||
PyErr_Format(PyExc_TypeError, "Value type used on signal needs to be registered on meta type: %s", typeName.data());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
signalValues[i] = QVariant(typeId, (void*) 0);
|
|
||||||
}
|
|
||||||
signalArgs[i+1] = signalValues[i].data();
|
|
||||||
typeResolver->toCpp(PySequence_Fast_GET_ITEM(sequence.object(), i), &signalArgs[i+1]);
|
|
||||||
} else {
|
|
||||||
PyErr_Format(PyExc_TypeError, "Unknown type used to emit a signal: %s", qPrintable(argTypes[i]));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok = i == argsGiven;
|
|
||||||
if (ok)
|
|
||||||
source->qt_metacall(QMetaObject::InvokeMetaMethod, signalIndex, signalArgs);
|
|
||||||
|
|
||||||
delete[] signalArgs;
|
|
||||||
delete[] signalValues;
|
|
||||||
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
} //namespace
|
} //namespace
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue