Skip to content

Commit

Permalink
Upgrade from PyQt4 to PyQt6 in Qskope
Browse files Browse the repository at this point in the history
  • Loading branch information
ricardonunosr committed Nov 10, 2023
1 parent 7f4404d commit bb78eb6
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 74 deletions.
2 changes: 1 addition & 1 deletion INSTALL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Requirements
============

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

Using the Windows installer
===========================
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Python library for processing block structured binary files:
* **Batteries included:** Many tools for files used by 3D games, such
as optimizers, stripifier, tangent space calculator, 2d/3d hull
algorithms, inertia calculator, as well as a general purpose file
editor QSkope (using `PyQt4
editor QSkope (using `PyQt6
<http://www.riverbankcomputing.co.uk/software/pyqt/download>`_), are
included.

Expand Down
2 changes: 1 addition & 1 deletion pyffi/formats/cgf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ def read(self, stream):

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

chunk_types = [
Expand Down
48 changes: 17 additions & 31 deletions pyffi/qskope/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
#
# ***** END LICENSE BLOCK *****

from PyQt4 import QtGui, QtCore
from PyQt6 import QtGui, QtCore , QtWidgets

import pyffi.qskope.global_model
import pyffi.qskope.detail_model
Expand All @@ -61,35 +61,33 @@

# implementation details:
# http://doc.trolltech.com/4.3/qmainwindow.html#details
class QSkope(QtGui.QMainWindow):
class QSkope(QtWidgets.QMainWindow):
"""Main QSkope window."""
def __init__(self, parent = None):
"""Initialize the main window."""
QtGui.QMainWindow.__init__(self, parent)
QtWidgets.QMainWindow.__init__(self, parent)

# set up the menu bar
self.createActions()
self.createMenus()

# set up the global model view
self.globalWidget = QtGui.QTreeView()
self.globalWidget = QtWidgets.QTreeView()
self.globalWidget.setAlternatingRowColors(True)

# set up the detail model view
self.detailWidget = QtGui.QTreeView()
self.detailWidget = QtWidgets.QTreeView()
self.detailDelegate = pyffi.qskope.detail_delegate.DetailDelegate()
self.detailWidget.setItemDelegate(self.detailDelegate)
self.detailWidget.setAlternatingRowColors(True)

# connect global with detail:
# if object is selected in global view, then show its details in the
# detail view
QtCore.QObject.connect(self.globalWidget,
QtCore.SIGNAL("clicked(const QModelIndex &)"),
self.setDetailModel)
self.globalWidget.clicked.connect(self.setDetailModel)

# set up the central widget
self.splitter = QtGui.QSplitter()
self.splitter = QtWidgets.QSplitter()
self.splitter.addWidget(self.globalWidget)
self.splitter.addWidget(self.detailWidget)
self.setCentralWidget(self.splitter)
Expand All @@ -114,42 +112,30 @@ def createActions(self):
# open a file
self.openAct = QtGui.QAction("&Open", self)
self.openAct.setShortcut("Ctrl+O")
QtCore.QObject.connect(self.openAct,
QtCore.SIGNAL("triggered()"),
self.openAction)
self.openAct.triggered.connect(self.openAction)

# save a file
self.saveAct = QtGui.QAction("&Save", self)
self.saveAct.setShortcut("Ctrl+S")
QtCore.QObject.connect(self.saveAct,
QtCore.SIGNAL("triggered()"),
self.saveAction)
self.saveAct.triggered.connect(self.saveAction)

# save a file as ...
self.saveAsAct = QtGui.QAction("Save As...", self)
self.saveAsAct.setShortcut("Ctrl+Shift+S")
QtCore.QObject.connect(self.saveAsAct,
QtCore.SIGNAL("triggered()"),
self.saveAsAction)
self.saveAsAct.triggered.connect(self.saveAsAction)

# exit
self.exitAct = QtGui.QAction("E&xit", self)
self.exitAct.setShortcut("Ctrl+Q")
QtCore.QObject.connect(self.exitAct,
QtCore.SIGNAL("triggered()"),
QtGui.qApp.quit)
self.exitAct.triggered.connect(QtWidgets.QApplication.quit)

# tell something about QSkope
self.aboutQSkopeAct = QtGui.QAction("About QSkope", self)
QtCore.QObject.connect(self.aboutQSkopeAct,
QtCore.SIGNAL("triggered()"),
self.aboutQSkopeAction)
self.aboutQSkopeAct.triggered.connect(self.aboutQSkopeAction)

# tell something about Qt
self.aboutQtAct = QtGui.QAction("About Qt", self)
QtCore.QObject.connect(self.aboutQtAct,
QtCore.SIGNAL("triggered()"),
QtGui.qApp.aboutQt)
self.aboutQtAct.triggered.connect(QtWidgets.QApplication.aboutQt)

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


#
Expand Down Expand Up @@ -294,15 +280,15 @@ def openAction(self):
"""Open a file."""
# wrapper around openFile
# (displays an extra file dialog)
filename = QtGui.QFileDialog.getOpenFileName(self, "Open File")
filename = QtWidgets.QFileDialog.getOpenFileName(self, "Open File")
if filename:
self.openFile(filename = filename)

def saveAsAction(self):
"""Save a file."""
# wrapper around saveAction
# (displays an extra file dialog)
filename = QtGui.QFileDialog.getSaveFileName(self, "Save File")
filename = QtWidgets.QFileDialog.getSaveFileName(self, "Save File")
if filename:
self.fileName = filename
self.saveAction()
Expand All @@ -317,7 +303,7 @@ def saveAction(self):
def aboutQSkopeAction(self):
"""Display an information window about QSkope."""
# create the box
mbox = QtGui.QMessageBox(self)
mbox = QtWidgets.QMessageBox(self)
# set window title and window text
mbox.setWindowTitle("About QSkope")
mbox.setText("""
Expand Down
24 changes: 12 additions & 12 deletions pyffi/qskope/detail_delegate.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
#
# ***** END LICENSE BLOCK *****

from PyQt4 import QtCore, QtGui
from PyQt6 import QtCore, QtGui, QtWidgets

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

def _checkValidEditor(self, data, editor):
Expand Down Expand Up @@ -78,19 +78,19 @@ def _checkValidEditor(self, data, editor):
# (some combo types may also derive from spin box such as bools,
# in that case prefer the combo box representation)
if isinstance(data, EditableComboBox):
isvalid = isinstance(editor, QtGui.QComboBox)
isvalid = isinstance(editor, QtWidgets.QComboBox)
# check float spin box
elif isinstance(data, EditableFloatSpinBox):
isvalid = isinstance(editor, QtGui.QDoubleSpinBox)
isvalid = isinstance(editor, QtWidgets.QDoubleSpinBox)
# check spin box
elif isinstance(data, EditableSpinBox):
isvalid = isinstance(editor, QtGui.QSpinBox)
isvalid = isinstance(editor, QtWidgets.QSpinBox)
# check text editor
elif isinstance(data, EditableTextEdit):
isvalid = isinstance(editor, QtGui.QTextEdit)
isvalid = isinstance(editor, QtWidgets.QTextEdit)
# check line editor
elif isinstance(data, EditableLineEdit):
isvalid = isinstance(editor, QtGui.QLineEdit)
isvalid = isinstance(editor, QtWidgets.QLineEdit)
else:
# data has no delegate class, which is classified as invalid
isvalid = False
Expand All @@ -112,7 +112,7 @@ def createEditor(self, parent, option, index):
# (see _checkValidEditor for the correct delegate preference order)
if isinstance(node, EditableComboBox):
# a general purpose combo box
editor = QtGui.QComboBox(parent)
editor = QtWidgets.QComboBox(parent)
for key in node.get_editor_keys():
editor.addItem(key)
elif isinstance(node, EditableFloatSpinBox):
Expand All @@ -123,17 +123,17 @@ def createEditor(self, parent, option, index):
editor.setDecimals(node.get_editor_decimals())
elif isinstance(node, EditableSpinBox):
# an integer spin box
editor = QtGui.QSpinBox(parent)
editor = QtWidgets.QSpinBox(parent)
editor.setMinimum(node.get_editor_minimum())
# work around a qt "bug": maximum must be C type "int"
# so cannot be larger than 0x7fffffff
editor.setMaximum(min(node.get_editor_maximum(), 0x7fffffff))
elif isinstance(node, EditableTextEdit):
# a text editor
editor = QtGui.QTextEdit(parent)
editor = QtWidgets.QTextEdit(parent)
elif isinstance(node, EditableLineEdit):
# a line editor
editor = QtGui.QLineEdit(parent)
editor = QtWidgets.QLineEdit(parent)
else:
return None
# check validity
Expand Down Expand Up @@ -195,5 +195,5 @@ def setModelData(self, editor, model, index):
return
# set the model data
# EditRole ensures that setData uses set_editor_value to set the data
model.setData(index, editorvalue, QtCore.Qt.EditRole)
model.setData(index, editorvalue, QtCore.Qt.ItemDataRole.EditRole)

23 changes: 11 additions & 12 deletions pyffi/qskope/detail_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
#
# ***** END LICENSE BLOCK *****

from PyQt4 import QtCore
from PyQt6 import QtCore

from pyffi.utils.graph import EdgeFilter, GlobalNode
from pyffi.qskope.detail_tree import DetailTreeItem, DetailTreeItemData
Expand Down Expand Up @@ -81,9 +81,9 @@ def flags(self, index):
"""Return flags for the given index: all indices are enabled and
selectable."""
if not index.isValid():
return QtCore.Qt.ItemFlags()
return QtCore.Qt.ItemFlag()
# all items are enabled and selectable
flags = QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
flags = QtCore.Qt.ItemFlag.ItemIsEnabled | QtCore.Qt.ItemFlag.ItemIsSelectable
# determine whether item value can be set
if index.column() == self.COL_VALUE:
try:
Expand All @@ -94,16 +94,16 @@ def flags(self, index):
except NotImplementedError:
pass
else:
flags |= QtCore.Qt.ItemIsEditable
return QtCore.Qt.ItemFlags(flags)
flags |= QtCore.Qt.ItemFlag.ItemIsEditable
return QtCore.Qt.ItemFlag(flags)

def data(self, index, role):
"""Return the data of model index in a particular role. Only
QtCore.Qt.DisplayRole is implemented.
"""
# check if the index is valid
# check if the role is supported
if not index.isValid() or role != QtCore.Qt.DisplayRole:
if not index.isValid() or role != QtCore.Qt.ItemDataRole.DisplayRole:
return None
# get the data for display
item = index.internalPointer()
Expand Down Expand Up @@ -142,8 +142,8 @@ def data(self, index, role):

def headerData(self, section, orientation, role):
"""Return header data."""
if (orientation == QtCore.Qt.Horizontal
and role == QtCore.Qt.DisplayRole):
if (orientation == QtCore.Qt.Orientation.Horizontal
and role == QtCore.Qt.ItemDataRole.DisplayRole):
if section == self.COL_TYPE:
return "Type"
elif section == self.COL_NAME:
Expand Down Expand Up @@ -194,9 +194,9 @@ def parent(self, index):

def setData(self, index, value, role):
"""Set data of a given index from given QVariant value. Only
QtCore.Qt.EditRole is implemented.
QtCore.Qt.ItemDataRole.EditRole is implemented.
"""
if role == QtCore.Qt.EditRole:
if role == QtCore.Qt.ItemDataRole.EditRole:
# fetch the current data, as a regular Python type
node = index.internalPointer().data.node
currentvalue = node.get_value()
Expand Down Expand Up @@ -224,8 +224,7 @@ def setData(self, index, value, role):
# set the value (EditRole, so use set_editor_value, not set_value)
node.set_editor_value(pyvalue)
# tell everyone that the data has changed
self.emit(QtCore.SIGNAL('dataChanged(QModelIndex, QModelIndex)'),
index, index)
self.dataChanged.emit(index,index, [])
return True
# all other cases: failed
return False
22 changes: 11 additions & 11 deletions pyffi/qskope/global_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@
#
# ***** END LICENSE BLOCK *****

from collections import MutableMapping
from collections.abc import MutableMapping

from PyQt4 import QtGui, QtCore
from PyQt6 import QtCore

from pyffi.utils.graph import EdgeFilter
from pyffi.qskope.global_tree import GlobalTreeItemData, GlobalTreeItem
Expand Down Expand Up @@ -76,7 +76,7 @@ def __delitem__(self, key):
# index becomes available
self.free_indices.append(self.data[id(key)])
# remove it
del self.data[id(key)]
del self.data[id(key)]

def clear(self):
# all indices larger than the first element
Expand Down Expand Up @@ -107,27 +107,27 @@ def updateIndexDict(self, item):
self.index_dict[item.data.node]
for child_item in item.children:
self.updateIndexDict(child_item)


def flags(self, index):
"""Return flags for the given index: all indices are enabled and
selectable."""
# all items are selectable
# they are enabled if their edge_type is active
if not index.isValid():
return QtCore.Qt.ItemFlags()
return QtCore.Qt.ItemFlag()
item = index.internalPointer()
if item.edge_type.active:
flags = QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
flags = QtCore.Qt.ItemFlag.ItemIsEnabled | QtCore.Qt.ItemFlag.ItemIsSelectable
else:
flags = QtCore.Qt.ItemIsSelectable
return QtCore.Qt.ItemFlags(flags)
flags = QtCore.Qt.ItemFlag.ItemIsSelectable
return QtCore.Qt.ItemFlag(flags)

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

def headerData(self, section, orientation, role):
"""Return header data."""
if (orientation == QtCore.Qt.Horizontal
and role == QtCore.Qt.DisplayRole):
if (orientation == QtCore.Qt.Orientation.Horizontal
and role == QtCore.Qt.ItemDataRole.DisplayRole):
if section == self.COL_TYPE:
return "Type"
elif section == self.COL_NAME:
Expand Down
Loading

0 comments on commit bb78eb6

Please sign in to comment.