Fix bug 926 - "qmlRegisterType does not work with QObject"
Reviewer: Luciano Wolf <luciano.wolf@openbossa.org>
Lauro Neto <lauro.neto@openbossa.org>
This commit is contained in:
parent
b6e0977d86
commit
0a41e336ba
7 changed files with 119 additions and 32 deletions
|
|
@ -52,9 +52,7 @@ static void propListMetaCall(PySideProperty* pp, PyObject* self, QMetaObject::Ca
|
||||||
static PyObject* pyTypes[PYSIDE_MAX_QML_TYPES];
|
static PyObject* pyTypes[PYSIDE_MAX_QML_TYPES];
|
||||||
static void (*createFuncs[PYSIDE_MAX_QML_TYPES])(void*);
|
static void (*createFuncs[PYSIDE_MAX_QML_TYPES])(void*);
|
||||||
|
|
||||||
/// QDeclarativeItem will create objects using placement new then this pointer is non-null.
|
// Mutex used to avoid race condition on PySide::nextQObjectMemoryAddr
|
||||||
void* PySide::nextQmlElementMemoryAddr = 0;
|
|
||||||
// Mutex used to avoid race condition on PySide::nextQmlElementMemoryAddr
|
|
||||||
static QMutex nextQmlElementMutex;
|
static QMutex nextQmlElementMutex;
|
||||||
|
|
||||||
template<int N>
|
template<int N>
|
||||||
|
|
@ -63,12 +61,12 @@ struct ElementFactoryBase
|
||||||
static void createInto(void* memory)
|
static void createInto(void* memory)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&nextQmlElementMutex);
|
QMutexLocker locker(&nextQmlElementMutex);
|
||||||
PySide::nextQmlElementMemoryAddr = memory;
|
PySide::setNextQObjectMemoryAddr(memory);
|
||||||
Shiboken::GilState state;
|
Shiboken::GilState state;
|
||||||
PyObject* obj = PyObject_CallObject(pyTypes[N], 0);
|
PyObject* obj = PyObject_CallObject(pyTypes[N], 0);
|
||||||
if (!obj || PyErr_Occurred())
|
if (!obj || PyErr_Occurred())
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
PySide::nextQmlElementMemoryAddr = 0;
|
PySide::setNextQObjectMemoryAddr(0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -95,8 +93,8 @@ int PySide::qmlRegisterType(PyObject* pyObj, const char* uri, int versionMajor,
|
||||||
{
|
{
|
||||||
using namespace Shiboken;
|
using namespace Shiboken;
|
||||||
|
|
||||||
static PyTypeObject* declarativeItemType = TypeResolver::get("QDeclarativeItem*")->pythonType();
|
static PyTypeObject* qobjectType = TypeResolver::get("QObject*")->pythonType();
|
||||||
assert(declarativeItemType);
|
assert(qobjectType);
|
||||||
static int nextType = 0;
|
static int nextType = 0;
|
||||||
|
|
||||||
if (nextType >= PYSIDE_MAX_QML_TYPES) {
|
if (nextType >= PYSIDE_MAX_QML_TYPES) {
|
||||||
|
|
@ -104,8 +102,8 @@ int PySide::qmlRegisterType(PyObject* pyObj, const char* uri, int versionMajor,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PySequence_Contains(((PyTypeObject*)pyObj)->tp_mro, (PyObject*)declarativeItemType)) {
|
if (!PySequence_Contains(((PyTypeObject*)pyObj)->tp_mro, (PyObject*)qobjectType)) {
|
||||||
PyErr_Format(PyExc_TypeError, "A type inherited from %s expected, got %s.", declarativeItemType->tp_name, ((PyTypeObject*)pyObj)->tp_name);
|
PyErr_Format(PyExc_TypeError, "A type inherited from %s expected, got %s.", qobjectType->tp_name, ((PyTypeObject*)pyObj)->tp_name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,9 +116,9 @@ int PySide::qmlRegisterType(PyObject* pyObj, const char* uri, int versionMajor,
|
||||||
// Init proxy object static meta object
|
// Init proxy object static meta object
|
||||||
QDeclarativePrivate::RegisterType type;
|
QDeclarativePrivate::RegisterType type;
|
||||||
type.version = 0;
|
type.version = 0;
|
||||||
type.typeId = qMetaTypeId<QDeclarativeItem*>();
|
type.typeId = qMetaTypeId<QObject*>();
|
||||||
type.listId = qMetaTypeId<QDeclarativeListProperty<QDeclarativeItem> >();
|
type.listId = qMetaTypeId<QDeclarativeListProperty<QObject> >();
|
||||||
type.objectSize = sizeof(QDeclarativeItemWrapper);
|
type.objectSize = PySide::getSizeOfQObject(reinterpret_cast<SbkObjectType*>(pyObj));
|
||||||
type.create = createFuncs[nextType];
|
type.create = createFuncs[nextType];
|
||||||
type.uri = uri;
|
type.uri = uri;
|
||||||
type.versionMajor = versionMajor;
|
type.versionMajor = versionMajor;
|
||||||
|
|
@ -128,12 +126,12 @@ int PySide::qmlRegisterType(PyObject* pyObj, const char* uri, int versionMajor,
|
||||||
type.elementName = qmlName;
|
type.elementName = qmlName;
|
||||||
type.metaObject = metaObject;
|
type.metaObject = metaObject;
|
||||||
|
|
||||||
type.attachedPropertiesFunction = QDeclarativePrivate::attachedPropertiesFunc<QDeclarativeItem>();
|
type.attachedPropertiesFunction = QDeclarativePrivate::attachedPropertiesFunc<QObject>();
|
||||||
type.attachedPropertiesMetaObject = QDeclarativePrivate::attachedPropertiesMetaObject<QDeclarativeItem>();
|
type.attachedPropertiesMetaObject = QDeclarativePrivate::attachedPropertiesMetaObject<QObject>();
|
||||||
|
|
||||||
type.parserStatusCast = QDeclarativePrivate::StaticCastSelector<QDeclarativeItem,QDeclarativeParserStatus>::cast();
|
type.parserStatusCast = QDeclarativePrivate::StaticCastSelector<QObject, QDeclarativeParserStatus>::cast();
|
||||||
type.valueSourceCast = QDeclarativePrivate::StaticCastSelector<QDeclarativeItem,QDeclarativePropertyValueSource>::cast();
|
type.valueSourceCast = QDeclarativePrivate::StaticCastSelector<QObject, QDeclarativePropertyValueSource>::cast();
|
||||||
type.valueInterceptorCast = QDeclarativePrivate::StaticCastSelector<QDeclarativeItem,QDeclarativePropertyValueInterceptor>::cast();
|
type.valueInterceptorCast = QDeclarativePrivate::StaticCastSelector<QObject, QDeclarativePropertyValueInterceptor>::cast();
|
||||||
|
|
||||||
type.extensionObjectCreate = 0;
|
type.extensionObjectCreate = 0;
|
||||||
type.extensionMetaObject = 0;
|
type.extensionMetaObject = 0;
|
||||||
|
|
|
||||||
|
|
@ -103,14 +103,6 @@
|
||||||
<include file-name="pysideqmlregistertype.h" location="local"/>
|
<include file-name="pysideqmlregistertype.h" location="local"/>
|
||||||
</extra-includes>
|
</extra-includes>
|
||||||
<enum-type name="TransformOrigin" />
|
<enum-type name="TransformOrigin" />
|
||||||
<modify-function signature="QDeclarativeItem(QDeclarativeItem*)">
|
|
||||||
<inject-code class="target">
|
|
||||||
if (PySide::nextQmlElementMemoryAddr)
|
|
||||||
%0 = new (PySide::nextQmlElementMemoryAddr) ::QDeclarativePrivate::QDeclarativeElement<%TYPE>();
|
|
||||||
else
|
|
||||||
%0 = new %TYPE(%1);
|
|
||||||
</inject-code>
|
|
||||||
</modify-function>
|
|
||||||
</object-type>
|
</object-type>
|
||||||
|
|
||||||
<value-type name="QDeclarativeListReference" />
|
<value-type name="QDeclarativeListReference" />
|
||||||
|
|
|
||||||
|
|
@ -44,12 +44,14 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
static QStack<PySide::CleanupFunction> cleanupFunctionList;
|
static QStack<PySide::CleanupFunction> cleanupFunctionList;
|
||||||
|
static void* qobjectNextAddr;
|
||||||
|
|
||||||
namespace PySide
|
namespace PySide
|
||||||
{
|
{
|
||||||
|
|
||||||
void init(PyObject *module)
|
void init(PyObject *module)
|
||||||
{
|
{
|
||||||
|
qobjectNextAddr = 0;
|
||||||
ClassInfo::init(module);
|
ClassInfo::init(module);
|
||||||
Signal::init(module);
|
Signal::init(module);
|
||||||
Slot::init(module);
|
Slot::init(module);
|
||||||
|
|
@ -148,17 +150,35 @@ void destroyQCoreApplication()
|
||||||
delete app;
|
delete app;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base)
|
struct TypeUserData {
|
||||||
|
TypeUserData(PyTypeObject* type, const QMetaObject* metaobject) : mo(type, metaobject) {}
|
||||||
|
DynamicQMetaObject mo;
|
||||||
|
std::size_t cppObjSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t getSizeOfQObject(SbkObjectType* type)
|
||||||
|
{
|
||||||
|
using namespace Shiboken::ObjectType;
|
||||||
|
TypeUserData* userData = reinterpret_cast<TypeUserData*>(getTypeUserData(reinterpret_cast<SbkObjectType*>(type)));
|
||||||
|
return userData->cppObjSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, const std::size_t& cppObjSize)
|
||||||
{
|
{
|
||||||
//create DynamicMetaObject based on python type
|
//create DynamicMetaObject based on python type
|
||||||
DynamicQMetaObject* mo = new PySide::DynamicQMetaObject(reinterpret_cast<PyTypeObject*>(type), base);
|
TypeUserData* userData = new TypeUserData(reinterpret_cast<PyTypeObject*>(type), base);
|
||||||
Shiboken::ObjectType::setTypeUserData(type, mo, Shiboken::callCppDestructor<DynamicQMetaObject>);
|
userData->cppObjSize = cppObjSize;
|
||||||
|
Shiboken::ObjectType::setTypeUserData(type, userData, Shiboken::callCppDestructor<TypeUserData>);
|
||||||
|
|
||||||
//initialize staticQMetaObject property
|
//initialize staticQMetaObject property
|
||||||
PyObject* pyMetaObject = Shiboken::TypeResolver::get("QMetaObject*")->toPython(&mo);
|
void* metaObjectPtr = &userData->mo;
|
||||||
|
Shiboken::AutoDecRef pyMetaObject(Shiboken::TypeResolver::get("QMetaObject*")->toPython(&metaObjectPtr));
|
||||||
PyObject_SetAttrString(reinterpret_cast<PyObject*>(type), "staticMetaObject", pyMetaObject);
|
PyObject_SetAttrString(reinterpret_cast<PyObject*>(type), "staticMetaObject", pyMetaObject);
|
||||||
Py_DECREF(pyMetaObject);
|
}
|
||||||
|
|
||||||
|
void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base)
|
||||||
|
{
|
||||||
|
initDynamicMetaObject(type, base, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initQObjectSubType(SbkObjectType* type, PyObject* args, PyObject* kwds)
|
void initQObjectSubType(SbkObjectType* type, PyObject* args, PyObject* kwds)
|
||||||
|
|
@ -169,11 +189,13 @@ void initQObjectSubType(SbkObjectType* type, PyObject* args, PyObject* kwds)
|
||||||
PyObject* bases = PyTuple_GET_ITEM(args, 1);
|
PyObject* bases = PyTuple_GET_ITEM(args, 1);
|
||||||
int numBases = PyTuple_GET_SIZE(bases);
|
int numBases = PyTuple_GET_SIZE(bases);
|
||||||
QMetaObject* baseMo = 0;
|
QMetaObject* baseMo = 0;
|
||||||
|
SbkObjectType* qobjBase = 0;
|
||||||
|
|
||||||
for (int i = 0; i < numBases; ++i) {
|
for (int i = 0; i < numBases; ++i) {
|
||||||
PyTypeObject* base = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(bases, i));
|
PyTypeObject* base = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(bases, i));
|
||||||
if (PyType_IsSubtype(base, qObjType)) {
|
if (PyType_IsSubtype(base, qObjType)) {
|
||||||
baseMo = reinterpret_cast<QMetaObject*>(Shiboken::ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(base)));
|
baseMo = reinterpret_cast<QMetaObject*>(Shiboken::ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(base)));
|
||||||
|
qobjBase = reinterpret_cast<SbkObjectType*>(base);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -182,7 +204,8 @@ void initQObjectSubType(SbkObjectType* type, PyObject* args, PyObject* kwds)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
initDynamicMetaObject(type, baseMo);
|
TypeUserData* userData = reinterpret_cast<TypeUserData*>(Shiboken::ObjectType::getTypeUserData(qobjBase));
|
||||||
|
initDynamicMetaObject(type, baseMo, userData->cppObjSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* name)
|
PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* name)
|
||||||
|
|
@ -249,5 +272,15 @@ bool inherits(PyTypeObject* objType, const char* class_name)
|
||||||
return inherits(base, class_name);
|
return inherits(base, class_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* nextQObjectMemoryAddr()
|
||||||
|
{
|
||||||
|
return qobjectNextAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNextQObjectMemoryAddr(void* addr)
|
||||||
|
{
|
||||||
|
qobjectNextAddr = addr;
|
||||||
|
}
|
||||||
|
|
||||||
} //namespace PySide
|
} //namespace PySide
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,14 @@ template<typename T>
|
||||||
struct initQtMetaType<T, false> {
|
struct initQtMetaType<T, false> {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \deprecated
|
||||||
PYSIDE_API void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base);
|
PYSIDE_API void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base);
|
||||||
|
PYSIDE_API void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, const std::size_t& cppObjSize);
|
||||||
PYSIDE_API void initQObjectSubType(SbkObjectType* type, PyObject* args, PyObject* kwds);
|
PYSIDE_API void initQObjectSubType(SbkObjectType* type, PyObject* args, PyObject* kwds);
|
||||||
|
|
||||||
|
/// Return the size in bytes of a type that inherits QObject.
|
||||||
|
PYSIDE_API std::size_t getSizeOfQObject(SbkObjectType* type);
|
||||||
|
|
||||||
typedef void (*CleanupFunction)(void);
|
typedef void (*CleanupFunction)(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -110,6 +115,9 @@ PYSIDE_API PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, Py
|
||||||
*/
|
*/
|
||||||
PYSIDE_API bool inherits(PyTypeObject* self, const char* class_name);
|
PYSIDE_API bool inherits(PyTypeObject* self, const char* class_name);
|
||||||
|
|
||||||
|
PYSIDE_API void* nextQObjectMemoryAddr();
|
||||||
|
PYSIDE_API void setNextQObjectMemoryAddr(void* addr);
|
||||||
|
|
||||||
} //namespace PySide
|
} //namespace PySide
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ PYSIDE_TEST(bug_814.py)
|
||||||
PYSIDE_TEST(bug_825.py)
|
PYSIDE_TEST(bug_825.py)
|
||||||
PYSIDE_TEST(bug_847.py)
|
PYSIDE_TEST(bug_847.py)
|
||||||
PYSIDE_TEST(bug_915.py)
|
PYSIDE_TEST(bug_915.py)
|
||||||
|
PYSIDE_TEST(bug_926.py)
|
||||||
PYSIDE_TEST(qdeclarativenetwork_test.py)
|
PYSIDE_TEST(qdeclarativenetwork_test.py)
|
||||||
PYSIDE_TEST(qdeclarativeview_test.py)
|
PYSIDE_TEST(qdeclarativeview_test.py)
|
||||||
PYSIDE_TEST(connect_python_qml.py)
|
PYSIDE_TEST(connect_python_qml.py)
|
||||||
|
|
|
||||||
38
tests/QtDeclarative/bug_926.py
Normal file
38
tests/QtDeclarative/bug_926.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
from helper import adjust_filename
|
||||||
|
from PySide.QtCore import *
|
||||||
|
from PySide.QtGui import *
|
||||||
|
from PySide.QtDeclarative import *
|
||||||
|
|
||||||
|
class MyClass (QObject):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(MyClass,self).__init__()
|
||||||
|
self.__url = QUrl()
|
||||||
|
|
||||||
|
def getUrl(self):
|
||||||
|
return self.__url
|
||||||
|
|
||||||
|
def setUrl(self,value):
|
||||||
|
newUrl = QUrl(value)
|
||||||
|
if (newUrl != self.__url):
|
||||||
|
self.__url = newUrl
|
||||||
|
self.urlChanged.emit()
|
||||||
|
|
||||||
|
urlChanged = Signal()
|
||||||
|
urla = Property(QUrl, getUrl, setUrl, notify = urlChanged)
|
||||||
|
|
||||||
|
class TestBug926 (unittest.TestCase):
|
||||||
|
def testIt(self):
|
||||||
|
app = QApplication([])
|
||||||
|
qmlRegisterType(MyClass,'Example',1,0,'MyClass')
|
||||||
|
view = QDeclarativeView()
|
||||||
|
view.setSource(QUrl.fromLocalFile(adjust_filename('bug_926.qml', __file__)))
|
||||||
|
self.assertEqual(len(view.errors()), 0)
|
||||||
|
view.show()
|
||||||
|
QTimer.singleShot(0, app.quit)
|
||||||
|
app.exec_()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
17
tests/QtDeclarative/bug_926.qml
Normal file
17
tests/QtDeclarative/bug_926.qml
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import Qt 4.7
|
||||||
|
import Example 1.0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 100
|
||||||
|
height: 62
|
||||||
|
|
||||||
|
MyClass {
|
||||||
|
id: myClass
|
||||||
|
urla: "http://www.pyside.org"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: name
|
||||||
|
text: myClass.urla
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue