Skip to content

Commit 1968851

Browse files
committed
Upgrade from PyQt4 to PyQt6 in Qskope
1 parent 7f4404d commit 1968851

File tree

8 files changed

+60
-75
lines changed

8 files changed

+60
-75
lines changed

INSTALL.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Requirements
22
============
33

44
To run PyFFI's graphical file editor QSkope, you need
5-
`PyQt4 <http://www.riverbankcomputing.co.uk/software/pyqt/download>`_.
5+
`PyQt6 <http://www.riverbankcomputing.co.uk/software/pyqt/download>`_.
66

77
Using the Windows installer
88
===========================

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Python library for processing block structured binary files:
2020
* **Batteries included:** Many tools for files used by 3D games, such
2121
as optimizers, stripifier, tangent space calculator, 2d/3d hull
2222
algorithms, inertia calculator, as well as a general purpose file
23-
editor QSkope (using `PyQt4
23+
editor QSkope (using `PyQt6
2424
<http://www.riverbankcomputing.co.uk/software/pyqt/download>`_), are
2525
included.
2626

pyffi/formats/cgf/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ def read(self, stream):
716716

717717
# is it a caf file? these are missing chunk headers on controllers
718718
# (note: stream.name may not be a python string for some file
719-
# implementations, notably PyQt4, so convert it explicitely)
719+
# implementations, notably PyQt6, so convert it explicitely)
720720
is_caf = (str(stream.name)[-4:].lower() == ".caf")
721721

722722
chunk_types = [

pyffi/qskope/__init__.py

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
#
3838
# ***** END LICENSE BLOCK *****
3939

40-
from PyQt4 import QtGui, QtCore
40+
from PyQt6 import QtGui, QtCore , QtWidgets
4141

4242
import pyffi.qskope.global_model
4343
import pyffi.qskope.detail_model
@@ -61,35 +61,33 @@
6161

6262
# implementation details:
6363
# http://doc.trolltech.com/4.3/qmainwindow.html#details
64-
class QSkope(QtGui.QMainWindow):
64+
class QSkope(QtWidgets.QMainWindow):
6565
"""Main QSkope window."""
6666
def __init__(self, parent = None):
6767
"""Initialize the main window."""
68-
QtGui.QMainWindow.__init__(self, parent)
68+
QtWidgets.QMainWindow.__init__(self, parent)
6969

7070
# set up the menu bar
7171
self.createActions()
7272
self.createMenus()
7373

7474
# set up the global model view
75-
self.globalWidget = QtGui.QTreeView()
75+
self.globalWidget = QtWidgets.QTreeView()
7676
self.globalWidget.setAlternatingRowColors(True)
7777

7878
# set up the detail model view
79-
self.detailWidget = QtGui.QTreeView()
79+
self.detailWidget = QtWidgets.QTreeView()
8080
self.detailDelegate = pyffi.qskope.detail_delegate.DetailDelegate()
8181
self.detailWidget.setItemDelegate(self.detailDelegate)
8282
self.detailWidget.setAlternatingRowColors(True)
8383

8484
# connect global with detail:
8585
# if object is selected in global view, then show its details in the
8686
# detail view
87-
QtCore.QObject.connect(self.globalWidget,
88-
QtCore.SIGNAL("clicked(const QModelIndex &)"),
89-
self.setDetailModel)
87+
self.globalWidget.clicked.connect(self.setDetailModel)
9088

9189
# set up the central widget
92-
self.splitter = QtGui.QSplitter()
90+
self.splitter = QtWidgets.QSplitter()
9391
self.splitter.addWidget(self.globalWidget)
9492
self.splitter.addWidget(self.detailWidget)
9593
self.setCentralWidget(self.splitter)
@@ -114,42 +112,30 @@ def createActions(self):
114112
# open a file
115113
self.openAct = QtGui.QAction("&Open", self)
116114
self.openAct.setShortcut("Ctrl+O")
117-
QtCore.QObject.connect(self.openAct,
118-
QtCore.SIGNAL("triggered()"),
119-
self.openAction)
115+
self.openAct.triggered.connect(self.openAction)
120116

121117
# save a file
122118
self.saveAct = QtGui.QAction("&Save", self)
123119
self.saveAct.setShortcut("Ctrl+S")
124-
QtCore.QObject.connect(self.saveAct,
125-
QtCore.SIGNAL("triggered()"),
126-
self.saveAction)
120+
self.saveAct.triggered.connect(self.saveAction)
127121

128122
# save a file as ...
129123
self.saveAsAct = QtGui.QAction("Save As...", self)
130124
self.saveAsAct.setShortcut("Ctrl+Shift+S")
131-
QtCore.QObject.connect(self.saveAsAct,
132-
QtCore.SIGNAL("triggered()"),
133-
self.saveAsAction)
125+
self.saveAsAct.triggered.connect(self.saveAsAction)
134126

135127
# exit
136128
self.exitAct = QtGui.QAction("E&xit", self)
137129
self.exitAct.setShortcut("Ctrl+Q")
138-
QtCore.QObject.connect(self.exitAct,
139-
QtCore.SIGNAL("triggered()"),
140-
QtGui.qApp.quit)
130+
self.exitAct.triggered.connect(QtWidgets.QApplication.quit)
141131

142132
# tell something about QSkope
143133
self.aboutQSkopeAct = QtGui.QAction("About QSkope", self)
144-
QtCore.QObject.connect(self.aboutQSkopeAct,
145-
QtCore.SIGNAL("triggered()"),
146-
self.aboutQSkopeAction)
134+
self.aboutQSkopeAct.triggered.connect(self.aboutQSkopeAction)
147135

148136
# tell something about Qt
149137
self.aboutQtAct = QtGui.QAction("About Qt", self)
150-
QtCore.QObject.connect(self.aboutQtAct,
151-
QtCore.SIGNAL("triggered()"),
152-
QtGui.qApp.aboutQt)
138+
self.aboutQtAct.triggered.connect(QtWidgets.QApplication.aboutQt)
153139

154140
# implementation details:
155141
# http://doc.trolltech.com/4.3/mainwindows-menus.html
@@ -172,7 +158,7 @@ def closeEvent(self, event):
172158
"""Called when the application is closed. Saves the settings."""
173159
settings = self.getSettings(versioned = True)
174160
settings.setValue("MainWindow/geometry", self.saveGeometry())
175-
QtGui.QMainWindow.closeEvent(self, event)
161+
QtWidgets.QMainWindow.closeEvent(self, event)
176162

177163

178164
#
@@ -294,15 +280,15 @@ def openAction(self):
294280
"""Open a file."""
295281
# wrapper around openFile
296282
# (displays an extra file dialog)
297-
filename = QtGui.QFileDialog.getOpenFileName(self, "Open File")
283+
filename = QtWidgets.QFileDialog.getOpenFileName(self, "Open File")
298284
if filename:
299285
self.openFile(filename = filename)
300286

301287
def saveAsAction(self):
302288
"""Save a file."""
303289
# wrapper around saveAction
304290
# (displays an extra file dialog)
305-
filename = QtGui.QFileDialog.getSaveFileName(self, "Save File")
291+
filename = QtWidgets.QFileDialog.getSaveFileName(self, "Save File")
306292
if filename:
307293
self.fileName = filename
308294
self.saveAction()
@@ -317,7 +303,7 @@ def saveAction(self):
317303
def aboutQSkopeAction(self):
318304
"""Display an information window about QSkope."""
319305
# create the box
320-
mbox = QtGui.QMessageBox(self)
306+
mbox = QtWidgets.QMessageBox(self)
321307
# set window title and window text
322308
mbox.setWindowTitle("About QSkope")
323309
mbox.setText("""
@@ -336,4 +322,4 @@ def aboutQSkopeAction(self):
336322
<a href="https://github.com/niftools/pyffi/releases">
337323
PyFFI Github Releases page</a>.""" % pyffi.__version__)
338324
# display the window
339-
mbox.exec_()
325+
mbox.exec()

pyffi/qskope/detail_delegate.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
#
3838
# ***** END LICENSE BLOCK *****
3939

40-
from PyQt4 import QtCore, QtGui
40+
from PyQt6 import QtCore, QtGui, QtWidgets
4141

4242
# each delegate type corresponds to a QtGui delegate type
4343
# (see _checkValidEditor for more details)
@@ -50,7 +50,7 @@
5050
# implementation details:
5151
# http://doc.trolltech.com/4.3/model-view-delegate.html
5252
# http://doc.trolltech.com/4.3/qitemdelegate.html#details
53-
class DetailDelegate(QtGui.QItemDelegate):
53+
class DetailDelegate(QtWidgets.QItemDelegate):
5454
"""Defines an editor for data in the detail view."""
5555

5656
def _checkValidEditor(self, data, editor):
@@ -78,19 +78,19 @@ def _checkValidEditor(self, data, editor):
7878
# (some combo types may also derive from spin box such as bools,
7979
# in that case prefer the combo box representation)
8080
if isinstance(data, EditableComboBox):
81-
isvalid = isinstance(editor, QtGui.QComboBox)
81+
isvalid = isinstance(editor, QtWidgets.QComboBox)
8282
# check float spin box
8383
elif isinstance(data, EditableFloatSpinBox):
84-
isvalid = isinstance(editor, QtGui.QDoubleSpinBox)
84+
isvalid = isinstance(editor, QtWidgets.QDoubleSpinBox)
8585
# check spin box
8686
elif isinstance(data, EditableSpinBox):
87-
isvalid = isinstance(editor, QtGui.QSpinBox)
87+
isvalid = isinstance(editor, QtWidgets.QSpinBox)
8888
# check text editor
8989
elif isinstance(data, EditableTextEdit):
90-
isvalid = isinstance(editor, QtGui.QTextEdit)
90+
isvalid = isinstance(editor, QtWidgets.QTextEdit)
9191
# check line editor
9292
elif isinstance(data, EditableLineEdit):
93-
isvalid = isinstance(editor, QtGui.QLineEdit)
93+
isvalid = isinstance(editor, QtWidgets.QLineEdit)
9494
else:
9595
# data has no delegate class, which is classified as invalid
9696
isvalid = False
@@ -112,7 +112,7 @@ def createEditor(self, parent, option, index):
112112
# (see _checkValidEditor for the correct delegate preference order)
113113
if isinstance(node, EditableComboBox):
114114
# a general purpose combo box
115-
editor = QtGui.QComboBox(parent)
115+
editor = QtWidgets.QComboBox(parent)
116116
for key in node.get_editor_keys():
117117
editor.addItem(key)
118118
elif isinstance(node, EditableFloatSpinBox):
@@ -123,17 +123,17 @@ def createEditor(self, parent, option, index):
123123
editor.setDecimals(node.get_editor_decimals())
124124
elif isinstance(node, EditableSpinBox):
125125
# an integer spin box
126-
editor = QtGui.QSpinBox(parent)
126+
editor = QtWidgets.QSpinBox(parent)
127127
editor.setMinimum(node.get_editor_minimum())
128128
# work around a qt "bug": maximum must be C type "int"
129129
# so cannot be larger than 0x7fffffff
130130
editor.setMaximum(min(node.get_editor_maximum(), 0x7fffffff))
131131
elif isinstance(node, EditableTextEdit):
132132
# a text editor
133-
editor = QtGui.QTextEdit(parent)
133+
editor = QtWidgets.QTextEdit(parent)
134134
elif isinstance(node, EditableLineEdit):
135135
# a line editor
136-
editor = QtGui.QLineEdit(parent)
136+
editor = QtWidgets.QLineEdit(parent)
137137
else:
138138
return None
139139
# check validity
@@ -195,5 +195,5 @@ def setModelData(self, editor, model, index):
195195
return
196196
# set the model data
197197
# EditRole ensures that setData uses set_editor_value to set the data
198-
model.setData(index, editorvalue, QtCore.Qt.EditRole)
198+
model.setData(index, editorvalue, QtCore.Qt.ItemDataRole.EditRole)
199199

pyffi/qskope/detail_model.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
#
3939
# ***** END LICENSE BLOCK *****
4040

41-
from PyQt4 import QtCore
41+
from PyQt6 import QtCore
4242

4343
from pyffi.utils.graph import EdgeFilter, GlobalNode
4444
from pyffi.qskope.detail_tree import DetailTreeItem, DetailTreeItemData
@@ -81,9 +81,9 @@ def flags(self, index):
8181
"""Return flags for the given index: all indices are enabled and
8282
selectable."""
8383
if not index.isValid():
84-
return QtCore.Qt.ItemFlags()
84+
return QtCore.Qt.ItemFlag()
8585
# all items are enabled and selectable
86-
flags = QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
86+
flags = QtCore.Qt.ItemFlag.ItemIsEnabled | QtCore.Qt.ItemFlag.ItemIsSelectable
8787
# determine whether item value can be set
8888
if index.column() == self.COL_VALUE:
8989
try:
@@ -94,16 +94,16 @@ def flags(self, index):
9494
except NotImplementedError:
9595
pass
9696
else:
97-
flags |= QtCore.Qt.ItemIsEditable
98-
return QtCore.Qt.ItemFlags(flags)
97+
flags |= QtCore.Qt.ItemFlag.ItemIsEditable
98+
return QtCore.Qt.ItemFlag(flags)
9999

100100
def data(self, index, role):
101101
"""Return the data of model index in a particular role. Only
102102
QtCore.Qt.DisplayRole is implemented.
103103
"""
104104
# check if the index is valid
105105
# check if the role is supported
106-
if not index.isValid() or role != QtCore.Qt.DisplayRole:
106+
if not index.isValid() or role != QtCore.Qt.ItemDataRole.DisplayRole:
107107
return None
108108
# get the data for display
109109
item = index.internalPointer()
@@ -142,8 +142,8 @@ def data(self, index, role):
142142

143143
def headerData(self, section, orientation, role):
144144
"""Return header data."""
145-
if (orientation == QtCore.Qt.Horizontal
146-
and role == QtCore.Qt.DisplayRole):
145+
if (orientation == QtCore.Qt.Orientation.Horizontal
146+
and role == QtCore.Qt.ItemDataRole.DisplayRole):
147147
if section == self.COL_TYPE:
148148
return "Type"
149149
elif section == self.COL_NAME:
@@ -194,9 +194,9 @@ def parent(self, index):
194194

195195
def setData(self, index, value, role):
196196
"""Set data of a given index from given QVariant value. Only
197-
QtCore.Qt.EditRole is implemented.
197+
QtCore.Qt.ItemDataRole.EditRole is implemented.
198198
"""
199-
if role == QtCore.Qt.EditRole:
199+
if role == QtCore.Qt.ItemDataRole.EditRole:
200200
# fetch the current data, as a regular Python type
201201
node = index.internalPointer().data.node
202202
currentvalue = node.get_value()
@@ -224,8 +224,7 @@ def setData(self, index, value, role):
224224
# set the value (EditRole, so use set_editor_value, not set_value)
225225
node.set_editor_value(pyvalue)
226226
# tell everyone that the data has changed
227-
self.emit(QtCore.SIGNAL('dataChanged(QModelIndex, QModelIndex)'),
228-
index, index)
227+
self.dataChanged.emit(index,index, [])
229228
return True
230229
# all other cases: failed
231230
return False

pyffi/qskope/global_model.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@
3838
#
3939
# ***** END LICENSE BLOCK *****
4040

41-
from collections import MutableMapping
41+
from collections.abc import MutableMapping
4242

43-
from PyQt4 import QtGui, QtCore
43+
from PyQt6 import QtCore
4444

4545
from pyffi.utils.graph import EdgeFilter
4646
from pyffi.qskope.global_tree import GlobalTreeItemData, GlobalTreeItem
@@ -76,7 +76,7 @@ def __delitem__(self, key):
7676
# index becomes available
7777
self.free_indices.append(self.data[id(key)])
7878
# remove it
79-
del self.data[id(key)]
79+
del self.data[id(key)]
8080

8181
def clear(self):
8282
# all indices larger than the first element
@@ -107,27 +107,27 @@ def updateIndexDict(self, item):
107107
self.index_dict[item.data.node]
108108
for child_item in item.children:
109109
self.updateIndexDict(child_item)
110-
110+
111111

112112
def flags(self, index):
113113
"""Return flags for the given index: all indices are enabled and
114114
selectable."""
115115
# all items are selectable
116116
# they are enabled if their edge_type is active
117117
if not index.isValid():
118-
return QtCore.Qt.ItemFlags()
118+
return QtCore.Qt.ItemFlag()
119119
item = index.internalPointer()
120120
if item.edge_type.active:
121-
flags = QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
121+
flags = QtCore.Qt.ItemFlag.ItemIsEnabled | QtCore.Qt.ItemFlag.ItemIsSelectable
122122
else:
123-
flags = QtCore.Qt.ItemIsSelectable
124-
return QtCore.Qt.ItemFlags(flags)
123+
flags = QtCore.Qt.ItemFlag.ItemIsSelectable
124+
return QtCore.Qt.ItemFlag(flags)
125125

126126
def data(self, index, role):
127127
"""Return the data of model index in a particular role."""
128128
# check if the index is valid
129129
# check if the role is supported
130-
if not index.isValid() or role != QtCore.Qt.DisplayRole:
130+
if not index.isValid() or role != QtCore.Qt.ItemDataRole.DisplayRole:
131131
return None
132132
# get the data for display
133133
data = index.internalPointer().data
@@ -146,8 +146,8 @@ def data(self, index, role):
146146

147147
def headerData(self, section, orientation, role):
148148
"""Return header data."""
149-
if (orientation == QtCore.Qt.Horizontal
150-
and role == QtCore.Qt.DisplayRole):
149+
if (orientation == QtCore.Qt.Orientation.Horizontal
150+
and role == QtCore.Qt.ItemDataRole.DisplayRole):
151151
if section == self.COL_TYPE:
152152
return "Type"
153153
elif section == self.COL_NAME:

0 commit comments

Comments
 (0)