From 6caa48a47b037a1a78519b7a431d5a412b156a53 Mon Sep 17 00:00:00 2001 From: joshochoa Date: Sun, 30 Oct 2022 11:18:43 -0700 Subject: [PATCH 1/8] added PySide6 shiboken6 support --- Qt.py | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 104 insertions(+), 5 deletions(-) diff --git a/Qt.py b/Qt.py index 4ed2bea0..b2833809 100644 --- a/Qt.py +++ b/Qt.py @@ -730,12 +730,14 @@ def messageOutputHandler(*args): passObject = messageOutputHandler if handler else handler if Qt.IsPySide or Qt.IsPyQt4: return Qt._QtCore.qInstallMsgHandler(passObject) - elif Qt.IsPySide2 or Qt.IsPyQt5: + elif Qt.IsPySide2 or Qt.IsPyQt5 or Qt.IsPySide6: return Qt._QtCore.qInstallMessageHandler(passObject) def _getcpppointer(object): - if hasattr(Qt, "_shiboken2"): + if hasattr(Qt, "_shiboken6"): + return getattr(Qt, "_shiboken6").getCppPointer(object)[0] + elif hasattr(Qt, "_shiboken2"): return getattr(Qt, "_shiboken2").getCppPointer(object)[0] elif hasattr(Qt, "_shiboken"): return getattr(Qt, "_shiboken").getCppPointer(object)[0] @@ -773,6 +775,8 @@ def _wrapinstance(ptr, base=None): func = getattr(Qt, "_sip").wrapinstance elif Qt.IsPySide2: func = getattr(Qt, "_shiboken2").wrapInstance + elif Qt.IsPySide6: + func = getattr(Qt, "_shiboken6").wrapInstance elif Qt.IsPySide: func = getattr(Qt, "_shiboken").wrapInstance else: @@ -812,7 +816,10 @@ def _isvalid(object): object (QObject): QObject to check the validity of. """ - if hasattr(Qt, "_shiboken2"): + if hasattr(Qt, "_shiboken6"): + return getattr(Qt, "_shiboken6").isValid(object) + + elif hasattr(Qt, "_shiboken2"): return getattr(Qt, "_shiboken2").isValid(object) elif hasattr(Qt, "_shiboken"): @@ -1001,6 +1008,34 @@ def createWidget(self, class_name, parent=None, name=""): """ _misplaced_members = { + "PySide6": { + "QtCore.QStringListModel": "QtCore.QStringListModel", + "QtGui.QStringListModel": "QtCore.QStringListModel", + "QtCore.Property": "QtCore.Property", + "QtCore.Signal": "QtCore.Signal", + "QtCore.Slot": "QtCore.Slot", + "QtCore.QAbstractProxyModel": "QtCore.QAbstractProxyModel", + "QtCore.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel", + "QtCore.QItemSelection": "QtCore.QItemSelection", + "QtCore.QItemSelectionModel": "QtCore.QItemSelectionModel", + "QtCore.QItemSelectionRange": "QtCore.QItemSelectionRange", + "QtUiTools.QUiLoader": ["QtCompat.loadUi", _loadUi], + "shiboken6.wrapInstance": ["QtCompat.wrapInstance", _wrapinstance], + "shiboken6.getCppPointer": ["QtCompat.getCppPointer", _getcpppointer], + "shiboken6.isValid": ["QtCompat.isValid", _isvalid], + "QtWidgets.qApp": "QtWidgets.QApplication.instance()", + "QtCore.QCoreApplication.translate": [ + "QtCompat.translate", _translate + ], + "QtWidgets.QApplication.translate": [ + "QtCompat.translate", _translate + ], + "QtCore.qInstallMessageHandler": [ + "QtCompat.qInstallMessageHandler", _qInstallMessageHandler + ], + "QtWidgets.QStyleOptionViewItem": "QtCompat.QStyleOptionViewItemV4", + "QtMultimedia.QSound": "QtMultimedia.QSound", + }, "PySide2": { "QtCore.QStringListModel": "QtCore.QStringListModel", "QtGui.QStringListModel": "QtCore.QStringListModel", @@ -1144,6 +1179,26 @@ def createWidget(self, class_name, parent=None, name=""): } """ _compatibility_members = { + "PySide6": { + "QWidget": { + "grab": "QtWidgets.QWidget.grab", + }, + "QHeaderView": { + "sectionsClickable": "QtWidgets.QHeaderView.sectionsClickable", + "setSectionsClickable": + "QtWidgets.QHeaderView.setSectionsClickable", + "sectionResizeMode": "QtWidgets.QHeaderView.sectionResizeMode", + "setSectionResizeMode": + "QtWidgets.QHeaderView.setSectionResizeMode", + "sectionsMovable": "QtWidgets.QHeaderView.sectionsMovable", + "setSectionsMovable": "QtWidgets.QHeaderView.setSectionsMovable", + }, + "QFileDialog": { + "getOpenFileName": "QtWidgets.QFileDialog.getOpenFileName", + "getOpenFileNames": "QtWidgets.QFileDialog.getOpenFileNames", + "getSaveFileName": "QtWidgets.QFileDialog.getSaveFileName", + }, + }, "PySide2": { "QWidget": { "grab": "QtWidgets.QWidget.grab", @@ -1421,6 +1476,48 @@ def _build_compatibility_members(binding, decorators=None): compat_class = type(classname, (_QtCompat,), attrs) setattr(Qt.QtCompat, classname, compat_class) +def _pyside6(): + """Initialise PySide6 + + These functions serve to test the existence of a binding + along with set it up in such a way that it aligns with + the final step; adding members from the original binding + to Qt.py + + """ + + import PySide6 as module + extras = ["QtUiTools"] + try: + import shiboken6 + extras.append("shiboken6") + except ImportError as e: + print("ImportError: %s" % e) + + _setup(module, extras) + Qt.__binding_version__ = module.__version__ + + if hasattr(Qt, "_shiboken6"): + Qt.QtCompat.wrapInstance = _wrapinstance + Qt.QtCompat.getCppPointer = _getcpppointer + Qt.QtCompat.delete = shiboken6.delete + + if hasattr(Qt, "_QtUiTools"): + Qt.QtCompat.loadUi = _loadUi + + if hasattr(Qt, "_QtCore"): + Qt.__qt_version__ = Qt._QtCore.qVersion() + Qt.QtCompat.dataChanged = ( + lambda self, topleft, bottomright, roles=None: + self.dataChanged.emit(topleft, bottomright, roles or []) + ) + + if hasattr(Qt, "_QtWidgets"): + Qt.QtCompat.setSectionResizeMode = \ + Qt._QtWidgets.QHeaderView.setSectionResizeMode + + _reassign_misplaced_members("PySide6") + _build_compatibility_members("PySide6") def _pyside2(): """Initialise PySide2 @@ -1808,7 +1905,7 @@ def __call__(self, *a, **kw): def _install(): # Default order (customize order and content via QT_PREFERRED_BINDING) - default_order = ("PySide2", "PyQt5", "PySide", "PyQt4") + default_order = ("PySide6","PySide2", "PyQt5", "PySide", "PyQt4") preferred_order = None if QT_PREFERRED_BINDING_JSON: # A per-vendor preferred binding customization was defined @@ -1841,6 +1938,7 @@ def _install(): order = preferred_order or default_order available = { + "PySide6": _pyside6, "PySide2": _pyside2, "PyQt5": _pyqt5, "PySide": _pyside, @@ -1925,6 +2023,7 @@ def _install(): _install() # Setup Binding Enum states +Qt.IsPySide6 = Qt.__binding__ == "PySide6" Qt.IsPySide2 = Qt.__binding__ == 'PySide2' Qt.IsPyQt5 = Qt.__binding__ == 'PyQt5' Qt.IsPySide = Qt.__binding__ == 'PySide' @@ -2037,4 +2136,4 @@ def _install(): # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file From d91130ea685adc743585709a67481255a13bc4f1 Mon Sep 17 00:00:00 2001 From: joshochoa Date: Sun, 30 Oct 2022 11:50:09 -0700 Subject: [PATCH 2/8] white space format updates --- Qt.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Qt.py b/Qt.py index b2833809..9246ff07 100644 --- a/Qt.py +++ b/Qt.py @@ -1476,6 +1476,7 @@ def _build_compatibility_members(binding, decorators=None): compat_class = type(classname, (_QtCompat,), attrs) setattr(Qt.QtCompat, classname, compat_class) + def _pyside6(): """Initialise PySide6 @@ -1519,6 +1520,7 @@ def _pyside6(): _reassign_misplaced_members("PySide6") _build_compatibility_members("PySide6") + def _pyside2(): """Initialise PySide2 @@ -1905,7 +1907,7 @@ def __call__(self, *a, **kw): def _install(): # Default order (customize order and content via QT_PREFERRED_BINDING) - default_order = ("PySide6","PySide2", "PyQt5", "PySide", "PyQt4") + default_order = ("PySide6", "PySide2", "PyQt5", "PySide", "PyQt4") preferred_order = None if QT_PREFERRED_BINDING_JSON: # A per-vendor preferred binding customization was defined From 891e3163abd9ac9d3401c4088e21a36173245ac3 Mon Sep 17 00:00:00 2001 From: joshochoa Date: Sun, 30 Oct 2022 11:52:52 -0700 Subject: [PATCH 3/8] added newline at end of file --- Qt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Qt.py b/Qt.py index 9246ff07..4af2c9d9 100644 --- a/Qt.py +++ b/Qt.py @@ -2138,4 +2138,4 @@ def _install(): # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From 09911cf5c69779f6fc5d8f754d16a67457f173c0 Mon Sep 17 00:00:00 2001 From: Arda Kutlu Date: Thu, 23 Nov 2023 13:53:36 +0000 Subject: [PATCH 4/8] adding the QAction to the misplaced dict and removing it from the commons --- Qt.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Qt.py b/Qt.py index 4af2c9d9..58351447 100644 --- a/Qt.py +++ b/Qt.py @@ -442,7 +442,6 @@ "QAbstractScrollArea", "QAbstractSlider", "QAbstractSpinBox", - "QAction", "QActionGroup", "QApplication", "QBoxLayout", @@ -1011,6 +1010,7 @@ def createWidget(self, class_name, parent=None, name=""): "PySide6": { "QtCore.QStringListModel": "QtCore.QStringListModel", "QtGui.QStringListModel": "QtCore.QStringListModel", + "QtGui.QAction": "QtWidgets.QAction", "QtCore.Property": "QtCore.Property", "QtCore.Signal": "QtCore.Signal", "QtCore.Slot": "QtCore.Slot", @@ -1039,6 +1039,7 @@ def createWidget(self, class_name, parent=None, name=""): "PySide2": { "QtCore.QStringListModel": "QtCore.QStringListModel", "QtGui.QStringListModel": "QtCore.QStringListModel", + "QtWidgets.QAction": "QtWidgets.QAction", "QtCore.Property": "QtCore.Property", "QtCore.Signal": "QtCore.Signal", "QtCore.Slot": "QtCore.Slot", @@ -1065,6 +1066,7 @@ def createWidget(self, class_name, parent=None, name=""): "QtMultimedia.QSound": "QtMultimedia.QSound", }, "PyQt5": { + "QtWidgets.QAction": "QtWidgets.QAction", "QtCore.pyqtProperty": "QtCore.Property", "QtCore.pyqtSignal": "QtCore.Signal", "QtCore.pyqtSlot": "QtCore.Slot", @@ -1092,6 +1094,7 @@ def createWidget(self, class_name, parent=None, name=""): "QtMultimedia.QSound": "QtMultimedia.QSound", }, "PySide": { + "QtWidgets.QAction": "QtWidgets.QAction", "QtGui.QAbstractProxyModel": "QtCore.QAbstractProxyModel", "QtGui.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel", "QtGui.QStringListModel": "QtCore.QStringListModel", @@ -1127,6 +1130,7 @@ def createWidget(self, class_name, parent=None, name=""): "QtGui.QSound": "QtMultimedia.QSound", }, "PyQt4": { + "QtWidgets.QAction": "QtWidgets.QAction", "QtGui.QAbstractProxyModel": "QtCore.QAbstractProxyModel", "QtGui.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel", "QtGui.QItemSelection": "QtCore.QItemSelection", @@ -2138,4 +2142,4 @@ def _install(): # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file From 30b364a43e83c98d566e63cc362fa8baddfa5cc9 Mon Sep 17 00:00:00 2001 From: Arda Kutlu Date: Thu, 23 Nov 2023 14:03:13 +0000 Subject: [PATCH 5/8] ends --- Qt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Qt.py b/Qt.py index 58351447..1c0be852 100644 --- a/Qt.py +++ b/Qt.py @@ -2142,4 +2142,4 @@ def _install(): # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From 34e0b588acc7892755419f888bb84ef8499e1b20 Mon Sep 17 00:00:00 2001 From: Arda Kutlu Date: Thu, 23 Nov 2023 23:31:25 +0000 Subject: [PATCH 6/8] Adding QShortcut to the _misplaced members --- Qt.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Qt.py b/Qt.py index 1c0be852..28813e7b 100644 --- a/Qt.py +++ b/Qt.py @@ -549,7 +549,6 @@ "QRubberBand", "QScrollArea", "QScrollBar", - "QShortcut", "QSizeGrip", "QSizePolicy", "QSlider", @@ -1008,6 +1007,7 @@ def createWidget(self, class_name, parent=None, name=""): """ _misplaced_members = { "PySide6": { + "QtGui.QShortcut": "QtWidgets.QShortcut", "QtCore.QStringListModel": "QtCore.QStringListModel", "QtGui.QStringListModel": "QtCore.QStringListModel", "QtGui.QAction": "QtWidgets.QAction", @@ -1037,6 +1037,7 @@ def createWidget(self, class_name, parent=None, name=""): "QtMultimedia.QSound": "QtMultimedia.QSound", }, "PySide2": { + "QtWidgets.QShortcut": "QtWidgets.QShortcut", "QtCore.QStringListModel": "QtCore.QStringListModel", "QtGui.QStringListModel": "QtCore.QStringListModel", "QtWidgets.QAction": "QtWidgets.QAction", @@ -1066,6 +1067,7 @@ def createWidget(self, class_name, parent=None, name=""): "QtMultimedia.QSound": "QtMultimedia.QSound", }, "PyQt5": { + "QtWidgets.QShortcut": "QtWidgets.QShortcut", "QtWidgets.QAction": "QtWidgets.QAction", "QtCore.pyqtProperty": "QtCore.Property", "QtCore.pyqtSignal": "QtCore.Signal", @@ -1094,6 +1096,7 @@ def createWidget(self, class_name, parent=None, name=""): "QtMultimedia.QSound": "QtMultimedia.QSound", }, "PySide": { + "QtWidgets.QShortcut": "QtWidgets.QShortcut", "QtWidgets.QAction": "QtWidgets.QAction", "QtGui.QAbstractProxyModel": "QtCore.QAbstractProxyModel", "QtGui.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel", @@ -1130,6 +1133,7 @@ def createWidget(self, class_name, parent=None, name=""): "QtGui.QSound": "QtMultimedia.QSound", }, "PyQt4": { + "QtWidgets.QShortcut": "QtWidgets.QShortcut", "QtWidgets.QAction": "QtWidgets.QAction", "QtGui.QAbstractProxyModel": "QtCore.QAbstractProxyModel", "QtGui.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel", @@ -2142,4 +2146,4 @@ def _install(): # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file From 49c58a95a862d85fa0a06304fddd61da6dfdbd1d Mon Sep 17 00:00:00 2001 From: zoshua Date: Fri, 16 Feb 2024 18:32:48 -0700 Subject: [PATCH 7/8] Qt6 - QAction - Moved to QtGui In Qt6 the QAction class, which is used for creation toolbars and menus, has been moved from the QtWidgets to the QtGui module. --- Qt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Qt.py b/Qt.py index 4af2c9d9..0d7b1a96 100644 --- a/Qt.py +++ b/Qt.py @@ -215,6 +215,7 @@ ], "QtGui": [ "QAbstractTextDocumentLayout", + "QAction", "QActionEvent", "QBitmap", "QBrush", From 6dd420c1fd4ac512c89226c89d7e89475c345445 Mon Sep 17 00:00:00 2001 From: zoshua Date: Sat, 17 Feb 2024 08:39:26 -0700 Subject: [PATCH 8/8] Updated Header Documentation --- Qt.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Qt.py b/Qt.py index 0d7b1a96..76ae8bba 100644 --- a/Qt.py +++ b/Qt.py @@ -3,14 +3,16 @@ DOCUMENTATION Qt.py was born in the film and visual effects industry to address the growing need for the development of software capable of running - with more than one flavour of the Qt bindings for Python - PySide, - PySide2, PyQt4 and PyQt5. + with more than one flavour of the Qt bindings for Python. + + Supported Binding: PySide, PySide2, PySide6, PyQt4, PyQt5 1. Build for one, run with all 2. Explicit is better than implicit 3. Support co-existence Default resolution order: + - PySide6 - PySide2 - PyQt5 - PySide