aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/libpyside/dynamicqmetaobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/libpyside/dynamicqmetaobject.cpp')
-rw-r--r--sources/pyside6/libpyside/dynamicqmetaobject.cpp273
1 files changed, 181 insertions, 92 deletions
diff --git a/sources/pyside6/libpyside/dynamicqmetaobject.cpp b/sources/pyside6/libpyside/dynamicqmetaobject.cpp
index 39be38b29..048001f81 100644
--- a/sources/pyside6/libpyside/dynamicqmetaobject.cpp
+++ b/sources/pyside6/libpyside/dynamicqmetaobject.cpp
@@ -1,50 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "dynamicqmetaobject.h"
-#include "dynamicqmetaobject_p.h"
+#include "pysideqobject.h"
#include "pysidesignal.h"
#include "pysidesignal_p.h"
#include "pysideproperty.h"
#include "pysideproperty_p.h"
#include "pysideslot_p.h"
#include "pysideqenum.h"
+#include "pyside_p.h"
+#include "pysidestaticstrings.h"
#include <shiboken.h>
@@ -58,6 +24,8 @@
#include <cstring>
#include <vector>
+using namespace Qt::StringLiterals;
+
using namespace PySide;
// MetaObjectBuilder: Provides the QMetaObject's returned by
@@ -85,7 +53,8 @@ public:
const QByteArray &signature) const;
int indexOfProperty(const QByteArray &name) const;
int addSlot(const QByteArray &signature);
- int addSlot(const QByteArray &signature, const QByteArray &type);
+ int addSlot(const QByteArray &signature, const QByteArray &type,
+ const QByteArray &tag = {});
int addSignal(const QByteArray &signature);
void removeMethod(QMetaMethod::MethodType mtype, int index);
int getPropertyNotifyId(PySideProperty *property) const;
@@ -102,6 +71,10 @@ public:
const QMetaObject *m_baseObject = nullptr;
MetaObjects m_cachedMetaObjects;
bool m_dirty = true;
+
+private:
+ QMetaPropertyBuilder
+ createProperty(PySideProperty *property, const QByteArray &propertyName);
};
QMetaObjectBuilder *MetaObjectBuilderPrivate::ensureBuilder()
@@ -212,8 +185,8 @@ int MetaObjectBuilder::indexOfProperty(const QByteArray &name) const
static bool checkMethodSignature(const QByteArray &signature)
{
// Common mistake not to add parentheses to the signature.
- const int openParen = signature.indexOf('(');
- const int closingParen = signature.lastIndexOf(')');
+ const auto openParen = signature.indexOf('(');
+ const auto closingParen = signature.lastIndexOf(')');
const bool ok = openParen != -1 && closingParen != -1 && openParen < closingParen;
if (!ok) {
const QByteArray message =
@@ -239,13 +212,17 @@ int MetaObjectBuilder::addSlot(const char *signature)
}
int MetaObjectBuilderPrivate::addSlot(const QByteArray &signature,
- const QByteArray &type)
+ const QByteArray &type,
+ const QByteArray &tag)
{
if (!checkMethodSignature(signature))
return -1;
m_dirty = true;
QMetaMethodBuilder methodBuilder = ensureBuilder()->addSlot(signature);
- methodBuilder.setReturnType(type);
+ if (!type.isEmpty() && type != "void"_ba)
+ methodBuilder.setReturnType(type);
+ if (!tag.isEmpty())
+ methodBuilder.setTag(tag);
return m_baseObject->methodCount() + methodBuilder.index();
}
@@ -300,6 +277,35 @@ int MetaObjectBuilderPrivate::getPropertyNotifyId(PySideProperty *property) cons
return notifyId;
}
+QMetaPropertyBuilder
+ MetaObjectBuilderPrivate::createProperty(PySideProperty *property,
+ const QByteArray &propertyName)
+{
+ int propertyNotifyId = getPropertyNotifyId(property);
+ if (propertyNotifyId >= 0)
+ propertyNotifyId -= m_baseObject->methodCount();
+
+ // For QObject-derived Python types, retrieve the meta type registered
+ // by name from the qmlRegisterType, if there is one. This is required for
+ // grouped QML properties to work.
+ auto *builder = ensureBuilder();
+ auto *typeObject = Property::getTypeObject(property);
+ if (typeObject != nullptr && PyType_Check(typeObject)) {
+ auto *pyTypeObject = reinterpret_cast<PyTypeObject *>(typeObject);
+ if (qstrncmp(pyTypeObject->tp_name, "PySide", 6) != 0
+ && PySide::isQObjectDerived(pyTypeObject, false)) {
+ const QByteArray pyType(pyTypeObject->tp_name);
+ const auto metaType = QMetaType::fromName(pyType + '*');
+ if (metaType.isValid()) {
+ return builder->addProperty(propertyName, pyType,
+ metaType, propertyNotifyId);
+ }
+ }
+ }
+ return builder->addProperty(propertyName, property->d->typeName,
+ propertyNotifyId);
+}
+
int MetaObjectBuilderPrivate::addProperty(const QByteArray &propertyName,
PyObject *data)
{
@@ -307,13 +313,9 @@ int MetaObjectBuilderPrivate::addProperty(const QByteArray &propertyName,
if (index != -1)
return index;
- PySideProperty *property = reinterpret_cast<PySideProperty *>(data);
- int propertyNotifyId = getPropertyNotifyId(property);
- if (propertyNotifyId >= 0)
- propertyNotifyId -= m_baseObject->methodCount();
- auto newProperty =
- ensureBuilder()->addProperty(propertyName, property->d->typeName,
- propertyNotifyId);
+ auto *property = reinterpret_cast<PySideProperty *>(data);
+ auto newProperty = createProperty(property, propertyName);
+
// Adding property attributes
newProperty.setReadable(PySide::Property::isReadable(property));
newProperty.setWritable(PySide::Property::isWritable(property));
@@ -455,6 +457,107 @@ const QMetaObject *MetaObjectBuilder::update()
return m_d->update();
}
+static void formatEnum(QTextStream &str, const QMetaEnum &e)
+{
+ str << '"' << e.name() << "\" {";
+ for (int k = 0, cnt = e.keyCount(); k < cnt; ++k) {
+ if (k)
+ str << ", ";
+ str << e.key(k);
+ }
+ str << "}";
+}
+
+static void formatProperty(QTextStream &str, const QMetaProperty &p)
+{
+ str << '"' << p.name() << "\", " << p.typeName();
+ if (p.isWritable())
+ str << " [writeable]";
+ if (p.isResettable())
+ str << " [resettable]";
+ if (p.isConstant())
+ str << " [constant]";
+ if (p.isFinal())
+ str << " [final]";
+ if (p.isDesignable())
+ str << " [designable]";
+ auto sig = p.notifySignal();
+ if (sig.isValid())
+ str << ", notify=" << sig.name();
+}
+
+static void formatMethod(QTextStream &str, const QMetaMethod &m)
+{
+ str << "type=";
+ switch (m.methodType()) {
+ case QMetaMethod::Method:
+ str << "Method";
+ break;
+ case QMetaMethod::Signal:
+ str << "Signal";
+ break;
+ case QMetaMethod::Slot:
+ str << "Slot";
+ break;
+ case QMetaMethod::Constructor:
+ str << "Constructor";
+ break;
+ }
+
+ str << ", signature="
+ << m.methodSignature();
+ const QByteArrayList parms = m.parameterTypes();
+ if (!parms.isEmpty())
+ str << ", parameters=" << parms.join(", ");
+}
+
+QString MetaObjectBuilder::formatMetaObject(const QMetaObject *metaObject)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "PySide" << QT_VERSION_MAJOR << ".QtCore.QMetaObject(\""
+ << metaObject->className() << '"';
+ if (auto *s = metaObject->superClass())
+ str << " inherits \"" << s->className() << '"';
+ str << ":\n";
+
+ int offset = metaObject->enumeratorOffset();
+ int count = metaObject->enumeratorCount();
+ if (offset < count) {
+ str << "Enumerators:\n";
+ for (int e = offset; e < count; ++e) {
+ str << " #" << e << ' ';
+ formatEnum(str, metaObject->enumerator(e));
+ str << '\n';
+ }
+ }
+
+ offset = metaObject->propertyOffset();
+ count = metaObject->propertyCount();
+ if (offset < count) {
+ str << "Properties:\n";
+ for (int p = offset; p < count; ++p) {
+ str << " #" << p << ' ';
+ formatProperty(str, metaObject->property(p));
+ str << '\n';
+ }
+ }
+
+ offset = metaObject->methodOffset();
+ count = metaObject->methodCount();
+ if (offset < count) {
+ str << "Methods:\n";
+ for (int m = offset; m < count; ++m) {
+ str << " #" << m << ' ';
+ formatMethod(str, metaObject->method(m));
+ str << '\n';
+ }
+ }
+
+ str << ')';
+ return result;
+}
+
using namespace Shiboken;
void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
@@ -466,19 +569,18 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
// existing connections.
const PyObject *mro = type->tp_mro;
const Py_ssize_t basesCount = PyTuple_GET_SIZE(mro);
- PyTypeObject *qObjectType = Conversions::getPythonTypeObject("QObject*");
std::vector<PyTypeObject *> basesToCheck;
// Prepend the actual type that we are parsing.
basesToCheck.reserve(1u + basesCount);
basesToCheck.push_back(type);
- auto sbkObjTypeF = reinterpret_cast<PyTypeObject *>(SbkObject_TypeF());
+ auto sbkObjTypeF = SbkObject_TypeF();
auto baseObjType = reinterpret_cast<PyTypeObject *>(&PyBaseObject_Type);
for (Py_ssize_t i = 0; i < basesCount; ++i) {
auto baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i));
if (baseType != sbkObjTypeF && baseType != baseObjType
- && PyType_IsSubtype(baseType, qObjectType) == 0) {
+ && !PySide::isQObjectDerived(baseType, false)) {
basesToCheck.push_back(baseType);
}
}
@@ -487,7 +589,8 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
// Leave the properties to be registered after signals because they may depend on
// notify signals.
for (PyTypeObject *baseType : basesToCheck) {
- PyObject *attrs = baseType->tp_dict;
+ AutoDecRef tpDict(PepType_GetDict(baseType));
+ PyObject *attrs = tpDict.object();
PyObject *key = nullptr;
PyObject *value = nullptr;
Py_ssize_t pos = 0;
@@ -495,64 +598,51 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
while (PyDict_Next(attrs, &pos, &key, &value)) {
if (Signal::checkType(value)) {
// Register signals.
- auto data = reinterpret_cast<PySideSignal *>(value);
- if (data->data->signalName.isEmpty())
- data->data->signalName = String::toCString(key);
- for (const auto &s : data->data->signatures) {
- const auto sig = data->data->signalName + '(' + s.signature + ')';
+ auto *data = reinterpret_cast<PySideSignal *>(value)->data;
+ if (data->signalName.isEmpty())
+ data->signalName = String::toCString(key);
+ for (const auto &s : data->signatures) {
+ const auto sig = data->signalName + '(' + s.signature + ')';
if (m_baseObject->indexOfSignal(sig) == -1) {
// Registering the parameterNames to the QMetaObject (PYSIDE-634)
// from:
// Signal(..., arguments=['...', ...]
// the arguments are now on data-data->signalArguments
- if (!data->data->signalArguments->isEmpty()) {
- m_builder->addSignal(sig).setParameterNames(*data->data->signalArguments);
- } else {
- m_builder->addSignal(sig);
- }
+ auto builder = m_builder->addSignal(sig);
+ if (!data->signalArguments.isEmpty())
+ builder.setParameterNames(data->signalArguments);
}
}
}
}
}
- AutoDecRef slotAttrName(String::fromCString(PYSIDE_SLOT_LIST_ATTR));
+ PyObject *slotAttrName = PySide::PySideMagicName::slot_list_attr();
// PYSIDE-315: Now take care of the rest.
// Signals and slots should be separated, unless the types are modified, later.
// We check for this using "is_sorted()". Sorting no longer happens at all.
for (PyTypeObject *baseType : basesToCheck) {
- PyObject *attrs = baseType->tp_dict;
+ AutoDecRef tpDict(PepType_GetDict(baseType));
+ PyObject *attrs = tpDict.object();
PyObject *key = nullptr;
PyObject *value = nullptr;
Py_ssize_t pos = 0;
while (PyDict_Next(attrs, &pos, &key, &value)) {
if (Property::checkType(value)) {
- const int index = m_baseObject->indexOfProperty(String::toCString(key));
+ const QByteArray name = String::toCString(key);
+ const int index = m_baseObject->indexOfProperty(name);
if (index == -1)
- addProperty(String::toCString(key), value);
- } else if (Py_TYPE(value)->tp_call != nullptr) {
+ addProperty(name, value);
+ } else if (PepType_GetSlot(Py_TYPE(value), Py_tp_call) != nullptr) {
// PYSIDE-198: PyFunction_Check does not work with Nuitka.
// 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 *pySignature = PyList_GET_ITEM(signatureList, i);
- QByteArray signature(String::toCString(pySignature));
- // Split the slot type and its signature.
- QByteArray type;
- const int spacePos = signature.indexOf(' ');
- if (spacePos != -1) {
- type = signature.left(spacePos);
- signature.remove(0, spacePos + 1);
- }
- const int index = m_baseObject->indexOfSlot(signature);
- if (index == -1) {
- if (type.isEmpty() || type == "void")
- addSlot(signature);
- else
- addSlot(signature, type);
- }
+ auto *capsule = PyObject_GetAttr(value, slotAttrName);
+ const auto *entryList = PySide::Slot::dataListFromCapsule(capsule);
+ for (const auto &e : *entryList) {
+ if (m_baseObject->indexOfSlot(e.signature) == -1)
+ addSlot(e.signature, e.resultType, e.tag);
}
}
}
@@ -570,16 +660,15 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
AutoDecRef items(PyMapping_Items(members));
Py_ssize_t nr_items = PySequence_Length(items);
- QList<QPair<QByteArray, int> > entries;
+ QList<std::pair<QByteArray, int> > entries;
for (Py_ssize_t idx = 0; idx < nr_items; ++idx) {
AutoDecRef item(PySequence_GetItem(items, idx));
AutoDecRef key(PySequence_GetItem(item, 0));
AutoDecRef member(PySequence_GetItem(item, 1));
AutoDecRef value(PyObject_GetAttr(member, Shiboken::PyName::value()));
auto ckey = String::toCString(key);
- auto ivalue = PyInt_AsSsize_t(value); // int/long cheating
- auto thing = QPair<QByteArray, int>(ckey, int(ivalue));
- entries.push_back(thing);
+ auto ivalue = PyLong_AsSsize_t(value);
+ entries.push_back(std::make_pair(ckey, int(ivalue)));
}
addEnumerator(name, isFlag, true, entries);
}