static PyObject * meth_get__doc__(PythonQtSlotFunctionObject * m, void * /*closure*/) { QByteArray doc; PythonQtSlotInfo* info = m->m_ml; const QByteArray& returnType = info->parameters().at(0).name; int returnTypeId = info->parameters().at(0).typeId; PythonQtSlotInfo* longestInfo = info; PythonQtSlotInfo* infoSearch = info->nextInfo(); while (infoSearch) { if (longestInfo->parameterCount() < infoSearch->parameterCount()) { longestInfo = infoSearch; } infoSearch = infoSearch->nextInfo(); } doc = "X." + info->slotName(true) + "("; for (int i = 1;i<longestInfo->parameterCount(); i++) { if (i!=1) { doc += ", "; } doc += QString('a' + i-1); } doc += ")"; QByteArray pyReturnType; if (returnType == "QString" || returnType == "SbName" || returnType == "SbString") { pyReturnType = "str"; } else if (returnType.startsWith("QVector<") || returnType.startsWith("QList<") || returnType == "QStringList" || returnType == "QObjectList" || returnType == "QVariantList") { pyReturnType = "tuple"; } else if (returnType.startsWith("QHash<") || returnType.startsWith("QMap<") || returnType == "QVariantMap" || returnType == "QVariantHash") { pyReturnType = "dict"; } else if (returnTypeId == QVariant::Bool) { pyReturnType = "bool"; } else if (returnTypeId == PythonQtMethodInfo::Variant) { pyReturnType = "object"; } else if (returnTypeId == QMetaType::Char || returnTypeId == QMetaType::UChar || returnTypeId == QMetaType::Short || returnTypeId == QMetaType::UShort || returnTypeId == QMetaType::Int || returnTypeId == QMetaType::UInt || returnTypeId == QMetaType::Long || returnTypeId == QMetaType::ULong || returnTypeId == QMetaType::LongLong || returnTypeId == QMetaType::ULongLong) { pyReturnType = "int"; } else if (returnTypeId == QMetaType::Float || returnTypeId == QMetaType::Double) { pyReturnType = "float"; } else { PythonQtClassInfo* returnTypeClassInfo = PythonQt::priv()->getClassInfo(returnType); if (returnTypeClassInfo) { PyObject* s = PyObject_GetAttrString(returnTypeClassInfo->pythonQtClassWrapper(), "__module__"); if (s) { pyReturnType = QByteArray(PyString_AsString(s)) + "." + returnType; Py_DECREF(s); } } } if (!pyReturnType.isEmpty()) { doc += " -> " + pyReturnType; } return PyString_FromString(doc.constData()); }
bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer) { static unsigned int recursiveEntry = 0; if (directReturnValuePointer) { *directReturnValuePointer = NULL; } // store the current storage position, so that we can get back to this state after a slot is called // (do this locally, so that we have all positions on the stack PythonQtValueStoragePosition globalValueStoragePos; PythonQtValueStoragePosition globalPtrStoragePos; PythonQtValueStoragePosition globalVariantStoragePos; PythonQtConv::global_valueStorage.getPos(globalValueStoragePos); PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos); PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos); recursiveEntry++; // the arguments that are passed to qt_metacall void* argList[PYTHONQT_MAX_ARGS]; PyObject* result = NULL; int argc = info->parameterCount(); const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters(); const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0); // set return argument to NULL argList[0] = NULL; bool ok = true; bool skipFirst = false; if (info->isInstanceDecorator()) { skipFirst = true; // for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer void* arg1 = firstArgument; if (!arg1) { arg1 = objectToCall; } if (arg1) { // upcast to correct parent class arg1 = ((char*)arg1)+info->upcastingOffset(); } argList[1] = &arg1; if (ok) { for (int i = 2; i<argc && ok; i++) { const PythonQtSlotInfo::ParameterInfo& param = params.at(i); argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo); if (argList[i]==NULL) { ok = false; break; } } } } else { for (int i = 1; i<argc && ok; i++) { const PythonQtSlotInfo::ParameterInfo& param = params.at(i); argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo); if (argList[i]==NULL) { ok = false; break; } } } if (ok) { // parameters are ok, now create the qt return value which is assigned to by metacall if (returnValueParam.typeId != QMetaType::Void) { // create empty default value for the return value if (!directReturnValuePointer) { // create empty default value for the return value argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam); if (argList[0]==NULL) { // return value could not be created, maybe we have a registered class with a default constructor, so that we can construct the pythonqt wrapper object and // pass its internal pointer PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name); if (info && info->pythonQtClassWrapper()) { PyObject* emptyTuple = PyTuple_New(0); // 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL); if (result) { argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr; } Py_DECREF(emptyTuple); } } } else { // we can use our pointer directly! argList[0] = directReturnValuePointer; } } PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB(); if (profilingCB) { const char* className = NULL; if (info->decorator()) { className = info->decorator()->metaObject()->className(); } else { className = objectToCall->metaObject()->className(); } profilingCB(PythonQt::Enter, className, info->metaMethod()->signature()); } // invoke the slot via metacall bool hadException = false; QObject* obj = info->decorator()?info->decorator():objectToCall; if (!obj) { hadException = true; PyErr_SetString(PyExc_RuntimeError, "Trying to call a slot on a deleted QObject!"); } else { try { obj->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList); } catch (std::bad_alloc & e) { hadException = true; QByteArray what("std::bad_alloc: "); what += e.what(); PyErr_SetString(PyExc_MemoryError, what.constData()); } catch (std::runtime_error & e) { hadException = true; QByteArray what("std::runtime_error: "); what += e.what(); PyErr_SetString(PyExc_RuntimeError, what.constData()); } catch (std::logic_error & e) { hadException = true; QByteArray what("std::logic_error: "); what += e.what(); PyErr_SetString(PyExc_RuntimeError, what.constData()); } catch (std::exception& e) { hadException = true; QByteArray what("std::exception: "); what += e.what(); PyErr_SetString(PyExc_StandardError, what.constData()); } } if (profilingCB) { profilingCB(PythonQt::Leave, NULL, NULL); } // handle the return value (which in most cases still needs to be converted to a Python object) if (!hadException) { if (argList[0] || returnValueParam.typeId == QMetaType::Void) { if (directReturnValuePointer) { result = NULL; } else { // the resulting object maybe present already, because we created it above at 1)... if (!result) { result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]); } } } else { QString e = QString("Called ") + info->fullSignature() + ", return type '" + returnValueParam.name + "' is ignored because it is unknown to PythonQt. Probably you should register it using qRegisterMetaType() or add a default constructor decorator to the class."; PyErr_SetString(PyExc_ValueError, e.toLatin1().data()); result = NULL; } } else { result = NULL; } } recursiveEntry--; // reset the parameter storage position to the stored pos to "pop" the parameter stack PythonQtConv::global_valueStorage.setPos(globalValueStoragePos); PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos); PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos); *pythonReturnValue = result; // NOTE: it is important to only return here, otherwise the stack will not be popped!!! return result || (directReturnValuePointer && *directReturnValuePointer); }
PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data) { // is it an enum value? if (info.enumWrapper) { if (info.pointerCount==0) { return PythonQtPrivate::createEnumValueInstance(info.enumWrapper, *((unsigned int*)data)); } else { // we do not support pointers to enums (who needs them?) Py_INCREF(Py_None); return Py_None; } } if (info.typeId == QMetaType::Void) { Py_INCREF(Py_None); return Py_None; } else if ((info.pointerCount == 1) && (info.typeId == QMetaType::Char)) { // a char ptr will probably be a null terminated string, so we support that: char* charPtr = *((char**)data); if (charPtr) { return PyString_FromString(charPtr); } else { Py_INCREF(Py_None); return Py_None; } } else if ((info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) && info.isQList && (info.innerNamePointerCount == 1)) { // it is a QList<Obj*> template: QList<void*>* listPtr = NULL; if (info.pointerCount == 1) { listPtr = *((QList<void*>**)data); } else if (info.pointerCount == 0) { listPtr = (QList<void*>*)data; } if (listPtr) { return ConvertQListOfPointerTypeToPythonList(listPtr, info.innerName); } else { return NULL; } } if (info.typeId >= QMetaType::User) { // if a converter is registered, we use is: PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId); if (converter) { return (*converter)(info.pointerCount==0?data:*((void**)data), info.typeId); } } // special handling did not match, so we convert the usual way (either pointer or value version): if (info.pointerCount == 1) { // convert the pointer to a Python Object (we can handle ANY C++ object, in the worst case we just know the type and the pointer) return PythonQt::priv()->wrapPtr(*((void**)data), info.name); } else if (info.pointerCount == 0) { if (info.typeId != PythonQtMethodInfo::Unknown) { // handle values that are const& or by value and have a metatype return ConvertQtValueToPythonInternal(info.typeId, data); } else { // the type does not have a typeid, we need to make a copy using the copy constructor PythonQtClassInfo* classInfo = PythonQt::priv()->getClassInfo(info.name); if (classInfo) { PyObject* result = classInfo->copyObject((void*)data); if (result) { return result; } } } } Py_INCREF(Py_None); return Py_None; }