diff options
Diffstat (limited to 'sources/pyside6/PySide6/glue/qtwidgets.cpp')
-rw-r--r-- | sources/pyside6/PySide6/glue/qtwidgets.cpp | 345 |
1 files changed, 236 insertions, 109 deletions
diff --git a/sources/pyside6/PySide6/glue/qtwidgets.cpp b/sources/pyside6/PySide6/glue/qtwidgets.cpp index ca9acb349..1b3e94016 100644 --- a/sources/pyside6/PySide6/glue/qtwidgets.cpp +++ b/sources/pyside6/PySide6/glue/qtwidgets.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2018 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) 2018 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 /********************************************************************* * INJECT CODE @@ -55,8 +19,9 @@ Shiboken::Object::releaseOwnership(%PYARG_0); // @snippet qtreewidgetitemiterator-value // @snippet qgraphicsitem -PyObject *userTypeConstant = PyInt_FromLong(QGraphicsItem::UserType); -PyDict_SetItemString(reinterpret_cast<PyTypeObject *>(Sbk_QGraphicsItem_TypeF())->tp_dict, "UserType", userTypeConstant); +PyObject *userTypeConstant = PyLong_FromLong(QGraphicsItem::UserType); +tpDict.reset(PepType_GetDict(Sbk_QGraphicsItem_TypeF())); +PyDict_SetItemString(tpDict.object(), "UserType", userTypeConstant); // @snippet qgraphicsitem // @snippet qgraphicsitem-scene-return-parenting @@ -96,18 +61,74 @@ QFormLayout::ItemRole _role; %CPPSELF->%FUNCTION_NAME(%ARGUMENT_NAMES, &_row, &_role); %PYARG_0 = PyTuple_New(2); PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[int](_row)); +// On the C++ side, *rolePtr is not set if row == -1, in which case on +// the Python side this gets converted to a random value outside the +// enum range. Fix this by setting _role to a default value here. +if (_row == -1) + _role = QFormLayout::LabelRole; PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[QFormLayout::ItemRole](_role)); // @snippet qformlayout-fix-args // @snippet qfiledialog-return +%BEGIN_ALLOW_THREADS %RETURN_TYPE retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, &%5, %6); +%END_ALLOW_THREADS %PYARG_0 = PyTuple_New(2); PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[%RETURN_TYPE](retval_)); -PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[%ARG5_TYPE](%5)); +PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[QString](%5)); // @snippet qfiledialog-return +// @snippet qwidget-addaction-glue +static PyObject *connectAction(QAction *action, PyObject *callback) +{ + PyObject *pyAct = %CONVERTTOPYTHON[QAction *](action); + Shiboken::AutoDecRef result(PyObject_CallMethod(pyAct, "connect", "OsO", + pyAct, + SIGNAL(triggered()), callback)); + if (result.isNull()) { + Py_DECREF(pyAct); + return nullptr; + } + return pyAct; +} + +static inline PyObject *addActionWithPyObject(QWidget *self, const QString &text, + PyObject *callback) +{ + QAction *act = self->addAction(text); + return connectAction(act, callback); +} + +static inline PyObject *addActionWithPyObject(QWidget *self, const QIcon &icon, const QString &text, + PyObject *callback) +{ + auto *act = self->addAction(icon, text); + return connectAction(act, callback); +} + +static inline PyObject *addActionWithPyObject(QWidget *self, const QString &text, + const QKeySequence &shortcut, + PyObject *callback) +{ + QAction *act = self->addAction(text, shortcut); + return connectAction(act, callback); +} + +static inline PyObject *addActionWithPyObject(QWidget *self, const QIcon &icon, + const QString &text, + const QKeySequence &shortcut, + PyObject *callback) +{ + QAction *act = self->addAction(icon, text, shortcut); + return connectAction(act, callback); +} +// @snippet qwidget-addaction-glue + +// FIXME PYSIDE7: Remove in favor of widgets methods // @snippet qmenu-glue -inline PyObject *addActionWithPyObject(QMenu *self, const QIcon &icon, const QString &text, PyObject *callback, const QKeySequence &shortcut) +inline PyObject *addMenuActionWithPyObject(QMenu *self, const QIcon &icon, + const QString &text, PyObject *callback, + const QKeySequence &shortcut) { QAction *act = self->addAction(text); @@ -132,18 +153,35 @@ inline PyObject *addActionWithPyObject(QMenu *self, const QIcon &icon, const QSt } // @snippet qmenu-glue +// addAction(QString,PyObject*,QKeySequence) FIXME PYSIDE7 deprecated // @snippet qmenu-addaction-1 -%PYARG_0 = addActionWithPyObject(%CPPSELF, QIcon(), %1, %2, %3); +%PYARG_0 = addMenuActionWithPyObject(%CPPSELF, QIcon(), %1, %2, %3); // @snippet qmenu-addaction-1 +// addAction(QIcon,QString,PyObject*,QKeySequence) FIXME PYSIDE7 deprecated // @snippet qmenu-addaction-2 -%PYARG_0 = addActionWithPyObject(%CPPSELF, %1, %2, %3, %4); +%PYARG_0 = addMenuActionWithPyObject(%CPPSELF, %1, %2, %3, %4); // @snippet qmenu-addaction-2 // @snippet qmenu-addaction-3 %CPPSELF.addAction(%1); // @snippet qmenu-addaction-3 +// addAction(QString,PyObject*) +// @snippet qwidget-addaction-2 +%PYARG_0 = addActionWithPyObject(%CPPSELF, %1, %2); +// @snippet qwidget-addaction-2 + +// addAction(QString,QKeySequence,PyObject*) or addAction(QIcon,QString,PyObject*) +// @snippet qwidget-addaction-3 +%PYARG_0 = addActionWithPyObject(%CPPSELF, %1, %2, %3); +// @snippet qwidget-addaction-3 + +// addAction(QIcon,QString,QKeySequence,PyObject*) +// @snippet qwidget-addaction-4 +%PYARG_0 = addActionWithPyObject(%CPPSELF, %1, %2, %3, %4); +// @snippet qwidget-addaction-4 + // @snippet qmenu-clear Shiboken::BindingManager &bm = Shiboken::BindingManager::instance(); const auto &actions = %CPPSELF.actions(); @@ -158,30 +196,6 @@ for (auto *act : actions) { } // @snippet qmenu-clear -// @snippet qmenubar-glue -inline PyObject * -addActionWithPyObject(QMenuBar *self, const QString &text, PyObject *callback) -{ - QAction *act = self->addAction(text); - - self->addAction(act); - - PyObject *pyAct = %CONVERTTOPYTHON[QAction *](act); - PyObject *result = PyObject_CallMethod(pyAct, "connect", "OsO", - pyAct, - SIGNAL(triggered(bool)), callback); - - if (result == nullptr || result == Py_False) { - if (result) - Py_DECREF(result); - Py_DECREF(pyAct); - return nullptr; - } - - return pyAct; -} -// @snippet qmenubar-glue - // @snippet qmenubar-clear const auto &actions = %CPPSELF.actions(); for (auto *act : actions) { @@ -191,14 +205,6 @@ for (auto *act : actions) { } // @snippet qmenubar-clear -// @snippet qmenubar-addaction-1 -%PYARG_0 = addActionWithPyObject(%CPPSELF, %1, %2); -// @snippet qmenubar-addaction-1 - -// @snippet qmenubar-addaction-2 -%CPPSELF.addAction(%1); -// @snippet qmenubar-addaction-2 - // @snippet qtoolbox-removeitem QWidget *_widget = %CPPSELF.widget(%1); if (_widget) { @@ -208,17 +214,24 @@ if (_widget) { // @snippet qtoolbox-removeitem // @snippet qlayout-help-functions +#ifndef _QLAYOUT_HELP_FUNCTIONS_ +#define _QLAYOUT_HELP_FUNCTIONS_ // Guard for jumbo builds + +static const char msgInvalidParameterAdd[] = + "Invalid parameter None passed to addLayoutOwnership()."; +static const char msgInvalidParameterRemoval[] = + "Invalid parameter None passed to removeLayoutOwnership()."; + void addLayoutOwnership(QLayout *layout, QLayoutItem *item); void removeLayoutOwnership(QLayout *layout, QWidget *widget); -inline QByteArray retrieveObjectName(PyObject *obj) -{ - Shiboken::AutoDecRef objName(PyObject_Str(obj)); - return Shiboken::String::toCString(objName); -} - inline void addLayoutOwnership(QLayout *layout, QWidget *widget) { + if (layout == nullptr || widget == nullptr) { + PyErr_SetString(PyExc_RuntimeError, msgInvalidParameterAdd); + return; + } + //transfer ownership to parent widget QWidget *lw = layout->parentWidget(); QWidget *pw = widget->parentWidget(); @@ -232,7 +245,9 @@ inline void addLayoutOwnership(QLayout *layout, QWidget *widget) if (!lw && !pw) { //keep the reference while the layout is orphan Shiboken::AutoDecRef pyParent(%CONVERTTOPYTHON[QWidget *](layout)); - Shiboken::Object::keepReference(reinterpret_cast<SbkObject *>(pyParent.object()), retrieveObjectName(pyParent).data(), pyChild, true); + Shiboken::Object::keepReference(reinterpret_cast<SbkObject *>(pyParent.object()), + retrieveObjectName(pyParent).constData(), + pyChild, true); } else { if (!lw) lw = pw; @@ -243,6 +258,11 @@ inline void addLayoutOwnership(QLayout *layout, QWidget *widget) inline void addLayoutOwnership(QLayout *layout, QLayout *other) { + if (layout == nullptr || other == nullptr) { + PyErr_SetString(PyExc_RuntimeError, msgInvalidParameterAdd); + return; + } + //transfer all children widgets from other to layout parent widget QWidget *parent = layout->parentWidget(); if (!parent) { @@ -250,7 +270,8 @@ inline void addLayoutOwnership(QLayout *layout, QLayout *other) Shiboken::AutoDecRef pyParent(%CONVERTTOPYTHON[QLayout *](layout)); Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QLayout *](other)); Shiboken::Object::keepReference(reinterpret_cast<SbkObject *>(pyParent.object()), - retrieveObjectName(pyParent).data(), pyChild, true); + retrieveObjectName(pyParent).constData(), + pyChild, true); return; } @@ -268,8 +289,11 @@ inline void addLayoutOwnership(QLayout *layout, QLayout *other) inline void addLayoutOwnership(QLayout *layout, QLayoutItem *item) { - if (!item) + + if (layout == nullptr || item == nullptr) { + PyErr_SetString(PyExc_RuntimeError, msgInvalidParameterAdd); return; + } if (QWidget *w = item->widget()) { addLayoutOwnership(layout, w); @@ -285,6 +309,11 @@ inline void addLayoutOwnership(QLayout *layout, QLayoutItem *item) static void removeWidgetFromLayout(QLayout *layout, QWidget *widget) { + if (layout == nullptr || widget == nullptr) { + PyErr_SetString(PyExc_RuntimeError, msgInvalidParameterRemoval); + return; + } + if (QWidget *parent = widget->parentWidget()) { //give the ownership to parent Shiboken::AutoDecRef pyParent(%CONVERTTOPYTHON[QWidget *](parent)); @@ -295,12 +324,18 @@ static void removeWidgetFromLayout(QLayout *layout, QWidget *widget) Shiboken::AutoDecRef pyParent(%CONVERTTOPYTHON[QWidget *](layout)); Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QWidget *](widget)); Shiboken::Object::removeReference(reinterpret_cast<SbkObject *>(pyParent.object()), - retrieveObjectName(pyParent).data(), pyChild); + retrieveObjectName(pyParent).constData(), + pyChild); } } inline void removeLayoutOwnership(QLayout *layout, QLayoutItem *item) { + if (layout == nullptr || item == nullptr) { + PyErr_SetString(PyExc_RuntimeError, msgInvalidParameterRemoval); + return; + } + if (QWidget *w = item->widget()) { removeWidgetFromLayout(layout, w); } else { @@ -316,8 +351,10 @@ inline void removeLayoutOwnership(QLayout *layout, QLayoutItem *item) inline void removeLayoutOwnership(QLayout *layout, QWidget *widget) { - if (!widget) + if (layout == nullptr || widget == nullptr) { + PyErr_SetString(PyExc_RuntimeError, msgInvalidParameterRemoval); return; + } for (int i = 0, i_max = layout->count(); i < i_max; ++i) { QLayoutItem *item = layout->itemAt(i); @@ -327,15 +364,17 @@ inline void removeLayoutOwnership(QLayout *layout, QWidget *widget) removeLayoutOwnership(layout, item); } } +#endif // _QLAYOUT_HELP_FUNCTIONS_ // @snippet qlayout-help-functions // @snippet qlayout-setalignment %CPPSELF.setAlignment(%1); // @snippet qlayout-setalignment -// @snippet addownership-0 -addLayoutOwnership(%CPPSELF, %0); -// @snippet addownership-0 +// @snippet addownership-item-at +if (%0 != nullptr) + addLayoutOwnership(%CPPSELF, %0); +// @snippet addownership-item-at // @snippet addownership-1 addLayoutOwnership(%CPPSELF, %1); @@ -382,7 +421,7 @@ Shiboken::BindingManager &bm = Shiboken::BindingManager::instance(); for (auto *item : items) { SbkObject *obj = bm.retrieveWrapper(item); if (obj) { - if (reinterpret_cast<PyObject *>(obj)->ob_refcnt > 1) // If the refcnt is 1 the object will vannish anyway. + if (Py_REFCNT(reinterpret_cast<PyObject *>(obj)) > 1) // If the refcnt is 1 the object will vannish anyway. Shiboken::Object::invalidate(obj); Shiboken::Object::removeParent(obj); } @@ -430,13 +469,18 @@ for (int i = 0, count = %CPPSELF.count(); i < count; ++i) { %CPPSELF.%FUNCTION_NAME(); // @snippet qlistwidget-clear -// @snippet qwidget-glue -static QString retrieveObjectName(PyObject *obj) +// @snippet qwidget-retrieveobjectname +#ifndef _RETRIEVEOBJECTNAME_ +#define _RETRIEVEOBJECTNAME_ // Guard for jumbo builds +static QByteArray retrieveObjectName(PyObject *obj) { Shiboken::AutoDecRef objName(PyObject_Str(obj)); - return QString(Shiboken::String::toCString(objName)); + return Shiboken::String::toCString(objName); } +#endif +// @snippet qwidget-retrieveobjectname +// @snippet qwidget-glue // Transfer objects ownership from layout to widget static inline void qwidgetReparentLayout(QWidget *parent, QLayout *layout) @@ -464,7 +508,8 @@ static inline void qwidgetReparentLayout(QWidget *parent, QLayout *layout) Shiboken::Object::setParent(pyParent, pyChild); //remove previous references Shiboken::Object::keepReference(reinterpret_cast<SbkObject *>(pyChild.object()), - qPrintable(retrieveObjectName(pyChild)), Py_None); + retrieveObjectName(pyChild).constData(), + Py_None); } static inline void qwidgetSetLayout(QWidget *self, QLayout *layout) @@ -502,15 +547,20 @@ Shiboken::Object::keepReference(reinterpret_cast<SbkObject *>(%PYSELF), "__style // @snippet qwidget-style QStyle *myStyle = %CPPSELF->style(); if (myStyle && qApp) { -%PYARG_0 = %CONVERTTOPYTHON[QStyle *](myStyle); + bool keepReference = true; + %PYARG_0 = %CONVERTTOPYTHON[QStyle *](myStyle); QStyle *appStyle = qApp->style(); if (appStyle == myStyle) { Shiboken::AutoDecRef pyApp(%CONVERTTOPYTHON[QApplication *](qApp)); - Shiboken::Object::setParent(pyApp, %PYARG_0); - Shiboken::Object::releaseOwnership(%PYARG_0); - } else { - Shiboken::Object::keepReference(reinterpret_cast<SbkObject *>(%PYSELF), "__style__", %PYARG_0); + // Do not set parentship when qApp is embedded + if (Shiboken::Object::wasCreatedByPython(reinterpret_cast<SbkObject *>(pyApp.object()))) { + Shiboken::Object::setParent(pyApp, %PYARG_0); + Shiboken::Object::releaseOwnership(%PYARG_0); + keepReference = false; + } } + if (keepReference) + Shiboken::Object::keepReference(reinterpret_cast<SbkObject *>(%PYSELF), "__style__", %PYARG_0); } // @snippet qwidget-style @@ -565,27 +615,25 @@ for (int i = 0, count = %CPPSELF.count(); i < count; ++i) { %CPPSELF.addAction(%1); // @snippet qlineedit-addaction -// @snippet qtoolbar-addaction-1 +// addAction(QIcon,QString,const QObject*,const char*,Qt::ConnectionType) +// @snippet qwidget-addaction-1 QAction *action = %CPPSELF.addAction(%1, %2); %PYARG_0 = %CONVERTTOPYTHON[QAction *](action); Shiboken::AutoDecRef result(PyObject_CallMethod(%PYARG_0, "connect", "OsO", %PYARG_0, SIGNAL(triggered()), %PYARG_3) ); -// @snippet qtoolbar-addaction-1 +// @snippet qwidget-addaction-1 -// @snippet qtoolbar-addaction-2 +// addAction(QString,const QObject*,const char*,Qt::ConnectionType) +// @snippet qwidget-addaction-2 QAction *action = %CPPSELF.addAction(%1); %PYARG_0 = %CONVERTTOPYTHON[QAction *](action); Shiboken::AutoDecRef result(PyObject_CallMethod(%PYARG_0, "connect", "OsO", %PYARG_0, SIGNAL(triggered()), %PYARG_2) ); -// @snippet qtoolbar-addaction-2 - -// @snippet qtoolbar-addaction-3 -%CPPSELF.addAction(%1); -// @snippet qtoolbar-addaction-3 +// @snippet qwidget-addaction-2 // @snippet qtoolbar-clear QList<PyObject *> lst; @@ -608,7 +656,7 @@ for (auto *act : actions) { } %CPPSELF.clear(); -for (auto *obj : qAsConst(lst)) { +for (auto *obj : std::as_const(lst)) { Shiboken::Object::invalidate(reinterpret_cast<SbkObject *>(obj)); Py_XDECREF(obj); } @@ -684,6 +732,85 @@ QAction *cppResult = %CPPSELF.exec(%1, %2, %3, %4); %PYARG_0 = %CONVERTTOPYTHON[QAction*](cppResult); // @snippet qmenu-exec-3 +// @snippet qstyleoption-typename +const char *styleOptionType(const QStyleOption *o) +{ + switch (o->type) { + case QStyleOption::SO_Default: + break; + case QStyleOption::SO_FocusRect: + return "QStyleOptionFocusRect"; + case QStyleOption::SO_Button: + return "QStyleOptionButton"; + case QStyleOption::SO_Tab: + return "QStyleOptionTab"; + case QStyleOption::SO_MenuItem: + return "QStyleOptionMenuItem"; + case QStyleOption::SO_Frame: + return "QStyleOptionFrame"; + case QStyleOption::SO_ProgressBar: + return "QStyleOptionProgressBar"; + case QStyleOption::SO_ToolBox: + return "QStyleOptionToolBox"; + case QStyleOption::SO_Header: + return "QStyleOptionHeader"; + case QStyleOption::SO_DockWidget: + return "QStyleOptionDockWidget"; + case QStyleOption::SO_ViewItem: + return "QStyleOptionViewItem"; + case QStyleOption::SO_TabWidgetFrame: + return "QStyleOptionTabWidgetFrame"; + case QStyleOption::SO_TabBarBase: + return "QStyleOptionTabBarBase"; + case QStyleOption::SO_RubberBand: + return "QStyleOptionRubberBand"; + case QStyleOption::SO_ToolBar: + return "QStyleOptionToolBar"; + case QStyleOption::SO_GraphicsItem: + return "QStyleOptionGraphicsItem"; + case QStyleOption::SO_Slider: + return "QStyleOptionSlider"; + case QStyleOption::SO_SpinBox: + return "QStyleOptionSpinBox"; + case QStyleOption::SO_ToolButton: + return "QStyleOptionToolButton"; + case QStyleOption::SO_ComboBox: + return "QStyleOptionComboBox"; + case QStyleOption::SO_TitleBar: + return "QStyleOptionTitleBar"; + case QStyleOption::SO_GroupBox: + return "QStyleOptionGroupBox"; + case QStyleOption::SO_SizeGrip: + return "QStyleOptionSizeGrip"; + default: + break; + } + return "QStyleOption"; +} +// @snippet qstyleoption-typename + +// @snippet qwizardpage-registerfield +auto *signalInst = reinterpret_cast<PySideSignalInstance *>(%PYARG_4); +const auto data = PySide::Signal::getEmitterData(signalInst); +if (data.methodIndex == -1) { + PyErr_SetString(PyExc_RuntimeError, "QWizardPage::registerField(): Unable to retrieve signal emitter."); + return nullptr; +} +const auto method = data.emitter->metaObject()->method(data.methodIndex); +const QByteArray signature = QByteArrayLiteral("2") + method.methodSignature(); +%BEGIN_ALLOW_THREADS +%CPPSELF.%FUNCTION_NAME(%1, %2, %3, signature.constData()); +%END_ALLOW_THREADS +// @snippet qwizardpage-registerfield + +// The constructor heuristics generate setting a parent-child relationship +// when creating a QDialog with parent. This causes the dialog to leak +// when it synchronous exec() is used instead of asynchronous show(). +// In that case, remove the parent-child relationship. +// @snippet qdialog-exec-remove-parent-relation +Shiboken::Object::removeParent(reinterpret_cast<SbkObject *>(%PYSELF)); +// @snippet qdialog-exec-remove-parent-relation + /********************************************************************* * CONVERSIONS ********************************************************************/ |