5353#include " PythonQtStdDecorators.h"
5454#include " PythonQtQFileImporter.h"
5555#include " PythonQtBoolResult.h"
56+
57+ #include < QDir>
58+
5659#include < pydebug.h>
5760#include < vector>
5861
@@ -63,18 +66,17 @@ void PythonQt_init_QtGuiBuiltin(PyObject*);
6366void PythonQt_init_QtCoreBuiltin (PyObject*);
6467
6568
66- PyObject* PythonQtConvertFromStringRef (const void * inObject, int /* metaTypeId*/ )
67- {
68- return PythonQtConv::QStringToPyObject (((QStringRef*)inObject)->toString ());
69- }
70-
7169void PythonQt::init (int flags, const QByteArray& pythonQtModuleName)
7270{
7371 if (!_self) {
7472 _self = new PythonQt (flags, pythonQtModuleName);
7573
7674 PythonQt::priv ()->setupSharedLibrarySuffixes ();
7775
76+ _self->_p ->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>(" PythonQtObjectPtr" );
77+ PythonQtConv::registerMetaTypeToPythonConverter (_self->_p ->_PythonQtObjectPtr_metaId , PythonQtConv::convertFromPythonQtObjectPtr);
78+ PythonQtConv::registerPythonToMetaTypeConverter (_self->_p ->_PythonQtObjectPtr_metaId , PythonQtConv::convertToPythonQtObjectPtr);
79+
7880 PythonQtMethodInfo::addParameterTypeAlias (" QObjectList" , " QList<QObject*>" );
7981 qRegisterMetaType<QList<QObject*> >(" QList<void*>" );
8082 qRegisterMetaType<QObjectList>(" QObjectList" );
@@ -85,7 +87,11 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
8587 qRegisterMetaType<quint32>(" size_t" );
8688 }
8789 int stringRefId = qRegisterMetaType<QStringRef>(" QStringRef" );
88- PythonQtConv::registerMetaTypeToPythonConverter (stringRefId, PythonQtConvertFromStringRef);
90+ PythonQtConv::registerMetaTypeToPythonConverter (stringRefId, PythonQtConv::convertFromStringRef);
91+
92+ int objectPtrListId = qRegisterMetaType<QList<PythonQtObjectPtr> >(" QList<PythonQtObjectPtr>" );
93+ PythonQtConv::registerMetaTypeToPythonConverter (objectPtrListId, PythonQtConv::convertFromQListOfPythonQtObjectPtr);
94+ PythonQtConv::registerPythonToMetaTypeConverter (objectPtrListId, PythonQtConv::convertToQListOfPythonQtObjectPtr);
8995
9096 PythonQtRegisterToolClassesTemplateConverter (int );
9197 PythonQtRegisterToolClassesTemplateConverter (float );
@@ -250,8 +256,6 @@ PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
250256 _p = new PythonQtPrivate;
251257 _p->_initFlags = flags;
252258
253- _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>(" PythonQtObjectPtr" );
254-
255259 if ((flags & PythonAlreadyInitialized) == 0 ) {
256260#ifdef PY3K
257261 Py_SetProgramName (const_cast <wchar_t *>(L" PythonQt" ));
@@ -491,7 +495,7 @@ PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
491495 return (PyObject*)wrap;
492496}
493497
494- PyObject* PythonQtPrivate::wrapPtr (void * ptr, const QByteArray& name)
498+ PyObject* PythonQtPrivate::wrapPtr (void * ptr, const QByteArray& name, bool passOwnership )
495499{
496500 if (!ptr) {
497501 Py_INCREF (Py_None);
@@ -510,7 +514,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
510514 wrap = NULL ;
511515 }
512516 if (!wrap) {
513- PythonQtClassInfo* info = _knownClassInfos. value (name);
517+ PythonQtClassInfo* info = getClassInfo (name);
514518 if (!info) {
515519 // maybe it is a PyObject, which we can return directly
516520 if (name == " PyObject" ) {
@@ -538,6 +542,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
538542 }
539543 }
540544 wrap = createNewPythonQtInstanceWrapper (qptr, info);
545+ wrap->_ownedByPythonQt = passOwnership;
541546 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
542547 return (PyObject*)wrap;
543548 }
@@ -574,6 +579,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
574579 info = _knownClassInfos.value (qptr->metaObject ()->className ());
575580 }
576581 wrap = createNewPythonQtInstanceWrapper (qptr, info);
582+ wrap->_ownedByPythonQt = passOwnership;
577583 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
578584 return (PyObject*)wrap;
579585 }
@@ -594,6 +600,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
594600 Py_INCREF (wrap);
595601 } else {
596602 wrap = createNewPythonQtInstanceWrapper (wrapper, info, ptr);
603+ wrap->_ownedByPythonQt = passOwnership;
597604 }
598605 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
599606 } else {
@@ -622,13 +629,22 @@ PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObje
622629 result->_ownedByPythonQt = false ;
623630 result->_useQMetaTypeDestroy = false ;
624631
625- if (wrappedPtr) {
626- _wrappedObjects.insert (wrappedPtr, result);
627- } else {
628- _wrappedObjects.insert (obj, result);
629- if (obj->parent ()== NULL && _wrappedCB) {
630- // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
631- (*_wrappedCB)(obj);
632+ if (wrappedPtr || obj) {
633+
634+ // if this object is reference counted, we ref it:
635+ PythonQtVoidPtrCB* refCB = info->referenceCountingRefCB ();
636+ if (refCB) {
637+ (*refCB)(wrappedPtr);
638+ }
639+
640+ if (wrappedPtr) {
641+ _wrappedObjects.insert (wrappedPtr, result);
642+ } else {
643+ _wrappedObjects.insert (obj, result);
644+ if (obj->parent ()== NULL && _wrappedCB) {
645+ // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
646+ (*_wrappedCB)(obj);
647+ }
632648 }
633649 }
634650 return result;
@@ -980,27 +996,15 @@ QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
980996 if (type == CallOverloads) {
981997 if (PythonQtSlotFunction_Check (object)) {
982998 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object;
983- PythonQtSlotInfo* info = o->m_ml ;
984-
985- while (info) {
986- results << info->fullSignature ();
987- info = info->nextInfo ();
988- }
999+ results = o->m_ml ->overloads ();
9891000 } else if (PythonQtSignalFunction_Check (object)) {
9901001 PythonQtSignalFunctionObject* o = (PythonQtSignalFunctionObject*)object;
991- PythonQtSlotInfo* info = o->m_ml ;
992-
993- while (info) {
994- results << info->fullSignature ();
995- info = info->nextInfo ();
996- }
1002+ results = o->m_ml ->overloads ();
9971003 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
9981004 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
9991005 PythonQtSlotInfo* info = o->classInfo ()->constructors ();
1000-
1001- while (info) {
1002- results << info->fullSignature ();
1003- info = info->nextInfo ();
1006+ if (info) {
1007+ results = info->overloads (/* skipReturnValue = */ true );
10041008 }
10051009 } else {
10061010 QString signature = _p->getSignature (object);
@@ -1009,8 +1013,16 @@ QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
10091013 } else {
10101014 PyObject* doc = PyObject_GetAttrString (object, " __doc__" );
10111015 if (doc) {
1012- results << PyString_AsString (doc);
1016+ QString docString = QString::fromUtf8 ( PyString_AsString (doc) );
10131017 Py_DECREF (doc);
1018+ int idx = docString.indexOf (" \n " );
1019+ if (idx != -1 ) {
1020+ docString = docString.mid (0 , idx);
1021+ }
1022+ // if the first line contains a "(", take it as a signature
1023+ if (docString.contains (" (" )) {
1024+ results << docString;
1025+ }
10141026 }
10151027 }
10161028 }
@@ -1086,13 +1098,6 @@ QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
10861098 }
10871099 Py_DECREF (keys);
10881100 }
1089- if ((type == Anything) || (type == Variable)) {
1090- if (object->ob_type == &PythonQtClassWrapper_Type) {
1091- PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
1092- PythonQtClassInfo* info = o->classInfo ();
1093- results += info->propertyList ();
1094- }
1095- }
10961101 }
10971102 return results;
10981103}
@@ -1511,7 +1516,13 @@ void PythonQt::overwriteSysPath(const QStringList& paths)
15111516{
15121517 PythonQtObjectPtr sys;
15131518 sys.setNewRef (PyImport_ImportModule (" sys" ));
1514- PyModule_AddObject (sys, " path" , PythonQtConv::QStringListToPyList (paths));
1519+ // Since Python uses os.path.sep at various places,
1520+ // makse sure that we use the native path separators.
1521+ QStringList nativePaths;
1522+ foreach (QString path, paths) {
1523+ nativePaths << QDir::toNativeSeparators (path);
1524+ }
1525+ PyModule_AddObject (sys, " path" , PythonQtConv::QStringListToPyList (nativePaths));
15151526}
15161527
15171528void PythonQt::setModuleImportPath (PyObject* module , const QStringList& paths)
@@ -1592,7 +1603,6 @@ void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ
15921603 if (redirectStdOut) {
15931604 PythonQtObjectPtr out;
15941605 PythonQtObjectPtr err;
1595- sys.setNewRef (PyImport_ImportModule (" sys" ));
15961606 // create a redirection object for stdout and stderr
15971607 out = PythonQtStdOutRedirectType.tp_new (&PythonQtStdOutRedirectType,NULL , NULL );
15981608 ((PythonQtStdOutRedirect*)out.object ())->_cb = stdOutRedirectCB;
@@ -1626,13 +1636,12 @@ QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString&
16261636 QStringList tmp = name.split (" ." );
16271637 QString methodName = tmp.takeLast ();
16281638 QString variableName = tmp.join (" ." );
1629- // TODO: the variableName may be a type name, this needs to be handled differently,
1630- // because it is not necessarily known in the module context
16311639 PythonQtObjectPtr variableObject = lookupObject (module , variableName);
16321640 if (variableObject.isNull ()) {
1633- return " " ;
1641+ // try lookup by interpreting the variableName as a type
1642+ QString type = getReturnTypeOfWrappedMethod (variableName, methodName);
1643+ return type;
16341644 }
1635-
16361645 return getReturnTypeOfWrappedMethodHelper (variableObject, methodName, name);
16371646}
16381647
@@ -1664,53 +1673,24 @@ QString PythonQt::getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& va
16641673 // a constructor is called. Return the context.
16651674 type = context;
16661675 } else if (methodObject->ob_type == &PythonQtSlotFunction_Type) {
1667- QString className;
1668-
1669- if (PyObject_TypeCheck (variableObject, &PythonQtInstanceWrapper_Type)) {
1670- // the type name of wrapped instance is the class name
1671- className = variableObject->ob_type ->tp_name ;
1672- } else {
1673- PyObject* classNameObject = PyObject_GetAttrString (variableObject, " __name__" );
1674- if (classNameObject) {
1675- Q_ASSERT (PyString_Check (classNameObject));
1676- className = PyString_AsString (classNameObject);
1677- Py_DECREF (classNameObject);
1678- }
1679- }
1680-
1681- if (!className.isEmpty ()) {
1682- PythonQtClassInfo* info = _p->_knownClassInfos .value (className.toLatin1 ().constData ());
1683- if (info) {
1684- PythonQtSlotInfo* slotInfo = info->member (methodName.toLatin1 ().constData ())._slot ;
1685- if (slotInfo) {
1686- if (slotInfo->metaMethod ()) {
1687- type = PythonQtUtils::typeName (*slotInfo->metaMethod ());
1688- if (!type.isEmpty ()) {
1689- QChar c = type.at (type.length ()-1 );
1690- while (c == ' *' || c == ' &' ) {
1691- type.truncate (type.length ()-1 );
1692- if (!type.isEmpty ()) {
1693- c = type.at (type.length ()-1 );
1694- } else {
1695- break ;
1696- }
1697- }
1698- // split away template arguments
1699- type = type.split (" <" ).first ();
1700- // split away const
1701- type = type.split (" " ).last ().trimmed ();
1702-
1703- // if the type is a known class info, then create the full type name, i.e. include the
1704- // module name. For example, the slot may return a QDate, then this looks up the
1705- // name _PythonQt.QtCore.QDate.
1706- PythonQtClassInfo* typeInfo = _p->_knownClassInfos .value (type.toLatin1 ().constData ());
1707- if (typeInfo && typeInfo->pythonQtClassWrapper ()) {
1708- PyObject* s = PyObject_GetAttrString (typeInfo->pythonQtClassWrapper (), " __module__" );
1709- Q_ASSERT (PyString_Check (s));
1710- type = QString (PyString_AsString (s)) + " ." + type;
1711- Py_DECREF (s);
1712- }
1713- }
1676+ PythonQtSlotInfo* slotInfo = ((PythonQtSlotFunctionObject*)methodObject.object ())->m_ml ;
1677+ if (slotInfo) {
1678+ if (slotInfo->parameterCount ()>0 ) {
1679+ type = slotInfo->parameters ().at (0 ).name ;
1680+ if (type.contains (" <" )) {
1681+ // can't handle templates
1682+ type = " " ;
1683+ }
1684+ if (!type.isEmpty ()) {
1685+ // if the type is a known class info, then create the full type name, i.e. include the
1686+ // module name. For example, the slot may return a QDate, then this looks up the
1687+ // name _PythonQt.QtCore.QDate.
1688+ PythonQtClassInfo* typeInfo = _p->_knownClassInfos .value (type.toLatin1 ().constData ());
1689+ if (typeInfo && typeInfo->pythonQtClassWrapper ()) {
1690+ PyObject* s = PyObject_GetAttrString (typeInfo->pythonQtClassWrapper (), " __module__" );
1691+ Q_ASSERT (PyString_Check (s));
1692+ type = QString (PyString_AsString (s)) + " ." + type;
1693+ Py_DECREF (s);
17141694 }
17151695 }
17161696 }
@@ -2062,3 +2042,34 @@ PyObject* PythonQtPrivate::wrapMemoryAsBuffer( void* data, Py_ssize_t size )
20622042 return PyBuffer_FromReadWriteMemory ((char *)data, size);
20632043#endif
20642044}
2045+
2046+ PythonQtClassInfo* PythonQtPrivate::getClassInfo ( const QMetaObject* meta )
2047+ {
2048+ return getClassInfo (QByteArray (meta->className ()));
2049+ }
2050+
2051+ PythonQtClassInfo* PythonQtPrivate::getClassInfo ( const QByteArray& className )
2052+ {
2053+ PythonQtClassInfo* result = _knownClassInfos.value (className);
2054+ if (!result) {
2055+ static bool recursion = false ;
2056+ if (!recursion) {
2057+ if (_knownLazyClasses.contains (className)) {
2058+ QByteArray module = _knownLazyClasses.value (className);
2059+ recursion = true ;
2060+ PyImport_ImportModule (module );
2061+ recursion = false ;
2062+ result = _knownClassInfos.value (className);
2063+ if (!result) {
2064+ std::cerr << " PythonQt lazy import " << module .constData () << " did not resolve " << className.constData () <<std::endl;
2065+ }
2066+ }
2067+ }
2068+ }
2069+ return result;
2070+ }
2071+
2072+ void PythonQtPrivate::registerLazyClass ( const QByteArray& name, const QByteArray& moduleToImport )
2073+ {
2074+ _knownLazyClasses.insert (name, moduleToImport);
2075+ }
0 commit comments