/* * * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29, * 28359 Bremen, Germany or: * * http://www.mevis.de * */ //---------------------------------------------------------------------------------- /*! // \file PythonQtMethodInfo.cpp // \author Florian Link // \author Last changed by $Author: florian $ // \date 2006-05 */ //---------------------------------------------------------------------------------- #include "PythonQtMethodInfo.h" #include "PythonQtClassInfo.h" #include QHash PythonQtMethodInfo::_cachedSignatures; QHash PythonQtMethodInfo::_cachedParameterInfos; QHash PythonQtMethodInfo::_parameterNameAliases; bool PythonQtSlotInfo::_globalShouldAllowThreads = false; PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo) { #ifdef PYTHONQT_DEBUG QByteArray sig = PythonQtUtils::signature(meta); sig = sig.mid(sig.indexOf('(')); QByteArray fullSig = QByteArray(meta.typeName()) + " " + sig; std::cout << "caching " << fullSig.data() << std::endl; #endif ParameterInfo type; fillParameterInfo(type, QByteArray(meta.typeName()), classInfo); _parameters.append(type); QList names = meta.parameterTypes(); for (const QByteArray& name : names) { fillParameterInfo(type, name, classInfo); _parameters.append(type); } setupAllowThreads(); } PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList& args) { ParameterInfo type; fillParameterInfo(type, typeName, nullptr); _parameters.append(type); for (const QByteArray& name : args) { fillParameterInfo(type, name, nullptr); _parameters.append(type); } setupAllowThreads(); } void PythonQtMethodInfo::setupAllowThreads() { bool allowThreads = true; for (const ParameterInfo& info : qAsConst(_parameters)) { if (info.name == "PyObject" || info.name == "PythonQtObjectPtr" || info.innerName == "PyObject" || info.innerName == "PythonQtObjectPtr") { allowThreads = false; break; } } _shouldAllowThreads = allowThreads; } const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo) { QByteArray sig(PythonQtUtils::signature(signal)); sig = sig.mid(sig.indexOf('(')); QByteArray fullSig = QByteArray(signal.typeName()) + " " + sig; PythonQtMethodInfo* result = _cachedSignatures.value(fullSig); if (!result) { result = new PythonQtMethodInfo(signal, classInfo); _cachedSignatures.insert(fullSig, result); } return result; } const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(int numArgs, const char** args) { QByteArray typeName = args[0]; QList arguments; QByteArray fullSig = typeName; fullSig += "("; for (int i = 1; i < numArgs; i++) { if (i > 1) { fullSig += ","; } QByteArray arg(args[i]); fullSig += arg; arguments << arg; } fullSig += ")"; PythonQtMethodInfo* result = _cachedSignatures.value(fullSig); if (!result) { result = new PythonQtMethodInfo(typeName, arguments); _cachedSignatures.insert(fullSig, result); } return result; } void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo) { QByteArray name = orgName; type.enumWrapper = nullptr; type.innerNamePointerCount = 0; type.isQList = false; type.passOwnershipToCPP = false; type.passOwnershipToPython = false; type.newOwnerOfThis = false; int len = name.length(); if (len > 0) { if (name.startsWith("PythonQtPassOwnershipToCPP<")) { type.passOwnershipToCPP = true; name = name.mid(27, len - 28); len -= 28; } else if (name.startsWith("PythonQtPassOwnershipToPython<")) { type.passOwnershipToPython = true; name = name.mid(30, len - 31); len -= 31; } else if (name.startsWith("PythonQtNewOwnerOfThis<")) { type.newOwnerOfThis = true; name = name.mid(23, len - 24); len -= 24; } if (strncmp(name.constData(), "const ", 6) == 0) { name = name.mid(6); len -= 6; type.isConst = true; } else { type.isConst = false; } char pointerCount = 0; bool hadReference = false; // remove * and & from the end of the string while (name.at(len - 1) == '*') { len--; pointerCount++; } while (name.at(len - 1) == '&') { len--; hadReference = true; } if (len != name.length()) { name = name.left(len); } type.pointerCount = pointerCount; type.isReference = hadReference; QByteArray alias = _parameterNameAliases.value(name); if (!alias.isEmpty()) { name = alias; } type.typeId = nameToType(name); if (type.typeId == Unknown) { type.typeId = PythonQtUtils::metaTypeIdFromTypeName(name.constData()); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (type.typeId == QMetaType::UnknownType) { #else if (type.typeId == QMetaType::Void) { #endif type.typeId = Unknown; } } type.name = name; if (name.startsWith("QList<")) { type.isQList = true; } if (name.contains("<")) { QByteArray innerName = getInnerTemplateTypeName(name); if (innerName.endsWith("*")) { type.innerNamePointerCount = 1; innerName.truncate(innerName.length() - 1); } type.innerName = innerName; } if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) { bool isLocalEnum; // TODOXXX: make use of this flag! type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, &isLocalEnum); } } else { type.typeId = QMetaType::Void; type.pointerCount = 0; type.isConst = false; type.isReference = false; } } int PythonQtMethodInfo::getInnerTemplateMetaType(const QByteArray& typeName) { int idx = typeName.indexOf("<"); if (idx > 0) { int idx2 = typeName.lastIndexOf(">"); if (idx2 > 0) { QByteArray innerType = typeName.mid(idx + 1, idx2 - idx - 1).trimmed(); return PythonQtUtils::metaTypeIdFromTypeName(innerType.constData()); } } return QMetaType::Void; } QByteArray PythonQtMethodInfo::getInnerTemplateTypeName(const QByteArray& typeName) { int idx = typeName.indexOf("<"); if (idx > 0) { int idx2 = typeName.lastIndexOf(">"); if (idx2 > 0) { return typeName.mid(idx + 1, idx2 - idx - 1).trimmed(); } } return QByteArray(); } QByteArray PythonQtMethodInfo::getInnerListTypeName(const QByteArray& typeName) { QByteArray name = getInnerTemplateTypeName(typeName); if (name.isEmpty() && typeName.endsWith("List")) { name = typeName.left(typeName.length() - 4); } return name; } int PythonQtMethodInfo::nameToType(const char* name) { if (_parameterTypeDict.isEmpty()) { // we could also use QMetaType::nameToType, but that does a string compare search // and does not support QVariant // QMetaType names _parameterTypeDict.insert("long", QMetaType::Long); _parameterTypeDict.insert("int", QMetaType::Int); _parameterTypeDict.insert("short", QMetaType::Short); _parameterTypeDict.insert("char", QMetaType::Char); _parameterTypeDict.insert("signed long", QMetaType::Long); _parameterTypeDict.insert("signed int", QMetaType::Int); _parameterTypeDict.insert("signed short", QMetaType::Short); _parameterTypeDict.insert("signed char", QMetaType::Char); _parameterTypeDict.insert("ulong", QMetaType::ULong); _parameterTypeDict.insert("unsigned long", QMetaType::ULong); _parameterTypeDict.insert("uint", QMetaType::UInt); _parameterTypeDict.insert("unsigned int", QMetaType::UInt); _parameterTypeDict.insert("ushort", QMetaType::UShort); _parameterTypeDict.insert("unsigned short", QMetaType::UShort); _parameterTypeDict.insert("uchar", QMetaType::UChar); _parameterTypeDict.insert("unsigned char", QMetaType::UChar); _parameterTypeDict.insert("bool", QMetaType::Bool); _parameterTypeDict.insert("float", QMetaType::Float); _parameterTypeDict.insert("double", QMetaType::Double); _parameterTypeDict.insert("qreal", QMetaType::Double); _parameterTypeDict.insert("QChar", QMetaType::QChar); _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray); _parameterTypeDict.insert("QString", QMetaType::QString); _parameterTypeDict.insert("", QMetaType::Void); _parameterTypeDict.insert("void", QMetaType::Void); _parameterTypeDict.insert("QtMsgType", QMetaType::Int); // GL types _parameterTypeDict.insert("GLenum", QMetaType::UInt); _parameterTypeDict.insert("GLboolean", QMetaType::UChar); _parameterTypeDict.insert("GLbitfield", QMetaType::UInt); _parameterTypeDict.insert("GLbyte", QMetaType::Char); _parameterTypeDict.insert("GLubyte", QMetaType::UChar); _parameterTypeDict.insert("GLshort", QMetaType::Short); _parameterTypeDict.insert("GLushort", QMetaType::UShort); _parameterTypeDict.insert("GLint", QMetaType::Int); _parameterTypeDict.insert("GLuint", QMetaType::UInt); _parameterTypeDict.insert("GLsizei", QMetaType::UInt); _parameterTypeDict.insert("GLclampf", QMetaType::Float); _parameterTypeDict.insert("GLfloat", QMetaType::Float); _parameterTypeDict.insert("GLclampd", QMetaType::Double); _parameterTypeDict.insert("GLdouble", QMetaType::Double); _parameterTypeDict.insert("GLvoid", QMetaType::Void); // Pointer-size dependent types if (QT_POINTER_SIZE == 8) { _parameterTypeDict.insert("qgl_GLintptr", QMetaType::LongLong); _parameterTypeDict.insert("qgl_GLsizeiptr", QMetaType::LongLong); _parameterTypeDict.insert("size_t", QMetaType::ULongLong); _parameterTypeDict.insert("qintptr", QMetaType::LongLong); _parameterTypeDict.insert("qptrdiff", QMetaType::LongLong); _parameterTypeDict.insert("quintptr", QMetaType::ULongLong); _parameterTypeDict.insert("WId", QMetaType::ULongLong); _parameterTypeDict.insert("qsizetype", QMetaType::LongLong); } else { _parameterTypeDict.insert("qgl_GLintptr", QMetaType::Int); _parameterTypeDict.insert("qgl_GLsizeiptr", QMetaType::Int); _parameterTypeDict.insert("size_t", QMetaType::UInt); _parameterTypeDict.insert("qintptr", QMetaType::Int); _parameterTypeDict.insert("qptrdiff", QMetaType::Int); _parameterTypeDict.insert("quintptr", QMetaType::UInt); _parameterTypeDict.insert("WId", QMetaType::UInt); _parameterTypeDict.insert("qsizetype", QMetaType::Int); } #ifdef PYTHONQT_SUPPORT_ML_TYPES _parameterTypeDict.insert("MLuint8", QMetaType::UChar); _parameterTypeDict.insert("MLint8", QMetaType::Char); _parameterTypeDict.insert("MLuint16", QMetaType::UShort); _parameterTypeDict.insert("MLint16", QMetaType::Short); _parameterTypeDict.insert("MLuint32", QMetaType::UInt); _parameterTypeDict.insert("MLint32", QMetaType::Int); _parameterTypeDict.insert("MLuint64", QMetaType::ULongLong); _parameterTypeDict.insert("MLint64", QMetaType::LongLong); _parameterTypeDict.insert("MLuint", QMetaType::ULongLong); _parameterTypeDict.insert("MLint", QMetaType::LongLong); _parameterTypeDict.insert("MLfloat", QMetaType::Float); _parameterTypeDict.insert("MLdouble", QMetaType::Double); #endif // QVariant names _parameterTypeDict.insert("Q_LLONG", QMetaType::LongLong); _parameterTypeDict.insert("Q_ULLONG", QMetaType::ULongLong); _parameterTypeDict.insert("qlonglong", QMetaType::LongLong); _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong); _parameterTypeDict.insert("qint64", QMetaType::LongLong); _parameterTypeDict.insert("quint64", QMetaType::ULongLong); _parameterTypeDict.insert("QVariantHash", QMetaType::QVariantHash); _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap); _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList); _parameterTypeDict.insert("QHash", QMetaType::QVariantHash); _parameterTypeDict.insert("QMap", QMetaType::QVariantMap); _parameterTypeDict.insert("QList", QMetaType::QVariantList); _parameterTypeDict.insert("QStringList", QMetaType::QStringList); _parameterTypeDict.insert("QBitArray", QMetaType::QBitArray); _parameterTypeDict.insert("QDate", QMetaType::QDate); _parameterTypeDict.insert("QTime", QMetaType::QTime); _parameterTypeDict.insert("QDateTime", QMetaType::QDateTime); _parameterTypeDict.insert("QUrl", QMetaType::QUrl); _parameterTypeDict.insert("QLocale", QMetaType::QLocale); _parameterTypeDict.insert("QRect", QMetaType::QRect); _parameterTypeDict.insert("QRectF", QMetaType::QRectF); _parameterTypeDict.insert("QSize", QMetaType::QSize); _parameterTypeDict.insert("QSizeF", QMetaType::QSizeF); _parameterTypeDict.insert("QLine", QMetaType::QLine); _parameterTypeDict.insert("QLineF", QMetaType::QLineF); _parameterTypeDict.insert("QPoint", QMetaType::QPoint); _parameterTypeDict.insert("QPointF", QMetaType::QPointF); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp); #endif _parameterTypeDict.insert("QRegularExpression", QMetaType::QRegularExpression); _parameterTypeDict.insert("QFont", QMetaType::QFont); _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap); _parameterTypeDict.insert("QBrush", QMetaType::QBrush); _parameterTypeDict.insert("QColor", QMetaType::QColor); _parameterTypeDict.insert("QCursor", QMetaType::QCursor); _parameterTypeDict.insert("QPalette", QMetaType::QPalette); _parameterTypeDict.insert("QIcon", QMetaType::QIcon); _parameterTypeDict.insert("QImage", QMetaType::QImage); _parameterTypeDict.insert("QRegion", QMetaType::QRegion); _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap); _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy); _parameterTypeDict.insert("QKeySequence", QMetaType::QKeySequence); _parameterTypeDict.insert("QPen", QMetaType::QPen); _parameterTypeDict.insert("QTextLength", QMetaType::QTextLength); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) _parameterTypeDict.insert("QMatrix", QMetaType::QMatrix); #endif _parameterTypeDict.insert("QMatrix4x4", QMetaType::QMatrix4x4); _parameterTypeDict.insert("QTransform", QMetaType::QTransform); _parameterTypeDict.insert("QTextFormat", QMetaType::QTextFormat); _parameterTypeDict.insert("QVariant", PythonQtMethodInfo::Variant); // own special types... (none so far, could be e.g. ObjectList } QHash::const_iterator it = _parameterTypeDict.find(name); if (it != _parameterTypeDict.end()) { return it.value(); } else { return PythonQtMethodInfo::Unknown; } } void PythonQtMethodInfo::cleanupCachedMethodInfos() { QHashIterator i(_cachedSignatures); while (i.hasNext()) { delete i.next().value(); } _cachedSignatures.clear(); _cachedParameterInfos.clear(); } void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QByteArray& name) { #if QT_VERSION >= 0x060000 QByteArray alias2 {alias}; QByteArray name2 {name}; // in Qt6 QPair has been replaced by std::pair, QVector is really QList, and there is no space between ">" alias2.replace("QPair", "std::pair").replace("QVector", "QList").replace("> >", ">>"); name2.replace("QPair", "std::pair").replace("QVector", "QList").replace("> >", ">>"); _parameterNameAliases.insert(alias2, name2); #else _parameterNameAliases.insert(alias, name); #endif } const PythonQtMethodInfo::ParameterInfo& PythonQtMethodInfo::getParameterInfoForMetaType(int type) { QHash::ConstIterator it = _cachedParameterInfos.find(type); if (it != _cachedParameterInfos.constEnd()) { return it.value(); } ParameterInfo info; fillParameterInfo(info, QByteArray(PythonQtUtils::typeNameFromMetaTypeId(type))); _cachedParameterInfos.insert(type, info); return _cachedParameterInfos[type]; } //------------------------------------------------------------------------------------------------- void PythonQtSlotInfo::deleteOverloadsAndThis() { PythonQtSlotInfo* cur = this; while (cur) { PythonQtSlotInfo* next = cur->nextInfo(); delete cur; cur = next; } } QString PythonQtSlotInfo::fullSignature(bool skipReturnValue, int optionalArgsIndex) const { int firstArgOffset = isInstanceDecorator() ? 2 : 1; QString result; QByteArray sig = slotName(); QList names = _meta.parameterNames(); bool isStatic = false; bool isConstructor = false; bool isDestructor = false; if (_type == ClassDecorator) { if (sig.startsWith("new_")) { sig = sig.mid(4); isConstructor = true; } else if (sig.startsWith("py_q_")) { sig = sig.mid(5); } else if (sig.startsWith("delete_")) { sig = sig.mid(7); isDestructor = true; } else if (sig.startsWith("static_")) { isStatic = true; sig = sig.mid(7); int idx = sig.indexOf("_"); if (idx >= 0) { sig = sig.mid(idx + 1); } } } result += sig; result += "("; for (int i = firstArgOffset; i < _parameters.count(); i++) { if ((optionalArgsIndex + firstArgOffset) == i) { result += " ["; } if (i != firstArgOffset) { result += ", "; } //if (_parameters.at(i).isConst) { // result += "const "; //} if (_parameters.at(i).name == "bool" && _parameters.at(i).pointerCount == 1) { result += "PythonQt.BoolResult"; } else { result += _parameters.at(i).name; } //if (_parameters.at(i).pointerCount) { // QByteArray stars; // stars.fill('*', _parameters.at(i).pointerCount); // result += stars; //} if (!names.at(i - 1).isEmpty()) { result += " "; result += names.at(i - 1); } } if (optionalArgsIndex != -1) { result += "]"; } result += ")"; if (isStatic) { result = QString("static ") + result; } if (isConstructor) { // result = QString("constructor ") + result; } if (isDestructor) { result = QString("~") + result; } if (!skipReturnValue) { if (!_parameters.at(0).name.isEmpty()) { result += " -> "; result += _parameters.at(0).name; } } return result; } QByteArray PythonQtSlotInfo::slotName(bool removeDecorators) const { QByteArray name = PythonQtUtils::methodName(_meta); if (removeDecorators) { if (name.startsWith("py_q_")) { name = name.mid(5); } else if (name.startsWith("static_")) { name = name.mid(7); int idx = name.indexOf("_"); if (idx >= 0) { name = name.mid(idx + 1); } } } return name; } QByteArray PythonQtSlotInfo::signature() const { return PythonQtUtils::signature(_meta); } QStringList PythonQtSlotInfo::overloads(bool skipReturnValue) const { const PythonQtSlotInfo* info = this; QList list; do { list << info; info = info->nextInfo(); } while (info); QList all = list; QStringList results; while (!list.isEmpty()) { const PythonQtSlotInfo* current = list.takeFirst(); int minSameArgs = 1000; QList currentArguments = current->arguments(); int maxArgs = currentArguments.size(); const PythonQtSlotInfo* maxArgSlot = current; QList slotsWithSameArgs; slotsWithSameArgs << current; QMutableListIterator it(all); while (it.hasNext()) { const PythonQtSlotInfo* other = it.next(); // same slot... if (other == current) { continue; } // different return types... if (other->parameters().at(0).name != current->parameters().at(0).name) { continue; } QList otherArguments = other->arguments(); int paramCount = qMin(currentArguments.size(), otherArguments.size()); int sameArgs = 0; for (int i = 0; i < paramCount; i++) { if (currentArguments.at(i).name == otherArguments.at(i).name) { sameArgs++; } else { break; } } if (sameArgs > 0 && sameArgs == paramCount) { slotsWithSameArgs << other; minSameArgs = qMin(sameArgs, minSameArgs); if (otherArguments.size() > maxArgs) { maxArgs = otherArguments.size(); maxArgSlot = other; current = other; currentArguments = otherArguments; } } } if (slotsWithSameArgs.size() > 1) { results << maxArgSlot->fullSignature(skipReturnValue, minSameArgs); for (const PythonQtSlotInfo* o : slotsWithSameArgs) { list.removeOne(o); } } else { results << current->fullSignature(skipReturnValue); } } return results; } QList PythonQtSlotInfo::arguments() const { QList result; for (int i = isInstanceDecorator() ? 2 : 1; i < _parameters.size(); i++) { result << _parameters[i]; } return result; } QByteArray PythonQtSlotInfo::getImplementingClassName() const { if (isInstanceDecorator()) { return _parameters.at(1).name; } else if (isClassDecorator()) { QByteArray name = PythonQtUtils::methodName(_meta); if (name.startsWith("static_")) { name = name.mid(7); int idx = name.indexOf("_"); name = name.mid(0, idx); return name; } else { return name; } } else { return _meta.enclosingMetaObject()->className(); } } void PythonQtSlotInfo::invokeQtMethod(QObject* obj, PythonQtSlotInfo* slot, void** args) { if (slot->shouldAllowThreads() && _globalShouldAllowThreads) { PYTHONQT_ALLOW_THREADS_SCOPE obj->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args); } else { obj->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args); } } void PythonQtSlotInfo::setGlobalShouldAllowThreads(bool flag) { _globalShouldAllowThreads = flag; } bool PythonQtSlotInfo::getGlobalShouldAllowThreads() { return _globalShouldAllowThreads; }