diff options
Diffstat (limited to 'sources/pyside6/libpyside/pysideclassinfo.cpp')
-rw-r--r-- | sources/pyside6/libpyside/pysideclassinfo.cpp | 231 |
1 files changed, 91 insertions, 140 deletions
diff --git a/sources/pyside6/libpyside/pysideclassinfo.cpp b/sources/pyside6/libpyside/pysideclassinfo.cpp index 2a9914a68..698cb1c76 100644 --- a/sources/pyside6/libpyside/pysideclassinfo.cpp +++ b/sources/pyside6/libpyside/pysideclassinfo.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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) 2016 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 <sbkpython.h> @@ -50,158 +14,145 @@ extern "C" { -static PyObject *classInfoTpNew(PyTypeObject *subtype, PyObject *args, PyObject *kwds); -static int classInfoTpInit(PyObject *, PyObject *, PyObject *); -static void classInfoFree(void *); -static PyObject *classCall(PyObject *, PyObject *, PyObject *); - -static PyType_Slot PySideClassInfoType_slots[] = { - {Py_tp_call, (void *)classCall}, - {Py_tp_init, (void *)classInfoTpInit}, - {Py_tp_new, (void *)classInfoTpNew}, - {Py_tp_free, (void *)classInfoFree}, - {Py_tp_dealloc, (void *)Sbk_object_dealloc}, - {0, 0} -}; -static PyType_Spec PySideClassInfoType_spec = { - "2:PySide6.QtCore.ClassInfo", - sizeof(PySideClassInfo), - 0, - Py_TPFLAGS_DEFAULT, - PySideClassInfoType_slots, +static PyTypeObject *createClassInfoType() +{ + auto typeSlots = + PySide::ClassDecorator::Methods<PySide::ClassInfo::ClassInfoPrivate>::typeSlots(); + + PyType_Spec PySideClassInfoType_spec = { + "2:PySide6.QtCore.ClassInfo", + sizeof(PySideClassDecorator), + 0, + Py_TPFLAGS_DEFAULT, + typeSlots.data()}; + return SbkType_FromSpec(&PySideClassInfoType_spec); }; - -PyTypeObject *PySideClassInfoTypeF(void) +PyTypeObject *PySideClassInfo_TypeF(void) { - static PyTypeObject *type = - reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&PySideClassInfoType_spec)); + static auto *type = createClassInfoType(); return type; } -PyObject *classCall(PyObject *self, PyObject *args, PyObject * /* kw */) -{ - if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) { - PyErr_Format(PyExc_TypeError, - "The ClassInfo decorator takes exactly 1 positional argument (%zd given)", - PyTuple_Size(args)); - return 0; - } +} // extern "C" - PySideClassInfo *data = reinterpret_cast<PySideClassInfo *>(self); - PySideClassInfoPrivate *pData = data->d; +namespace PySide::ClassInfo { - if (pData->m_alreadyWrapped) { - PyErr_SetString(PyExc_TypeError, "This instance of ClassInfo() was already used to wrap an object"); - return 0; - } +const char *ClassInfoPrivate::name() const +{ + return "ClassInfo"; +} + +PyObject *ClassInfoPrivate::tp_call(PyObject *self, PyObject *args, PyObject * /* kw */) +{ + PyObject *klass = tp_call_check(args, CheckMode::QObjectType); + if (klass == nullptr) + return nullptr; - PyObject *klass = PyTuple_GetItem(args, 0); - bool validClass = false; + auto *pData = DecoratorPrivate::get<ClassInfoPrivate>(self); - // This will sometimes segfault if you mistakenly use it on a function declaration - if (!PyType_Check(klass)) { - PyErr_SetString(PyExc_TypeError, "This decorator can only be used on class declarations"); - return 0; - } + if (pData->m_alreadyWrapped) + return PyErr_Format(PyExc_TypeError, "This instance of ClassInfo() was already used to wrap an object"); PyTypeObject *klassType = reinterpret_cast<PyTypeObject *>(klass); - if (Shiboken::ObjectType::checkType(klassType)) { - if (auto userData = PySide::retrieveTypeUserData(klassType)) { - PySide::MetaObjectBuilder &mo = userData->mo; - mo.addInfo(PySide::ClassInfo::getMap(data)); - pData->m_alreadyWrapped = true; - validClass = true; - } - } + if (!PySide::ClassInfo::setClassInfo(klassType, pData->m_data)) + return PyErr_Format(PyExc_TypeError, "This decorator can only be used on classes that are subclasses of QObject"); - if (!validClass) { - PyErr_SetString(PyExc_TypeError, "This decorator can only be used on classes that are subclasses of QObject"); - return 0; - } + pData->m_alreadyWrapped = true; Py_INCREF(klass); return klass; } -static PyObject *classInfoTpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */) +int ClassInfoPrivate::tp_init(PyObject *self, PyObject *args, PyObject *kwds) { - PySideClassInfo *me = reinterpret_cast<PySideClassInfo *>(subtype->tp_alloc(subtype, 0)); - me->d = new PySideClassInfoPrivate; - - me->d->m_alreadyWrapped = false; - - return reinterpret_cast<PyObject *>(me); -} + PyObject *infoDict = nullptr; + auto size = PyTuple_Size(args); + if (size == 1 && kwds == nullptr) { + PyObject *tmp = PyTuple_GET_ITEM(args, 0); + if (PyDict_Check(tmp)) + infoDict = tmp; + } else if (size == 0 && kwds && PyDict_Check(kwds)) { + infoDict = kwds; + } -int classInfoTpInit(PyObject *self, PyObject *args, PyObject *kwds) -{ - if (PyTuple_Check(args) && PyTuple_Size(args) > 0) { - PyErr_Format(PyExc_TypeError, "ClassInfo() takes exactly 0 positional arguments (%zd given)", PyTuple_Size(args)); + if (infoDict == nullptr) { + PyErr_Format(PyExc_TypeError, "ClassInfo() takes either keyword argument(s) or " + "a single dictionary argument"); return -1; } - PySideClassInfo *data = reinterpret_cast<PySideClassInfo *>(self); - PySideClassInfoPrivate *pData = data->d; + auto *pData = DecoratorPrivate::get<ClassInfoPrivate>(self); - PyObject *key; - PyObject *value; + PyObject *key{}; + PyObject *value{}; Py_ssize_t pos = 0; // PyDict_Next causes a segfault if kwds is empty - if (kwds && PyDict_Check(kwds) && PyDict_Size(kwds) > 0) { - while (PyDict_Next(kwds, &pos, &key, &value)) { + if (PyDict_Size(infoDict) > 0) { + while (PyDict_Next(infoDict, &pos, &key, &value)) { if (Shiboken::String::check(key) && Shiboken::String::check(value)) { - pData->m_data[Shiboken::String::toCString(key)] = Shiboken::String::toCString(value); + ClassInfo info{Shiboken::String::toCString(key), + Shiboken::String::toCString(value)}; + pData->m_data.append(info); } else { - PyErr_SetString(PyExc_TypeError, "All keys and values provided to ClassInfo() must be strings"); + PyErr_SetString(PyExc_TypeError, "All keys and values provided to ClassInfo() " + "must be strings"); return -1; } } } - return PyErr_Occurred() ? -1 : 0; -} - -void classInfoFree(void *self) -{ - auto pySelf = reinterpret_cast<PyObject *>(self); - auto data = reinterpret_cast<PySideClassInfo *>(self); - - delete data->d; - Py_TYPE(pySelf)->tp_base->tp_free(self); + return PyErr_Occurred() != nullptr ? -1 : 0; } - -} // extern "C" - - -namespace PySide { namespace ClassInfo { - static const char *ClassInfo_SignatureStrings[] = { "PySide6.QtCore.ClassInfo(self,**info:typing.Dict[str,str])", nullptr}; // Sentinel void init(PyObject *module) { - if (InitSignatureStrings(PySideClassInfoTypeF(), ClassInfo_SignatureStrings) < 0) + if (InitSignatureStrings(PySideClassInfo_TypeF(), ClassInfo_SignatureStrings) < 0) return; - Py_INCREF(PySideClassInfoTypeF()); - PyModule_AddObject(module, "ClassInfo", reinterpret_cast<PyObject *>(PySideClassInfoTypeF())); + Py_INCREF(PySideClassInfo_TypeF()); + PyModule_AddObject(module, "ClassInfo", reinterpret_cast<PyObject *>(PySideClassInfo_TypeF())); } bool checkType(PyObject *pyObj) { - if (pyObj) - return PyType_IsSubtype(Py_TYPE(pyObj), PySideClassInfoTypeF()); - return false; + return pyObj != nullptr + && PyType_IsSubtype(Py_TYPE(pyObj), PySideClassInfo_TypeF()) != 0; } -QMap<QByteArray, QByteArray> getMap(PySideClassInfo *obj) +ClassInfoList getClassInfoList(PyObject *decorator) { - return obj->d->m_data; + auto *pData = PySide::ClassDecorator::DecoratorPrivate::get<ClassInfoPrivate>(decorator); + return pData->m_data; +} + +bool setClassInfo(PyTypeObject *type, const QByteArray &key, + const QByteArray &value) +{ + auto *userData = PySide::retrieveTypeUserData(type); + const bool result = userData != nullptr; + if (result) { + PySide::MetaObjectBuilder &mo = userData->mo; + mo.addInfo(key, value); + } + return result; +} + +bool setClassInfo(PyTypeObject *type, const ClassInfoList &list) +{ + auto *userData = PySide::retrieveTypeUserData(type); + const bool result = userData != nullptr; + if (result) { + PySide::MetaObjectBuilder &mo = userData->mo; + for (const auto &info : list) + mo.addInfo(info.key.constData(), info.value.constData()); + } + return result; } -} //namespace Property -} //namespace PySide +} //namespace PySide::ClassInfo |