Set the object meta object at the declaration time, not instanciation time.
This commit is contained in:
parent
a29f511f6d
commit
8fb6037362
4 changed files with 96 additions and 62 deletions
|
|
@ -386,64 +386,6 @@ void DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data)
|
||||||
m_d->updateMetaObject(this);
|
m_d->updateMetaObject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DynamicQMetaObject* DynamicQMetaObject::createBasedOn(PyObject* pyObj, PyTypeObject* type, const QMetaObject* base)
|
|
||||||
{
|
|
||||||
PyObject* key;
|
|
||||||
PyObject* value;
|
|
||||||
Py_ssize_t pos = 0;
|
|
||||||
|
|
||||||
QString className(type->tp_name);
|
|
||||||
className = className.mid(className.lastIndexOf('.')+1);
|
|
||||||
DynamicQMetaObject *mo = new PySide::DynamicQMetaObject(className.toAscii(), base);
|
|
||||||
|
|
||||||
QList<PyObject*> properties;
|
|
||||||
|
|
||||||
while (PyDict_Next(type->tp_dict, &pos, &key, &value)) {
|
|
||||||
|
|
||||||
//Leave the properties to be register after signals because of notify object
|
|
||||||
if (value->ob_type == &PySidePropertyType)
|
|
||||||
properties.append(key);
|
|
||||||
|
|
||||||
//Register signals
|
|
||||||
if (value->ob_type == &PySideSignalType) {
|
|
||||||
PyObject *attr = PyObject_GetAttr(pyObj, key);
|
|
||||||
PySideSignalInstance *data = reinterpret_cast<PySideSignalInstance*>(attr);
|
|
||||||
while(data) {
|
|
||||||
int index = base->indexOfSignal(data->d->signature);
|
|
||||||
if (index == -1)
|
|
||||||
mo->addSignal(data->d->signature);
|
|
||||||
data = reinterpret_cast<PySideSignalInstance*>(data->d->next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PyFunction_Check(value))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//Register Slots
|
|
||||||
if (PyObject_HasAttrString(value, PYSIDE_SLOT_LIST_ATTR)) {
|
|
||||||
PyObject *signature_list = PyObject_GetAttrString(value, PYSIDE_SLOT_LIST_ATTR);
|
|
||||||
for(Py_ssize_t i = 0, i_max = PyList_Size(signature_list); i < i_max; i++) {
|
|
||||||
PyObject *signature = PyList_GET_ITEM(signature_list, i);
|
|
||||||
QString sig(PyString_AsString(signature));
|
|
||||||
//slot the slot type and signature
|
|
||||||
QStringList slotInfo = sig.split(" ", QString::SkipEmptyParts);
|
|
||||||
int index = base->indexOfSlot(qPrintable(slotInfo[1]));
|
|
||||||
if (index == -1)
|
|
||||||
mo->addSlot(slotInfo[1].toAscii(), slotInfo[0].toAscii());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Register properties
|
|
||||||
foreach(PyObject* key, properties) {
|
|
||||||
PyObject* value = PyDict_GetItem(type->tp_dict, key);
|
|
||||||
mo->addProperty(PyString_AsString(key), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DynamicQMetaObject::removeSignal(uint index)
|
void DynamicQMetaObject::removeSignal(uint index)
|
||||||
{
|
{
|
||||||
//Current Qt implementation does not support runtime remove signal
|
//Current Qt implementation does not support runtime remove signal
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
namespace PySide
|
namespace PySide
|
||||||
{
|
{
|
||||||
|
|
||||||
class PYSIDE_API DynamicQMetaObject : public QMetaObject
|
class DynamicQMetaObject : public QMetaObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DynamicQMetaObject(const char* className, const QMetaObject* metaObject);
|
DynamicQMetaObject(const char* className, const QMetaObject* metaObject);
|
||||||
|
|
@ -44,9 +44,6 @@ public:
|
||||||
void removeSlot(uint index);
|
void removeSlot(uint index);
|
||||||
void removeProperty(uint index);
|
void removeProperty(uint index);
|
||||||
|
|
||||||
//Retrieve Python metadata to create QMetaObject (class name, signals, slot)
|
|
||||||
static DynamicQMetaObject* createBasedOn(PyObject* obj, PyTypeObject* type, const QMetaObject* base);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class DynamicQMetaObjectPrivate;
|
class DynamicQMetaObjectPrivate;
|
||||||
DynamicQMetaObjectPrivate* m_d;
|
DynamicQMetaObjectPrivate* m_d;
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
#include "pysidesignal_p.h"
|
#include "pysidesignal_p.h"
|
||||||
#include "pysideslot_p.h"
|
#include "pysideslot_p.h"
|
||||||
#include "pysidemetafunction_p.h"
|
#include "pysidemetafunction_p.h"
|
||||||
|
#include "dynamicqmetaobject.h"
|
||||||
|
|
||||||
#include <basewrapper.h>
|
#include <basewrapper.h>
|
||||||
#include <conversions.h>
|
#include <conversions.h>
|
||||||
|
|
@ -134,5 +135,95 @@ void destroyQCoreApplication()
|
||||||
delete app;
|
delete app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base)
|
||||||
|
{
|
||||||
|
const char* typeName = type->super.ht_type.tp_name;
|
||||||
|
int len = strlen(typeName);
|
||||||
|
for (int i = len-1; i >= 0; --i)
|
||||||
|
if (typeName[i] == '.')
|
||||||
|
typeName += i + 1;
|
||||||
|
DynamicQMetaObject* mo = new PySide::DynamicQMetaObject(typeName, base);
|
||||||
|
Shiboken::ObjectType::setTypeUserData(type, mo, &Shiboken::callCppDestructor<DynamicQMetaObject>);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initQObjectSubType(SbkObjectType* type, PyObject* args, PyObject* kwds)
|
||||||
|
{
|
||||||
|
PyTypeObject* qObjType = Shiboken::TypeResolver::get("QObject*")->pythonType();
|
||||||
|
QByteArray className(PyString_AS_STRING(PyTuple_GET_ITEM(args, 0)));
|
||||||
|
|
||||||
|
PyObject* bases = PyTuple_GET_ITEM(args, 1);
|
||||||
|
int numBases = PyTuple_GET_SIZE(args);
|
||||||
|
QMetaObject* baseMo = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < numBases; ++i) {
|
||||||
|
PyTypeObject* base = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(bases, i));
|
||||||
|
if (PyType_IsSubtype(base, qObjType)) {
|
||||||
|
baseMo = reinterpret_cast<QMetaObject*>(Shiboken::ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(base)));
|
||||||
|
// If it's a class like QObject, QWidget, etc, use the original QMetaObject instead of the dynamic one
|
||||||
|
// IMO this if is a bug, however it keeps the current behaviour.
|
||||||
|
if (!Shiboken::ObjectType::isUserType(base))
|
||||||
|
baseMo = const_cast<QMetaObject*>(baseMo->d.superdata);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!baseMo) {
|
||||||
|
qWarning("Sub class of QObject not inheriting QObject!? Crash will happen when using %s.", className.constData());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicQMetaObject* mo = new PySide::DynamicQMetaObject(className.constData(), baseMo);
|
||||||
|
|
||||||
|
Shiboken::ObjectType::setTypeUserData(type, mo, &Shiboken::callCppDestructor<DynamicQMetaObject>);
|
||||||
|
|
||||||
|
PyObject* attrs = PyTuple_GET_ITEM(args, 2);
|
||||||
|
PyObject* key;
|
||||||
|
PyObject* value;
|
||||||
|
Py_ssize_t pos = 0;
|
||||||
|
|
||||||
|
typedef std::pair<const char*, PyObject*> PropPair;
|
||||||
|
QList<PropPair> properties;
|
||||||
|
|
||||||
|
Shiboken::AutoDecRef slotAttrName(PyString_FromString(PYSIDE_SLOT_LIST_ATTR));
|
||||||
|
|
||||||
|
while (PyDict_Next(attrs, &pos, &key, &value)) {
|
||||||
|
if (value->ob_type == &PySidePropertyType) {
|
||||||
|
// Leave the properties to be register after signals because they may depend on notify signals
|
||||||
|
properties << PropPair(PyString_AS_STRING(key), value);
|
||||||
|
} else if (value->ob_type == &PySideSignalType) { // Register signals
|
||||||
|
PySideSignal* data = reinterpret_cast<PySideSignal*>(value);
|
||||||
|
const char* signalName = PyString_AS_STRING(key);
|
||||||
|
data->signalName = strdup(signalName);
|
||||||
|
QByteArray sig;
|
||||||
|
sig.reserve(128);
|
||||||
|
for (int i = 0; i < data->signaturesSize; ++i) {
|
||||||
|
sig = signalName;
|
||||||
|
sig += '(';
|
||||||
|
if (data->signatures[i])
|
||||||
|
sig += data->signatures[i];
|
||||||
|
sig += ')';
|
||||||
|
if (baseMo->indexOfSignal(sig) == -1)
|
||||||
|
mo->addSignal(sig);
|
||||||
|
}
|
||||||
|
} else if (PyFunction_Check(value)) { // Register slots
|
||||||
|
if (PyObject_HasAttr(value, slotAttrName)) {
|
||||||
|
PyObject* signatureList = PyObject_GetAttr(value, slotAttrName);
|
||||||
|
for(Py_ssize_t i = 0, i_max = PyList_Size(signatureList); i < i_max; ++i) {
|
||||||
|
PyObject* signature = PyList_GET_ITEM(signatureList, i);
|
||||||
|
QByteArray sig(PyString_AS_STRING(signature));
|
||||||
|
//slot the slot type and signature
|
||||||
|
QList<QByteArray> slotInfo = sig.split(' ');
|
||||||
|
int index = baseMo->indexOfSlot(slotInfo[1]);
|
||||||
|
if (index == -1)
|
||||||
|
mo->addSlot(slotInfo[1], slotInfo[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register properties
|
||||||
|
foreach (PropPair propPair, properties)
|
||||||
|
mo->addProperty(propPair.first, propPair.second);
|
||||||
|
}
|
||||||
|
|
||||||
} //namespace PySide
|
} //namespace PySide
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
|
||||||
|
class SbkObjectType;
|
||||||
|
|
||||||
namespace PySide
|
namespace PySide
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -75,6 +77,8 @@ template<typename T>
|
||||||
struct initQtMetaType<T, false> {
|
struct initQtMetaType<T, false> {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PYSIDE_API void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base);
|
||||||
|
PYSIDE_API void initQObjectSubType(SbkObjectType* type, PyObject* args, PyObject* kwds);
|
||||||
|
|
||||||
typedef void (*CleanupFunction)(void);
|
typedef void (*CleanupFunction)(void);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue