diff --git a/novelwriter/__init__.py b/novelwriter/__init__.py index a5117eb3..336634eb 100644 --- a/novelwriter/__init__.py +++ b/novelwriter/__init__.py @@ -187,7 +187,7 @@ def main(sysArgs: list | None = None): )) for errLine in errorData: logger.critical(errLine) - errApp.exec_() + errApp.exec() sys.exit(errorCode) # Finish initialising config @@ -237,6 +237,6 @@ def main(sysArgs: list | None = None): nwGUI = GuiMain() nwGUI.postLaunchTasks(cmdOpen) - sys.exit(nwApp.exec_()) + sys.exit(nwApp.exec()) # END Function main diff --git a/novelwriter/config.py b/novelwriter/config.py index 670433a0..1f817e0f 100644 --- a/novelwriter/config.py +++ b/novelwriter/config.py @@ -61,8 +61,12 @@ class Config: self.appHandle = "novelwriter" # Set Paths - confRoot = Path(QStandardPaths.writableLocation(QStandardPaths.ConfigLocation)) - dataRoot = Path(QStandardPaths.writableLocation(QStandardPaths.AppDataLocation)) + confRoot = Path(QStandardPaths.writableLocation( + QStandardPaths.StandardLocation.ConfigLocation) + ) + dataRoot = Path(QStandardPaths.writableLocation( + QStandardPaths.StandardLocation.AppDataLocation) + ) self._confPath = confRoot.absolute() / self.appHandle # The user config location self._dataPath = dataRoot.absolute() / self.appHandle # The user data location @@ -83,7 +87,7 @@ class Config: # Localisation # Note that these paths must be strings self._nwLangPath = self._appPath / "assets" / "i18n" - self._qtLangPath = QLibraryInfo.location(QLibraryInfo.TranslationsPath) + self._qtLangPath = QLibraryInfo.location(QLibraryInfo.LibraryLocation.TranslationsPath) hasLocale = (self._nwLangPath / f"nw_{QLocale.system().name()}.qm").exists() self._qLocale = QLocale.system() if hasLocale else QLocale("en_GB") @@ -369,7 +373,7 @@ class Config: elif self.osDarwin and "Helvetica" in fontFam: self.textFont = "Helvetica" else: - self.textFont = fontDB.systemFont(QFontDatabase.GeneralFont).family() + self.textFont = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont).family() else: self.textFont = family return diff --git a/novelwriter/core/status.py b/novelwriter/core/status.py index 4b6911f2..554bdeed 100644 --- a/novelwriter/core/status.py +++ b/novelwriter/core/status.py @@ -35,6 +35,7 @@ from PyQt5.QtCore import QRectF from novelwriter import CONFIG from novelwriter.common import minmax, simplified +from novelwriter.types import QtPaintAnitAlias, QtTransparent if TYPE_CHECKING: # pragma: no cover from typing import TypeGuard # Requires Python 3.10 @@ -248,10 +249,10 @@ class NWStatus: def _createIcon(self, red: int, green: int, blue: int) -> QIcon: """Generate an icon for a status label.""" pixmap = QPixmap(self._iPX, self._iPX) - pixmap.fill(QColor(0, 0, 0, 0)) + pixmap.fill(QtTransparent) painter = QPainter(pixmap) - painter.setRenderHint(QPainter.Antialiasing) + painter.setRenderHint(QtPaintAnitAlias) painter.fillPath(self._iconPath, QColor(red, green, blue)) painter.end() diff --git a/novelwriter/dialogs/about.py b/novelwriter/dialogs/about.py index 4b1ab060..8317a30d 100644 --- a/novelwriter/dialogs/about.py +++ b/novelwriter/dialogs/about.py @@ -32,10 +32,10 @@ from PyQt5.QtWidgets import ( ) from novelwriter import CONFIG, SHARED -from novelwriter.common import readTextFile +from novelwriter.common import cssCol, readTextFile from novelwriter.extensions.configlayout import NColourLabel from novelwriter.extensions.versioninfo import VersionInfoWidget -from novelwriter.types import QtAlignRightTop +from novelwriter.types import QtAlignRightTop, QtDialogClose logger = logging.getLogger(__name__) @@ -70,7 +70,7 @@ class GuiAbout(QDialog): self.nwLicence = QLabel(self.tr("This application is licenced under {0}").format( "GPL v3.0" - )) + ), self) self.nwLicence.setOpenExternalLinks(True) # Credits @@ -84,7 +84,7 @@ class GuiAbout(QDialog): self.txtCredits.setViewportMargins(0, hA, hA, 0) # Buttons - self.btnBox = QDialogButtonBox(QDialogButtonBox.Close, self) + self.btnBox = QDialogButtonBox(QtDialogClose, self) self.btnBox.rejected.connect(self.close) # Assemble @@ -147,10 +147,10 @@ class GuiAbout(QDialog): def _setStyleSheet(self) -> None: """Set stylesheet for all browser tabs.""" - baseCol = self.palette().window().color() - self.txtCredits.setStyleSheet(( - "QTextBrowser {{border: none; background: rgb({r},{g},{b});}} " - ).format(r=baseCol.red(), g=baseCol.green(), b=baseCol.blue())) + baseCol = cssCol(self.palette().window().color()) + self.txtCredits.setStyleSheet( + f"QTextBrowser {{border: none; background: {baseCol};}} " + ) return # END Class GuiAbout diff --git a/novelwriter/dialogs/docmerge.py b/novelwriter/dialogs/docmerge.py index 0e5a313f..9c94489e 100644 --- a/novelwriter/dialogs/docmerge.py +++ b/novelwriter/dialogs/docmerge.py @@ -26,8 +26,8 @@ from __future__ import annotations import logging -from PyQt5.QtGui import QCloseEvent from PyQt5.QtCore import Qt, pyqtSlot +from PyQt5.QtGui import QCloseEvent from PyQt5.QtWidgets import ( QAbstractItemView, QDialog, QDialogButtonBox, QGridLayout, QLabel, QListWidget, QListWidgetItem, QVBoxLayout, QWidget @@ -36,13 +36,14 @@ from PyQt5.QtWidgets import ( from novelwriter import CONFIG, SHARED from novelwriter.extensions.switch import NSwitch from novelwriter.extensions.configlayout import NColourLabel +from novelwriter.types import QtDialogCancel, QtDialogOk, QtDialogReset, QtUserRole logger = logging.getLogger(__name__) class GuiDocMerge(QDialog): - D_HANDLE = Qt.ItemDataRole.UserRole + D_HANDLE = QtUserRole def __init__(self, parent: QWidget, sHandle: str, itemList: list[str]) -> None: super().__init__(parent=parent) @@ -53,7 +54,8 @@ class GuiDocMerge(QDialog): self._data = {} - self.headLabel = QLabel("{0}".format(self.tr("Documents to Merge"))) + self.headLabel = QLabel(self.tr("Documents to Merge"), self) + self.headLabel.setFont(SHARED.theme.guiFontB) self.helpLabel = NColourLabel( self.tr("Drag and drop items to change the order, or uncheck to exclude."), SHARED.theme.helpText, parent=self, wrap=True @@ -69,12 +71,12 @@ class GuiDocMerge(QDialog): self.listBox.setIconSize(iSz) self.listBox.setMinimumWidth(CONFIG.pxInt(400)) self.listBox.setMinimumHeight(CONFIG.pxInt(180)) - self.listBox.setSelectionBehavior(QAbstractItemView.SelectRows) - self.listBox.setSelectionMode(QAbstractItemView.SingleSelection) - self.listBox.setDragDropMode(QAbstractItemView.InternalMove) + self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) + self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) + self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove) # Merge Options - self.trashLabel = QLabel(self.tr("Move merged items to Trash")) + self.trashLabel = QLabel(self.tr("Move merged items to Trash"), self) self.trashSwitch = NSwitch(self, height=iPx) self.optBox = QGridLayout() @@ -84,11 +86,11 @@ class GuiDocMerge(QDialog): self.optBox.setColumnStretch(2, 1) # Buttons - self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) - self.resetButton = self.buttonBox.addButton(QDialogButtonBox.Reset) + self.resetButton = self.buttonBox.addButton(QtDialogReset) self.resetButton.clicked.connect(self._resetList) # Assemble @@ -120,7 +122,7 @@ class GuiDocMerge(QDialog): finalItems = [] for i in range(self.listBox.count()): item = self.listBox.item(i) - if item is not None and item.checkState() == Qt.Checked: + if item is not None and item.checkState() == Qt.CheckState.Checked: finalItems.append(item.data(self.D_HANDLE)) self._data["moveToTrash"] = self.trashSwitch.isChecked() @@ -175,7 +177,7 @@ class GuiDocMerge(QDialog): newItem.setIcon(itemIcon) newItem.setText(nwItem.itemName) newItem.setData(self.D_HANDLE, tHandle) - newItem.setCheckState(Qt.Checked) + newItem.setCheckState(Qt.CheckState.Checked) self.listBox.addItem(newItem) diff --git a/novelwriter/dialogs/docsplit.py b/novelwriter/dialogs/docsplit.py index 1ad639f9..b9d1f048 100644 --- a/novelwriter/dialogs/docsplit.py +++ b/novelwriter/dialogs/docsplit.py @@ -26,8 +26,8 @@ from __future__ import annotations import logging +from PyQt5.QtCore import pyqtSlot from PyQt5.QtGui import QCloseEvent -from PyQt5.QtCore import Qt, pyqtSlot from PyQt5.QtWidgets import ( QAbstractItemView, QComboBox, QDialog, QDialogButtonBox, QGridLayout, QLabel, QListWidget, QListWidgetItem, QVBoxLayout, QWidget @@ -36,15 +36,16 @@ from PyQt5.QtWidgets import ( from novelwriter import CONFIG, SHARED from novelwriter.extensions.switch import NSwitch from novelwriter.extensions.configlayout import NColourLabel +from novelwriter.types import QtDialogCancel, QtDialogOk, QtUserRole logger = logging.getLogger(__name__) class GuiDocSplit(QDialog): - LINE_ROLE = Qt.ItemDataRole.UserRole - LEVEL_ROLE = Qt.ItemDataRole.UserRole + 1 - LABEL_ROLE = Qt.ItemDataRole.UserRole + 2 + LINE_ROLE = QtUserRole + LEVEL_ROLE = QtUserRole + 1 + LABEL_ROLE = QtUserRole + 2 def __init__(self, parent: QWidget, sHandle: str) -> None: super().__init__(parent=parent) @@ -57,7 +58,8 @@ class GuiDocSplit(QDialog): self.setWindowTitle(self.tr("Split Document")) - self.headLabel = QLabel("{0}".format(self.tr("Document Headings"))) + self.headLabel = QLabel(self.tr("Document Headings"), self) + self.headLabel.setFont(SHARED.theme.guiFontB) self.helpLabel = NColourLabel( self.tr("Select the maximum level to split into files."), SHARED.theme.helpText, parent=self, wrap=True @@ -75,8 +77,8 @@ class GuiDocSplit(QDialog): docHierarchy = pOptions.getBool("GuiDocSplit", "docHierarchy", True) # Heading Selection - self.listBox = QListWidget() - self.listBox.setDragDropMode(QAbstractItemView.NoDragDrop) + self.listBox = QListWidget(self) + self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop) self.listBox.setMinimumWidth(CONFIG.pxInt(400)) self.listBox.setMinimumHeight(CONFIG.pxInt(180)) @@ -91,15 +93,15 @@ class GuiDocSplit(QDialog): self.splitLevel.currentIndexChanged.connect(self._reloadList) # Split Options - self.folderLabel = QLabel(self.tr("Split into a new folder")) + self.folderLabel = QLabel(self.tr("Split into a new folder"), self) self.folderSwitch = NSwitch(self, height=iPx) self.folderSwitch.setChecked(intoFolder) - self.hierarchyLabel = QLabel(self.tr("Create document hierarchy")) + self.hierarchyLabel = QLabel(self.tr("Create document hierarchy"), self) self.hierarchySwitch = NSwitch(self, height=iPx) self.hierarchySwitch.setChecked(docHierarchy) - self.trashLabel = QLabel(self.tr("Move split document to Trash")) + self.trashLabel = QLabel(self.tr("Move split document to Trash"), self) self.trashSwitch = NSwitch(self, height=iPx) self.optBox = QGridLayout() @@ -114,7 +116,7 @@ class GuiDocSplit(QDialog): self.optBox.setColumnStretch(3, 1) # Buttons - self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) diff --git a/novelwriter/dialogs/editlabel.py b/novelwriter/dialogs/editlabel.py index 154dd390..a2d374fd 100644 --- a/novelwriter/dialogs/editlabel.py +++ b/novelwriter/dialogs/editlabel.py @@ -31,6 +31,7 @@ from PyQt5.QtWidgets import ( ) from novelwriter import CONFIG +from novelwriter.types import QtDialogCancel, QtDialogOk logger = logging.getLogger(__name__) @@ -55,13 +56,13 @@ class GuiEditLabel(QDialog): self.labelValue.selectAll() # Buttons - self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) # Assemble self.innerBox = QHBoxLayout() - self.innerBox.addWidget(QLabel(self.tr("Label")), 0) + self.innerBox.addWidget(QLabel(self.tr("Label"), self), 0) self.innerBox.addWidget(self.labelValue, 1) self.innerBox.setSpacing(mSp) @@ -88,9 +89,9 @@ class GuiEditLabel(QDialog): def getLabel(cls, parent: QWidget, text: str) -> tuple[str, bool]: """Pop the dialog and return the result.""" cls = GuiEditLabel(parent, text=text) - cls.exec_() + cls.exec() label = cls.itemLabel - accepted = cls.result() == QDialog.Accepted + accepted = cls.result() == QDialog.DialogCode.Accepted cls.deleteLater() return label, accepted diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py index bef7b2bb..7d1e4671 100644 --- a/novelwriter/dialogs/preferences.py +++ b/novelwriter/dialogs/preferences.py @@ -26,12 +26,12 @@ from __future__ import annotations import logging -from PyQt5.QtGui import QCloseEvent, QFont, QKeyEvent, QKeySequence from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot +from PyQt5.QtGui import QCloseEvent, QFont, QKeyEvent, QKeySequence from PyQt5.QtWidgets import ( - QAbstractButton, QCompleter, QDialog, QDialogButtonBox, QFileDialog, - QFontDialog, QHBoxLayout, QLineEdit, QPushButton, QVBoxLayout, QWidget, - qApp + QAbstractButton, QApplication, QCompleter, QDialog, QDialogButtonBox, + QFileDialog, QFontDialog, QHBoxLayout, QLineEdit, QPushButton, QVBoxLayout, + QWidget ) from novelwriter import CONFIG, SHARED @@ -41,7 +41,10 @@ from novelwriter.extensions.configlayout import NColourLabel, NScrollableForm from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NIconToolButton, NSpinBox from novelwriter.extensions.pagedsidebar import NPagedSideBar from novelwriter.extensions.switch import NSwitch -from novelwriter.types import QtAlignCenter +from novelwriter.types import ( + QtAlignCenter, QtDialogApply, QtDialogClose, QtDialogSave, QtRoleAccept, + QtRoleApply, QtRoleReject +) logger = logging.getLogger(__name__) @@ -84,11 +87,7 @@ class GuiPreferences(QDialog): self.mainForm.setHelpTextStyle(SHARED.theme.helpText) # Buttons - self.buttonBox = QDialogButtonBox( - QDialogButtonBox.StandardButton.Apply - | QDialogButtonBox.StandardButton.Save - | QDialogButtonBox.StandardButton.Close - ) + self.buttonBox = QDialogButtonBox(QtDialogApply | QtDialogSave | QtDialogClose, self) self.buttonBox.clicked.connect(self._dialogButtonClicked) # Assemble @@ -742,7 +741,7 @@ class GuiPreferences(QDialog): logger.debug("Close: GuiPreferences") self._saveWindowSize() event.accept() - qApp.processEvents() + QApplication.processEvents() self.done(nwConst.DLG_FINISHED) self.deleteLater() return @@ -762,12 +761,12 @@ class GuiPreferences(QDialog): def _dialogButtonClicked(self, button: QAbstractButton) -> None: """Handle button clicks from the dialog button box.""" role = self.buttonBox.buttonRole(button) - if role == QDialogButtonBox.ButtonRole.ApplyRole: + if role == QtRoleApply: self._saveValues() - elif role == QDialogButtonBox.ButtonRole.AcceptRole: + elif role == QtRoleAccept: self._saveValues() self.close() - elif role == QDialogButtonBox.ButtonRole.RejectRole: + elif role == QtRoleReject: self.close() return @@ -812,7 +811,7 @@ class GuiPreferences(QDialog): """Open a dialog to select the backup folder.""" if path := QFileDialog.getExistingDirectory( self, self.tr("Backup Directory"), str(self.backupPath) or "", - options=QFileDialog.ShowDirsOnly + options=QFileDialog.Option.ShowDirsOnly ): self.backupPath = path self.mainForm.setHelpText("backupPath", self.tr("Path: {0}").format(path)) diff --git a/novelwriter/dialogs/projectsettings.py b/novelwriter/dialogs/projectsettings.py index c24137fc..4e234f76 100644 --- a/novelwriter/dialogs/projectsettings.py +++ b/novelwriter/dialogs/projectsettings.py @@ -26,12 +26,12 @@ from __future__ import annotations import logging -from PyQt5.QtGui import QCloseEvent, QColor, QIcon, QPixmap from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot +from PyQt5.QtGui import QCloseEvent, QColor, QIcon, QPixmap from PyQt5.QtWidgets import ( - QColorDialog, QDialog, QDialogButtonBox, QHBoxLayout, QLineEdit, - QPushButton, QStackedWidget, QTreeWidget, QTreeWidgetItem, QVBoxLayout, - QWidget, qApp + QApplication, QColorDialog, QDialog, QDialogButtonBox, QHBoxLayout, + QLineEdit, QPushButton, QStackedWidget, QTreeWidget, QTreeWidgetItem, + QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED @@ -40,6 +40,7 @@ from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrol from novelwriter.extensions.modified import NComboBox, NIconToolButton from novelwriter.extensions.pagedsidebar import NPagedSideBar from novelwriter.extensions.switch import NSwitch +from novelwriter.types import QtDialogCancel, QtDialogSave, QtUserRole logger = logging.getLogger(__name__) @@ -83,9 +84,7 @@ class GuiProjectSettings(QDialog): self.sidebar.buttonClicked.connect(self._sidebarClicked) # Buttons - self.buttonBox = QDialogButtonBox( - QDialogButtonBox.StandardButton.Save | QDialogButtonBox.StandardButton.Cancel - ) + self.buttonBox = QDialogButtonBox(QtDialogSave | QtDialogCancel, self) self.buttonBox.accepted.connect(self._doSave) self.buttonBox.rejected.connect(self.close) @@ -195,7 +194,7 @@ class GuiProjectSettings(QDialog): project.data.setAutoReplace(newList) self.newProjectSettingsReady.emit(rebuildTrees) - qApp.processEvents() + QApplication.processEvents() self.close() return @@ -305,9 +304,9 @@ class _StatusPage(NFixedPage): COL_LABEL = 0 COL_USAGE = 1 - KEY_ROLE = Qt.ItemDataRole.UserRole - COL_ROLE = Qt.ItemDataRole.UserRole + 1 - NUM_ROLE = Qt.ItemDataRole.UserRole + 2 + KEY_ROLE = QtUserRole + COL_ROLE = QtUserRole + 1 + NUM_ROLE = QtUserRole + 2 def __init__(self, parent: QWidget, isStatus: bool) -> None: super().__init__(parent=parent) @@ -604,7 +603,7 @@ class _ReplacePage(NFixedPage): ) # List Box - self.listBox = QTreeWidget() + self.listBox = QTreeWidget(self) self.listBox.setHeaderLabels([self.tr("Keyword"), self.tr("Replace With")]) self.listBox.setColumnWidth(self.COL_KEY, wCol0) self.listBox.setIndentation(0) @@ -614,7 +613,7 @@ class _ReplacePage(NFixedPage): newItem = QTreeWidgetItem(["<%s>" % aKey, aVal]) self.listBox.addTopLevelItem(newItem) - self.listBox.sortByColumn(self.COL_KEY, Qt.AscendingOrder) + self.listBox.sortByColumn(self.COL_KEY, Qt.SortOrder.AscendingOrder) self.listBox.setSortingEnabled(True) # List Controls diff --git a/novelwriter/dialogs/quotes.py b/novelwriter/dialogs/quotes.py index dac6fbc3..d728994f 100644 --- a/novelwriter/dialogs/quotes.py +++ b/novelwriter/dialogs/quotes.py @@ -26,7 +26,7 @@ from __future__ import annotations import logging from PyQt5.QtGui import QFontMetrics -from PyQt5.QtCore import QSize, Qt, pyqtSlot +from PyQt5.QtCore import QSize, pyqtSlot from PyQt5.QtWidgets import ( QDialog, QDialogButtonBox, QFrame, QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QVBoxLayout, QWidget @@ -34,7 +34,7 @@ from PyQt5.QtWidgets import ( from novelwriter import CONFIG from novelwriter.constants import trConst, nwQuotes -from novelwriter.types import QtAlignCenter, QtAlignTop +from novelwriter.types import QtAlignCenter, QtAlignTop, QtDialogCancel, QtDialogOk, QtUserRole logger = logging.getLogger(__name__) @@ -43,7 +43,7 @@ class GuiQuoteSelect(QDialog): _selected = "" - D_KEY = Qt.ItemDataRole.UserRole + D_KEY = QtUserRole def __init__(self, parent: QWidget, current: str = '"') -> None: super().__init__(parent=parent) @@ -66,14 +66,14 @@ class GuiQuoteSelect(QDialog): lblFont.setPointSizeF(4*lblFont.pointSizeF()) # Preview Label - self.previewLabel = QLabel(current) + self.previewLabel = QLabel(current, self) self.previewLabel.setFont(lblFont) self.previewLabel.setFixedSize(QSize(pxW, pxH)) self.previewLabel.setAlignment(QtAlignCenter) - self.previewLabel.setFrameStyle(QFrame.Box | QFrame.Plain) + self.previewLabel.setFrameStyle(QFrame.Shape.Box | QFrame.Shadow.Plain) # Quote Symbols - self.listBox = QListWidget() + self.listBox = QListWidget(self) self.listBox.itemSelectionChanged.connect(self._selectedSymbol) minSize = 100 @@ -90,7 +90,7 @@ class GuiQuoteSelect(QDialog): self.listBox.setMinimumHeight(CONFIG.pxInt(150)) # Buttons - self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) @@ -123,7 +123,7 @@ class GuiQuoteSelect(QDialog): def getQuote(cls, parent: QWidget, current: str = "") -> tuple[str, bool]: """Pop the dialog and return the result.""" cls = GuiQuoteSelect(parent, current=current) - cls.exec_() + cls.exec() quote = cls._selected accepted = cls.result() == QDialog.DialogCode.Accepted cls.deleteLater() diff --git a/novelwriter/dialogs/wordlist.py b/novelwriter/dialogs/wordlist.py index cd2908a9..c82ca3d6 100644 --- a/novelwriter/dialogs/wordlist.py +++ b/novelwriter/dialogs/wordlist.py @@ -28,11 +28,11 @@ import logging from typing import TYPE_CHECKING from pathlib import Path -from PyQt5.QtGui import QCloseEvent from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot +from PyQt5.QtGui import QCloseEvent from PyQt5.QtWidgets import ( - QAbstractItemView, QDialog, QDialogButtonBox, QFileDialog, QHBoxLayout, - QLineEdit, QListWidget, QVBoxLayout, qApp + QAbstractItemView, QApplication, QDialog, QDialogButtonBox, QFileDialog, + QHBoxLayout, QLineEdit, QListWidget, QVBoxLayout ) from novelwriter import CONFIG, SHARED @@ -40,6 +40,7 @@ from novelwriter.common import formatFileFilter from novelwriter.core.spellcheck import UserDictionary from novelwriter.extensions.configlayout import NColourLabel from novelwriter.extensions.modified import NIconToolButton +from novelwriter.types import QtDialogClose, QtDialogSave if TYPE_CHECKING: # pragma: no cover from novelwriter.guimain import GuiMain @@ -91,7 +92,7 @@ class GuiWordList(QDialog): # List Box self.listBox = QListWidget(self) - self.listBox.setDragDropMode(QAbstractItemView.NoDragDrop) + self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop) self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) self.listBox.setSortingEnabled(True) @@ -110,7 +111,7 @@ class GuiWordList(QDialog): self.editBox.addWidget(self.delButton, 0) # Buttons - self.buttonBox = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Close) + self.buttonBox = QDialogButtonBox(QtDialogSave | QtDialogClose, self) self.buttonBox.accepted.connect(self._doSave) self.buttonBox.rejected.connect(self.close) @@ -157,7 +158,7 @@ class GuiWordList(QDialog): self.newEntry.setText("") self.listBox.clearSelection() self._addWord(word) - if items := self.listBox.findItems(word, Qt.MatchExactly): + if items := self.listBox.findItems(word, Qt.MatchFlag.MatchExactly): self.listBox.setCurrentItem(items[0]) self.listBox.scrollToItem(items[0], QAbstractItemView.ScrollHint.PositionAtCenter) return @@ -177,7 +178,7 @@ class GuiWordList(QDialog): userDict.add(word) userDict.save() self.newWordListReady.emit() - qApp.processEvents() + QApplication.processEvents() self.close() return @@ -244,7 +245,7 @@ class GuiWordList(QDialog): def _addWord(self, word: str) -> None: """Add a single word to the list.""" - if word and not self.listBox.findItems(word, Qt.MatchExactly): + if word and not self.listBox.findItems(word, Qt.MatchFlag.MatchExactly): self.listBox.addItem(word) self._changed = True return diff --git a/novelwriter/error.py b/novelwriter/error.py index 37b40857..0801d55d 100644 --- a/novelwriter/error.py +++ b/novelwriter/error.py @@ -29,11 +29,11 @@ import logging from typing import TYPE_CHECKING -from PyQt5.QtGui import QFont, QFontDatabase from PyQt5.QtCore import Qt, pyqtSlot +from PyQt5.QtGui import QFont, QFontDatabase from PyQt5.QtWidgets import ( - QWidget, qApp, QDialog, QGridLayout, QStyle, QPlainTextEdit, QLabel, - QDialogButtonBox + QApplication, QWidget, QDialog, QGridLayout, QStyle, QPlainTextEdit, + QLabel, QDialogButtonBox ) if TYPE_CHECKING: # pragma: no cover @@ -74,7 +74,9 @@ class NWErrorMessage(QDialog): # Widgets self.msgIcon = QLabel() self.msgIcon.setPixmap( - qApp.style().standardIcon(QStyle.SP_MessageBoxCritical).pixmap(64, 64) + QApplication.style().standardIcon( + QStyle.StandardPixmap.SP_MessageBoxCritical + ).pixmap(64, 64) ) self.msgHead = QLabel() self.msgHead.setOpenExternalLinks(True) @@ -88,7 +90,7 @@ class NWErrorMessage(QDialog): self.msgBody.setFont(font) self.msgBody.setReadOnly(True) - self.btnBox = QDialogButtonBox(QDialogButtonBox.Close) + self.btnBox = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) self.btnBox.rejected.connect(self._doClose) # Assemble @@ -179,14 +181,14 @@ class NWErrorMessage(QDialog): def exceptionHandler(exType: type, exValue: BaseException, exTrace: TracebackType) -> None: """Function to catch unhandled global exceptions.""" from traceback import print_tb - from PyQt5.QtWidgets import qApp + from PyQt5.QtWidgets import QApplication logger.critical("%s: %s", exType.__name__, str(exValue)) print_tb(exTrace) try: nwGUI = None - for qWin in qApp.topLevelWidgets(): + for qWin in QApplication.topLevelWidgets(): if qWin.objectName() == "GuiMain": nwGUI = qWin break @@ -197,7 +199,7 @@ def exceptionHandler(exType: type, exValue: BaseException, exTrace: TracebackTyp errMsg = NWErrorMessage(nwGUI) errMsg.setMessage(exType, exValue, exTrace) - errMsg.exec_() + errMsg.exec() try: # Try a controlled shutdown @@ -209,7 +211,7 @@ def exceptionHandler(exType: type, exValue: BaseException, exTrace: TracebackTyp logger.critical("Could not close the project before exiting") logger.critical(formatException(exc)) - qApp.exit(1) + QApplication.exit(1) except Exception as exc: logger.critical(formatException(exc)) diff --git a/novelwriter/extensions/circularprogress.py b/novelwriter/extensions/circularprogress.py index 70d84f31..bbc2f64a 100644 --- a/novelwriter/extensions/circularprogress.py +++ b/novelwriter/extensions/circularprogress.py @@ -25,11 +25,13 @@ from __future__ import annotations from math import ceil +from PyQt5.QtCore import QRect from PyQt5.QtGui import QBrush, QColor, QPaintEvent, QPainter, QPen -from PyQt5.QtCore import QRect, Qt from PyQt5.QtWidgets import QProgressBar, QSizePolicy, QWidget -from novelwriter.types import QtAlignCenter +from novelwriter.types import ( + QtPaintAnitAlias, QtAlignCenter, QtRoundCap, QtSolidLine, QtTransparent +) class NProgressCircle(QProgressBar): @@ -50,14 +52,14 @@ class NProgressCircle(QProgressBar): self._point = point self._dRect = QRect(0, 0, size, size) self._cRect = QRect(point, point, size - 2*point, size - 2*point) - self._dPen = QPen(Qt.transparent) - self._dBrush = QBrush(Qt.transparent) + self._dPen = QPen(QtTransparent) + self._dBrush = QBrush(QtTransparent) self.setColours( track=self.palette().alternateBase().color(), bar=self.palette().highlight().color(), text=self.palette().text().color() ) - self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) self.setFixedWidth(size) self.setFixedHeight(size) return @@ -69,9 +71,9 @@ class NProgressCircle(QProgressBar): self._dPen = QPen(back) self._dBrush = QBrush(back) if isinstance(bar, QColor): - self._cPen = QPen(QBrush(bar), self._point, Qt.SolidLine, Qt.RoundCap) + self._cPen = QPen(QBrush(bar), self._point, QtSolidLine, QtRoundCap) if isinstance(track, QColor): - self._bPen = QPen(QBrush(track), self._point, Qt.SolidLine, Qt.RoundCap) + self._bPen = QPen(QBrush(track), self._point, QtSolidLine, QtRoundCap) if isinstance(text, QColor): self._tColor = text return @@ -87,7 +89,7 @@ class NProgressCircle(QProgressBar): progress = 100.0*self.value()/self.maximum() angle = ceil(16*3.6*progress) painter = QPainter(self) - painter.setRenderHint(QPainter.Antialiasing, True) + painter.setRenderHint(QtPaintAnitAlias, True) painter.setPen(self._dPen) painter.setBrush(self._dBrush) painter.drawEllipse(self._dRect) diff --git a/novelwriter/extensions/configlayout.py b/novelwriter/extensions/configlayout.py index 1357ea19..cdfcbffe 100644 --- a/novelwriter/extensions/configlayout.py +++ b/novelwriter/extensions/configlayout.py @@ -258,7 +258,7 @@ class NColourLabel(QLabel): font.setWeight(QFont.Weight.Bold if bold else QFont.Weight.Normal) if color: colour = self.palette() - colour.setColor(QPalette.WindowText, color) + colour.setColor(QPalette.ColorRole.WindowText, color) self.setPalette(colour) self.setFont(font) diff --git a/novelwriter/extensions/pagedsidebar.py b/novelwriter/extensions/pagedsidebar.py index 5fb15516..a3c53455 100644 --- a/novelwriter/extensions/pagedsidebar.py +++ b/novelwriter/extensions/pagedsidebar.py @@ -32,7 +32,7 @@ from PyQt5.QtWidgets import ( QStyleOptionToolButton, QToolBar, QToolButton, QWidget ) -from novelwriter.types import QtAlignLeft +from novelwriter.types import QtPaintAnitAlias, QtAlignLeft, QtMouseOver, QtNoBrush, QtNoPen class NPagedSideBar(QToolBar): @@ -56,10 +56,10 @@ class NPagedSideBar(QToolBar): self._group.buttonClicked.connect(self._buttonClicked) self.setMovable(False) - self.setOrientation(Qt.Vertical) + self.setOrientation(Qt.Orientation.Vertical) stretch = QWidget(self) - stretch.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + stretch.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self._stretchAction = self.addWidget(stretch) return @@ -119,13 +119,13 @@ class _NPagedToolButton(QToolButton): def __init__(self, parent: QWidget) -> None: super().__init__(parent=parent) - self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) self.setCheckable(True) fH = self.fontMetrics().height() self._bH = round(fH * 1.7) self._tM = (self._bH - fH)//2 - self._lM = 3*self.style().pixelMetric(QStyle.PM_ButtonMargin)//2 + self._lM = 3*self.style().pixelMetric(QStyle.PixelMetric.PM_ButtonMargin)//2 self._cR = self._lM//2 self._aH = 2*fH//7 self.setFixedHeight(self._bH) @@ -145,15 +145,15 @@ class _NPagedToolButton(QToolButton): opt.initFrom(self) paint = QPainter(self) - paint.setRenderHint(QPainter.Antialiasing, True) - paint.setPen(Qt.NoPen) - paint.setBrush(Qt.NoBrush) + paint.setRenderHint(QtPaintAnitAlias, True) + paint.setPen(QtNoPen) + paint.setBrush(QtNoBrush) width = self.width() height = self.height() palette = self.palette() - if opt.state & QStyle.State_MouseOver == QStyle.State_MouseOver: + if opt.state & QtMouseOver == QtMouseOver: backCol = palette.base() paint.setBrush(backCol) paint.setOpacity(0.75) @@ -197,12 +197,12 @@ class _NPagedToolLabel(QLabel): def __init__(self, parent: QWidget, textColor: QColor | None = None) -> None: super().__init__(parent=parent) - self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) fH = self.fontMetrics().height() self._bH = round(fH * 1.7) self._tM = (self._bH - fH)//2 - self._lM = self.style().pixelMetric(QStyle.PM_ButtonMargin)//2 + self._lM = self.style().pixelMetric(QStyle.PixelMetric.PM_ButtonMargin)//2 self.setFixedHeight(self._bH) self._textCol = textColor or self.palette().text().color() @@ -214,8 +214,8 @@ class _NPagedToolLabel(QLabel): label that matches the button style. """ paint = QPainter(self) - paint.setRenderHint(QPainter.Antialiasing, True) - paint.setPen(Qt.NoPen) + paint.setRenderHint(QtPaintAnitAlias, True) + paint.setPen(QtNoPen) width = self.width() height = self.height() diff --git a/novelwriter/extensions/simpleprogress.py b/novelwriter/extensions/simpleprogress.py index 73452ad8..f350d394 100644 --- a/novelwriter/extensions/simpleprogress.py +++ b/novelwriter/extensions/simpleprogress.py @@ -28,6 +28,8 @@ from math import ceil from PyQt5.QtGui import QPaintEvent, QPainter from PyQt5.QtWidgets import QProgressBar, QWidget +from novelwriter.types import QtPaintAnitAlias + class NProgressSimple(QProgressBar): """Extension: Simple Progress Widget @@ -44,7 +46,7 @@ class NProgressSimple(QProgressBar): if (value := self.value()) > 0: progress = ceil(self.width()*float(value)/self.maximum()) painter = QPainter(self) - painter.setRenderHint(QPainter.Antialiasing, True) + painter.setRenderHint(QtPaintAnitAlias, True) painter.setPen(self.palette().highlight().color()) painter.setBrush(self.palette().highlight()) painter.drawRect(0, 0, progress, self.height()) diff --git a/novelwriter/extensions/statusled.py b/novelwriter/extensions/statusled.py index 77006a02..afd641fb 100644 --- a/novelwriter/extensions/statusled.py +++ b/novelwriter/extensions/statusled.py @@ -30,6 +30,8 @@ from typing import Literal from PyQt5.QtGui import QColor, QPaintEvent, QPainter from PyQt5.QtWidgets import QAbstractButton, QWidget +from novelwriter.types import QtPaintAnitAlias + logger = logging.getLogger(__name__) @@ -67,7 +69,7 @@ class StatusLED(QAbstractButton): def paintEvent(self, event: QPaintEvent) -> None: """Draw the LED.""" painter = QPainter(self) - painter.setRenderHint(QPainter.Antialiasing, True) + painter.setRenderHint(QtPaintAnitAlias, True) painter.setPen(self.palette().dark().color()) painter.setBrush(self._theCol) painter.setOpacity(1.0) diff --git a/novelwriter/extensions/switch.py b/novelwriter/extensions/switch.py index 5d020385..e35bd79a 100644 --- a/novelwriter/extensions/switch.py +++ b/novelwriter/extensions/switch.py @@ -28,6 +28,7 @@ from PyQt5.QtCore import QEvent, QPropertyAnimation, Qt, pyqtProperty from PyQt5.QtWidgets import QAbstractButton, QSizePolicy, QWidget from novelwriter import CONFIG, SHARED +from novelwriter.types import QtPaintAnitAlias, QtMouseLeft, QtNoPen class NSwitch(QAbstractButton): @@ -45,7 +46,7 @@ class NSwitch(QAbstractButton): self._rR = self._xR - self._rB self.setCheckable(True) - self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) self.setFixedWidth(self._xW) self.setFixedHeight(self._xH) self._offset = self._xR @@ -89,8 +90,8 @@ class NSwitch(QAbstractButton): def paintEvent(self, event: QPaintEvent) -> None: """Drawing the switch itself.""" painter = QPainter(self) - painter.setRenderHint(QPainter.Antialiasing, True) - painter.setPen(Qt.NoPen) + painter.setRenderHint(QtPaintAnitAlias, True) + painter.setPen(QtNoPen) palette = self.palette() if self.isChecked(): @@ -119,7 +120,7 @@ class NSwitch(QAbstractButton): def mouseReleaseEvent(self, event: QMouseEvent) -> None: """Animate the switch on mouse release.""" super().mouseReleaseEvent(event) - if event.button() == Qt.LeftButton: + if event.button() == QtMouseLeft: anim = QPropertyAnimation(self, b"offset", self) anim.setDuration(120) anim.setStartValue(self._offset) @@ -129,7 +130,7 @@ class NSwitch(QAbstractButton): def enterEvent(self, event: QEvent) -> None: """Change the cursor when hovering the button.""" - self.setCursor(Qt.PointingHandCursor) + self.setCursor(Qt.CursorShape.PointingHandCursor) super().enterEvent(event) return diff --git a/novelwriter/extensions/switchbox.py b/novelwriter/extensions/switchbox.py index e3913288..d41587ba 100644 --- a/novelwriter/extensions/switchbox.py +++ b/novelwriter/extensions/switchbox.py @@ -58,8 +58,8 @@ class NSwitchBox(QScrollArea): self._content = QGridLayout() self._content.setColumnStretch(1, 1) - self._widget = QWidget() - self._widget.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) + self._widget = QWidget(self) + self._widget.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Minimum) self._widget.setLayout(self._content) self.setWidgetResizable(True) @@ -69,7 +69,7 @@ class NSwitchBox(QScrollArea): def addLabel(self, text: str) -> None: """Add a header label to the content box.""" - label = QLabel(text) + label = QLabel(text, self) font = label.font() font.setBold(True) label.setFont(font) @@ -80,12 +80,12 @@ class NSwitchBox(QScrollArea): def addItem(self, qIcon: QIcon, text: str, identifier: str, default: bool = False) -> None: """Add an item to the content box.""" - icon = QLabel("") + icon = QLabel("", self) icon.setAlignment(QtAlignRightMiddle) icon.setPixmap(qIcon.pixmap(self._sIcon, self._sIcon)) self._content.addWidget(icon, self._index, 0, QtAlignLeft) - label = QLabel(text) + label = QLabel(text, self) self._content.addWidget(label, self._index, 1, QtAlignLeft) switch = NSwitch(self, height=self._hSwitch) @@ -100,7 +100,7 @@ class NSwitchBox(QScrollArea): def addSeparator(self) -> None: """Add a blank entry in the content box.""" - spacer = QWidget() + spacer = QWidget(self) spacer.setFixedHeight(int(0.5*self._sIcon)) self._content.addWidget(spacer, self._index, 0, 1, 3, QtAlignLeft) self._widgets.append(spacer) diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index fbf4f224..8c773355 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -47,8 +47,8 @@ from PyQt5.QtGui import ( QPixmap, QResizeEvent, QTextBlock, QTextCursor, QTextDocument, QTextOption ) from PyQt5.QtWidgets import ( - QAction, QFrame, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QMenu, - QPlainTextEdit, QShortcut, QToolBar, QVBoxLayout, QWidget, qApp + QAction, QApplication, QFrame, QGridLayout, QHBoxLayout, QLabel, QLineEdit, + QMenu, QPlainTextEdit, QShortcut, QToolBar, QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED @@ -64,7 +64,9 @@ from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON from novelwriter.text.counting import standardCounter from novelwriter.tools.lipsum import GuiLipsum from novelwriter.types import ( - QtAlignCenterTop, QtAlignJustify, QtAlignLeft, QtAlignLeftTop, QtAlignRight + QtAlignCenterTop, QtAlignJustify, QtAlignLeft, QtAlignLeftTop, + QtAlignRight, QtKeepAnchor, QtModCtrl, QtMouseLeft, QtModeNone, QtModShift, + QtMoveAnchor, QtMoveLeft, QtMoveRight ) if TYPE_CHECKING: # pragma: no cover @@ -181,12 +183,12 @@ class GuiDocEditor(QPlainTextEdit): self.keyContext.activated.connect(self._openContextFromCursor) self.followTag1 = QShortcut(self) - self.followTag1.setKey(Qt.Key.Key_Return | Qt.KeyboardModifier.ControlModifier) + self.followTag1.setKey(Qt.Key.Key_Return | QtModCtrl) self.followTag1.setContext(Qt.ShortcutContext.WidgetShortcut) self.followTag1.activated.connect(self._processTag) self.followTag2 = QShortcut(self) - self.followTag2.setKey(Qt.Key.Key_Enter | Qt.KeyboardModifier.ControlModifier) + self.followTag2.setKey(Qt.Key.Key_Enter | QtModCtrl) self.followTag2.setContext(Qt.ShortcutContext.WidgetShortcut) self.followTag2.activated.connect(self._processTag) @@ -393,13 +395,13 @@ class GuiDocEditor(QPlainTextEdit): self.clearEditor() return False - qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) + QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) self._docHandle = tHandle self._allowAutoReplace(False) self._qDocument.setTextContent(docText, tHandle) self._allowAutoReplace(True) - qApp.processEvents() + QApplication.processEvents() self._lastEdit = time() self._lastActive = time() @@ -423,12 +425,12 @@ class GuiDocEditor(QPlainTextEdit): self.setPlainText("") self.setCursorPosition(0) - qApp.processEvents() + QApplication.processEvents() self.setDocumentChanged(False) self._qDocument.clearUndoRedoStacks() self.docToolBar.setVisible(CONFIG.showEditToolBar) - qApp.restoreOverrideCursor() + QApplication.restoreOverrideCursor() # Update the status bar if self._nwItem is not None: @@ -445,11 +447,11 @@ class GuiDocEditor(QPlainTextEdit): """Replace the text of the current document with the provided text. This also clears undo history. """ - qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) + QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) self.setPlainText(text) self.updateDocMargins() self.setDocumentChanged(True) - qApp.restoreOverrideCursor() + QApplication.restoreOverrideCursor() return def saveText(self) -> bool: @@ -536,7 +538,7 @@ class GuiDocEditor(QPlainTextEdit): while self.cursorRect().bottom() > vH and count < 100000: vBar.setValue(vBar.value() + 1) count += 1 - qApp.processEvents() + QApplication.processEvents() return def updateDocMargins(self) -> None: @@ -655,8 +657,8 @@ class GuiDocEditor(QPlainTextEdit): """Make a text selection.""" if start >= 0 and length > 0: cursor = self.textCursor() - cursor.setPosition(start, QTextCursor.MoveMode.MoveAnchor) - cursor.setPosition(start + length, QTextCursor.MoveMode.KeepAnchor) + cursor.setPosition(start, QtMoveAnchor) + cursor.setPosition(start + length, QtKeepAnchor) self.setTextCursor(cursor) return @@ -699,9 +701,9 @@ class GuiDocEditor(QPlainTextEdit): """ logger.debug("Running spell checker") start = time() - qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) + QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) self._qDocument.syntaxHighlighter.rehighlight() - qApp.restoreOverrideCursor() + QApplication.restoreOverrideCursor() logger.debug("Document highlighted in %.3f ms", 1000*(time() - start)) self.statusMessage.emit(self.tr("Spell check complete")) return @@ -814,7 +816,7 @@ class GuiDocEditor(QPlainTextEdit): def anyFocus(self) -> bool: """Check if any widget or child widget has focus.""" - return self.hasFocus() or self.isAncestorOf(qApp.focusWidget()) + return self.hasFocus() or self.isAncestorOf(QApplication.focusWidget()) def revealLocation(self) -> None: """Tell the user where on the file system the file in the editor @@ -962,7 +964,7 @@ class GuiDocEditor(QPlainTextEdit): super().keyPressEvent(event) nPos = self.cursorRect().topLeft().y() kMod = event.modifiers() - okMod = kMod in (Qt.KeyboardModifier.NoModifier, Qt.KeyboardModifier.ShiftModifier) + okMod = kMod in (QtModeNone, QtModShift) okKey = event.key() not in self.MOVE_KEYS if nPos != cPos and okMod and okKey: mPos = CONFIG.autoScrollPos*0.01 * self.viewport().height() @@ -991,7 +993,7 @@ class GuiDocEditor(QPlainTextEdit): pressed, check if we're clicking on a tag, and trigger the follow tag function. """ - if qApp.keyboardModifiers() == Qt.KeyboardModifier.ControlModifier: + if QApplication.keyboardModifiers() == QtModCtrl: self._processTag(self.cursorForPosition(event.pos())) super().mouseReleaseEvent(event) return @@ -1091,8 +1093,8 @@ class GuiDocEditor(QPlainTextEdit): block = cursor.block() if block.isValid(): pos += block.position() - cursor.setPosition(pos, QTextCursor.MoveMode.MoveAnchor) - cursor.setPosition(pos + length, QTextCursor.MoveMode.KeepAnchor) + cursor.setPosition(pos, QtMoveAnchor) + cursor.setPosition(pos + length, QtKeepAnchor) cursor.insertText(text) self._completer.hide() return @@ -1152,9 +1154,7 @@ class GuiDocEditor(QPlainTextEdit): block = pCursor.block() sCursor = self.textCursor() sCursor.setPosition(block.position() + cPos) - sCursor.movePosition( - QTextCursor.MoveOperation.Right, QTextCursor.MoveMode.KeepAnchor, cLen - ) + sCursor.movePosition(QtMoveRight, QtKeepAnchor, cLen) if suggest: ctxMenu.addSeparator() ctxMenu.addAction(self.tr("Spelling Suggestion(s)")) @@ -1171,7 +1171,7 @@ class GuiDocEditor(QPlainTextEdit): action.triggered.connect(lambda: self._addWord(word, block)) # Execute the context menu - ctxMenu.exec_(self.viewport().mapToGlobal(pos)) + ctxMenu.exec(self.viewport().mapToGlobal(pos)) ctxMenu.deleteLater() return @@ -1350,8 +1350,8 @@ class GuiDocEditor(QPlainTextEdit): else: resIdx = 0 if doLoop else maxIdx - cursor.setPosition(resS[resIdx], QTextCursor.MoveMode.MoveAnchor) - cursor.setPosition(resE[resIdx], QTextCursor.MoveMode.KeepAnchor) + cursor.setPosition(resS[resIdx], QtMoveAnchor) + cursor.setPosition(resE[resIdx], QtKeepAnchor) self.setTextCursor(cursor) self.docSearch.setResultCount(resIdx + 1, len(resS)) @@ -1397,8 +1397,8 @@ class GuiDocEditor(QPlainTextEdit): break if hasSelection: - cursor.setPosition(origA, QTextCursor.MoveMode.MoveAnchor) - cursor.setPosition(origB, QTextCursor.MoveMode.KeepAnchor) + cursor.setPosition(origA, QtMoveAnchor) + cursor.setPosition(origB, QtKeepAnchor) else: cursor.setPosition(origA) @@ -1501,8 +1501,8 @@ class GuiDocEditor(QPlainTextEdit): if blockS != blockE: posE = blockS.position() + blockS.length() - 1 cursor.clearSelection() - cursor.setPosition(posS, QTextCursor.MoveMode.MoveAnchor) - cursor.setPosition(posE, QTextCursor.MoveMode.KeepAnchor) + cursor.setPosition(posS, QtMoveAnchor) + cursor.setPosition(posE, QtKeepAnchor) self.setTextCursor(cursor) numB = 0 @@ -1579,8 +1579,8 @@ class GuiDocEditor(QPlainTextEdit): if select == _SelectAction.MOVE_AFTER: cursor.setPosition(posE + len(before + after)) elif select == _SelectAction.KEEP_SELECTION: - cursor.setPosition(posE + len(before), QTextCursor.MoveMode.MoveAnchor) - cursor.setPosition(posS + len(before), QTextCursor.MoveMode.KeepAnchor) + cursor.setPosition(posE + len(before), QtMoveAnchor) + cursor.setPosition(posS + len(before), QtKeepAnchor) elif select == _SelectAction.KEEP_POSITION: cursor.setPosition(posO + len(before)) @@ -1602,9 +1602,7 @@ class GuiDocEditor(QPlainTextEdit): self._allowAutoReplace(False) for posC in range(posS, posE+1): cursor.setPosition(posC) - cursor.movePosition( - QTextCursor.MoveOperation.Left, QTextCursor.MoveMode.KeepAnchor, 2 - ) + cursor.movePosition(QtMoveLeft, QtKeepAnchor, 2) selText = cursor.selectedText() nS = len(selText) @@ -1624,16 +1622,12 @@ class GuiDocEditor(QPlainTextEdit): cursor.setPosition(posC) if pC in closeCheck: cursor.beginEditBlock() - cursor.movePosition( - QTextCursor.MoveOperation.Left, QTextCursor.MoveMode.KeepAnchor, 1 - ) + cursor.movePosition(QtMoveLeft, QtKeepAnchor, 1) cursor.insertText(oQuote) cursor.endEditBlock() else: cursor.beginEditBlock() - cursor.movePosition( - QTextCursor.MoveOperation.Left, QTextCursor.MoveMode.KeepAnchor, 1 - ) + cursor.movePosition(QtMoveLeft, QtKeepAnchor, 1) cursor.insertText(cQuote) cursor.endEditBlock() @@ -1849,9 +1843,7 @@ class GuiDocEditor(QPlainTextEdit): cursor.beginEditBlock() cursor.clearSelection() cursor.setPosition(rS) - cursor.movePosition( - QTextCursor.MoveOperation.Right, QTextCursor.MoveMode.KeepAnchor, rE-rS - ) + cursor.movePosition(QtMoveRight, QtKeepAnchor, rE-rS) cursor.insertText(cleanText.rstrip() + "\n") cursor.endEditBlock() @@ -1912,7 +1904,7 @@ class GuiDocEditor(QPlainTextEdit): ).format(tag)): itemClass = nwKeyWords.KEY_CLASS.get(tBits[0], nwItemClass.NO_CLASS) self.requestNewNoteCreation.emit(tag, itemClass) - qApp.processEvents() + QApplication.processEvents() self._qDocument.syntaxHighlighter.rehighlightBlock(block) return nwTrinary.POSITIVE if exist else nwTrinary.NEGATIVE @@ -2017,9 +2009,7 @@ class GuiDocEditor(QPlainTextEdit): tInsert = tInsert + self._typPadChar if nDelete > 0: - cursor.movePosition( - QTextCursor.MoveOperation.Left, QTextCursor.MoveMode.KeepAnchor, nDelete - ) + cursor.movePosition(QtMoveLeft, QtKeepAnchor, nDelete) cursor.insertText(tInsert) return @@ -2075,8 +2065,8 @@ class GuiDocEditor(QPlainTextEdit): return cursor cursor.clearSelection() - cursor.setPosition(sPos, QTextCursor.MoveMode.MoveAnchor) - cursor.setPosition(ePos, QTextCursor.MoveMode.KeepAnchor) + cursor.setPosition(sPos, QtMoveAnchor) + cursor.setPosition(ePos, QtKeepAnchor) self.setTextCursor(cursor) @@ -2100,8 +2090,8 @@ class GuiDocEditor(QPlainTextEdit): posE = cursor.selectionEnd() selTxt = cursor.selectedText() if selTxt.startswith(nwUnicode.U_PSEP): - cursor.setPosition(posS+1, QTextCursor.MoveMode.MoveAnchor) - cursor.setPosition(posE, QTextCursor.MoveMode.KeepAnchor) + cursor.setPosition(posS+1, QtMoveAnchor) + cursor.setPosition(posE, QtKeepAnchor) self.setTextCursor(cursor) @@ -2440,11 +2430,11 @@ class GuiDocEditSearch(QFrame): self.searchOpt.setIconSize(iSz) self.searchOpt.setContentsMargins(0, 0, 0, 0) - self.searchLabel = QLabel(self.tr("Search")) + self.searchLabel = QLabel(self.tr("Search"), self) self.searchLabel.setFont(self.boxFont) self.searchLabel.setIndent(CONFIG.pxInt(6)) - self.resultLabel = QLabel("?/?") + self.resultLabel = QLabel("?/?", self) self.resultLabel.setFont(self.boxFont) self.resultLabel.setMinimumWidth(SHARED.theme.getTextWidth("?/?", self.boxFont)) @@ -2627,7 +2617,7 @@ class GuiDocEditSearch(QFrame): def updateTheme(self) -> None: """Update theme elements.""" - qPalette = qApp.palette() + qPalette = QApplication.palette() self.setPalette(qPalette) self.searchBox.setPalette(qPalette) self.replaceBox.setPalette(qPalette) @@ -2713,9 +2703,7 @@ class GuiDocEditSearch(QFrame): @pyqtSlot() def _doSearch(self) -> None: """Call the search action function for the document editor.""" - self.docEditor.findNext(goBack=( - qApp.keyboardModifiers() == Qt.KeyboardModifier.ShiftModifier) - ) + self.docEditor.findNext(goBack=(QApplication.keyboardModifiers() == QtModShift)) return @pyqtSlot() @@ -3002,7 +2990,7 @@ class GuiDocEditHeader(QWidget): """Capture a click on the title and ensure that the item is selected in the project tree. """ - if event.button() == Qt.MouseButton.LeftButton: + if event.button() == QtMouseLeft: self.docEditor.requestProjectItemSelected.emit(self._docHandle or "", True) return @@ -3048,7 +3036,7 @@ class GuiDocEditFooter(QWidget): self.statusIcon.setFixedHeight(iPx) self.statusIcon.setAlignment(QtAlignLeftTop) - self.statusText = QLabel(self.tr("Status")) + self.statusText = QLabel(self.tr("Status"), self) self.statusText.setIndent(0) self.statusText.setMargin(0) self.statusText.setContentsMargins(0, 0, 0, 0) diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py index 6e65ac0d..27ae33be 100644 --- a/novelwriter/gui/dochighlight.py +++ b/novelwriter/gui/dochighlight.py @@ -116,7 +116,7 @@ class GuiDocHighlighter(QSyntaxHighlighter): # Cache Spell Error Format self._spellErr = QTextCharFormat() self._spellErr.setUnderlineColor(SHARED.theme.colSpell) - self._spellErr.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline) + self._spellErr.setUnderlineStyle(QTextCharFormat.UnderlineStyle.SpellCheckUnderline) # Multiple or Trailing Spaces if CONFIG.showMultiSpaces: @@ -402,16 +402,16 @@ class GuiDocHighlighter(QSyntaxHighlighter): if style is not None: styles = style.split(",") if "bold" in styles: - charFormat.setFontWeight(QFont.Bold) + charFormat.setFontWeight(QFont.Weight.Bold) if "italic" in styles: charFormat.setFontItalic(True) if "strike" in styles: charFormat.setFontStrikeOut(True) if "errline" in styles: charFormat.setUnderlineColor(SHARED.theme.colError) - charFormat.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline) + charFormat.setUnderlineStyle(QTextCharFormat.UnderlineStyle.SpellCheckUnderline) if "background" in styles and color is not None: - charFormat.setBackground(QBrush(color, Qt.SolidPattern)) + charFormat.setBackground(QBrush(color, Qt.BrushStyle.SolidPattern)) if size is not None: charFormat.setFontPointSize(int(round(size*CONFIG.textSize))) diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py index 4e4eee8d..bc5caeb5 100644 --- a/novelwriter/gui/docviewer.py +++ b/novelwriter/gui/docviewer.py @@ -36,8 +36,8 @@ from PyQt5.QtGui import ( QTextOption ) from PyQt5.QtWidgets import ( - QAction, QFrame, QHBoxLayout, QLabel, QMenu, QTextBrowser, QToolButton, - QWidget, qApp + QAction, QApplication, QFrame, QHBoxLayout, QLabel, QMenu, QTextBrowser, + QToolButton, QWidget ) from novelwriter import CONFIG, SHARED @@ -49,7 +49,9 @@ from novelwriter.error import logException from novelwriter.extensions.eventfilters import WheelEventFilter from novelwriter.extensions.modified import NIconToolButton from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON -from novelwriter.types import QtAlignCenterTop, QtAlignJustify +from novelwriter.types import ( + QtAlignCenterTop, QtAlignJustify, QtKeepAnchor, QtMouseLeft, QtMoveAnchor +) logger = logging.getLogger(__name__) @@ -195,7 +197,7 @@ class GuiDocViewer(QTextBrowser): return False logger.debug("Generating preview for item '%s'", tHandle) - qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) + QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) sPos = self.verticalScrollBar().value() aDoc = ToHtml(SHARED.project) @@ -217,7 +219,7 @@ class GuiDocViewer(QTextBrowser): logger.error("Failed to generate preview for document with handle '%s'", tHandle) logException() self.setText(self.tr("An error occurred while generating the preview.")) - qApp.restoreOverrideCursor() + QApplication.restoreOverrideCursor() return False # Refresh the tab stops @@ -250,7 +252,7 @@ class GuiDocViewer(QTextBrowser): # Since we change the content while it may still be rendering, we mark # the document dirty again to make sure it's re-rendered properly. self.redrawText() - qApp.restoreOverrideCursor() + QApplication.restoreOverrideCursor() self.documentLoaded.emit(tHandle) return True @@ -410,7 +412,7 @@ class GuiDocViewer(QTextBrowser): ctxMenu.addAction(mnuSelPara) # Open the context menu - ctxMenu.exec_(self.viewport().mapToGlobal(point)) + ctxMenu.exec(self.viewport().mapToGlobal(point)) ctxMenu.deleteLater() return @@ -452,8 +454,8 @@ class GuiDocViewer(QTextBrowser): posE = cursor.selectionEnd() selTxt = cursor.selectedText() if selTxt.startswith(nwUnicode.U_PSEP): - cursor.setPosition(posS+1, QTextCursor.MoveMode.MoveAnchor) - cursor.setPosition(posE, QTextCursor.MoveMode.KeepAnchor) + cursor.setPosition(posS+1, QtMoveAnchor) + cursor.setPosition(posE, QtKeepAnchor) self.setTextCursor(cursor) @@ -635,7 +637,7 @@ class GuiDocViewHeader(QWidget): self.setAutoFillBackground(True) # Title Label - self.itemTitle = QLabel() + self.itemTitle = QLabel(self) self.itemTitle.setText("") self.itemTitle.setIndent(0) self.itemTitle.setMargin(0) @@ -826,7 +828,7 @@ class GuiDocViewHeader(QWidget): """Capture a click on the title and ensure that the item is selected in the project tree. """ - if event.button() == Qt.MouseButton.LeftButton: + if event.button() == QtMouseLeft: self.docViewer.requestProjectItemSelected.emit(self._docHandle, True) return diff --git a/novelwriter/gui/docviewerpanel.py b/novelwriter/gui/docviewerpanel.py index 0292e177..f96e44e6 100644 --- a/novelwriter/gui/docviewerpanel.py +++ b/novelwriter/gui/docviewerpanel.py @@ -40,6 +40,7 @@ from novelwriter.core.index import IndexHeading, IndexItem from novelwriter.enum import nwDocMode, nwItemClass from novelwriter.extensions.modified import NIconToolButton from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON +from novelwriter.types import QtDecoration, QtUserRole logger = logging.getLogger(__name__) @@ -232,7 +233,7 @@ class _ViewPanelBackRefs(QTreeWidget): C_VIEW = 2 C_TITLE = 3 - D_HANDLE = Qt.ItemDataRole.UserRole + D_HANDLE = QtUserRole def __init__(self, parent: GuiDocViewerPanel) -> None: super().__init__(parent=parent) @@ -349,7 +350,7 @@ class _ViewPanelBackRefs(QTreeWidget): trItem.setToolTip(self.C_DOC, nwItem.itemName) trItem.setIcon(self.C_EDIT, self._editIcon) trItem.setIcon(self.C_VIEW, self._viewIcon) - trItem.setData(self.C_TITLE, Qt.ItemDataRole.DecorationRole, hDec) + trItem.setData(self.C_TITLE, QtDecoration, hDec) trItem.setText(self.C_TITLE, hItem.title) trItem.setToolTip(self.C_TITLE, hItem.title) trItem.setData(self.C_DATA, self.D_HANDLE, tHandle) @@ -374,7 +375,7 @@ class _ViewPanelKeyWords(QTreeWidget): C_TITLE = 5 C_SHORT = 6 - D_TAG = Qt.ItemDataRole.UserRole + D_TAG = QtUserRole def __init__(self, parent: GuiDocViewerPanel, itemClass: nwItemClass) -> None: super().__init__(parent=parent) @@ -468,7 +469,7 @@ class _ViewPanelKeyWords(QTreeWidget): trItem.setIcon(self.C_DOC, docIcon) trItem.setText(self.C_DOC, nwItem.itemName) trItem.setToolTip(self.C_DOC, nwItem.itemName) - trItem.setData(self.C_TITLE, Qt.ItemDataRole.DecorationRole, hDec) + trItem.setData(self.C_TITLE, QtDecoration, hDec) trItem.setText(self.C_TITLE, hItem.title) trItem.setToolTip(self.C_TITLE, hItem.title) trItem.setText(self.C_SHORT, hItem.synopsis) diff --git a/novelwriter/gui/editordocument.py b/novelwriter/gui/editordocument.py index 04babe3f..0bbfd1b5 100644 --- a/novelwriter/gui/editordocument.py +++ b/novelwriter/gui/editordocument.py @@ -25,14 +25,14 @@ from __future__ import annotations import logging -from time import time from collections.abc import Iterable +from time import time from PyQt5.QtGui import QTextBlock, QTextCursor, QTextDocument from PyQt5.QtCore import QObject, pyqtSlot -from PyQt5.QtWidgets import QPlainTextDocumentLayout, qApp -from novelwriter import SHARED +from PyQt5.QtWidgets import QApplication, QPlainTextDocumentLayout +from novelwriter import SHARED from novelwriter.gui.dochighlight import GuiDocHighlighter, TextBlockData logger = logging.getLogger(__name__) @@ -86,7 +86,7 @@ class GuiTextDocument(QTextDocument): self.setUndoRedoEnabled(True) self.blockSignals(False) self._syntax.rehighlight() - qApp.processEvents() + QApplication.processEvents() tEnd = time() diff --git a/novelwriter/gui/itemdetails.py b/novelwriter/gui/itemdetails.py index 982770eb..5e9ed84d 100644 --- a/novelwriter/gui/itemdetails.py +++ b/novelwriter/gui/itemdetails.py @@ -115,25 +115,25 @@ class GuiItemDetails(QWidget): self.cCountName.setFont(fntLabel) self.cCountName.setAlignment(QtAlignRight) - self.cCountData = QLabel("") + self.cCountData = QLabel("", self) self.cCountData.setFont(fntValue) self.cCountData.setAlignment(QtAlignRight) # Word Count - self.wCountName = QLabel(" "+self.tr("Words")) + self.wCountName = QLabel(" "+self.tr("Words"), self) self.wCountName.setFont(fntLabel) self.wCountName.setAlignment(QtAlignRight) - self.wCountData = QLabel("") + self.wCountData = QLabel("", self) self.wCountData.setFont(fntValue) self.wCountData.setAlignment(QtAlignRight) # Paragraph Count - self.pCountName = QLabel(" "+self.tr("Paragraphs")) + self.pCountName = QLabel(" "+self.tr("Paragraphs"), self) self.pCountName.setFont(fntLabel) self.pCountName.setAlignment(QtAlignRight) - self.pCountData = QLabel("") + self.pCountData = QLabel("", self) self.pCountData.setFont(fntValue) self.pCountData.setAlignment(QtAlignRight) diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py index cb05df4d..ef52577d 100644 --- a/novelwriter/gui/noveltree.py +++ b/novelwriter/gui/noveltree.py @@ -31,8 +31,8 @@ from enum import Enum from time import time from typing import TYPE_CHECKING -from PyQt5.QtGui import QFocusEvent, QFont, QMouseEvent, QPalette, QResizeEvent from PyQt5.QtCore import QModelIndex, QPoint, Qt, pyqtSlot, pyqtSignal +from PyQt5.QtGui import QFocusEvent, QFont, QMouseEvent, QPalette, QResizeEvent from PyQt5.QtWidgets import ( QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView, QInputDialog, QMenu, QSizePolicy, QToolTip, QTreeWidget, QTreeWidgetItem, @@ -47,7 +47,7 @@ from novelwriter.enum import nwDocMode, nwItemClass, nwOutline from novelwriter.extensions.modified import NIconToolButton from novelwriter.extensions.novelselector import NovelSelector from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON -from novelwriter.types import QtAlignRight +from novelwriter.types import QtAlignRight, QtDecoration, QtMouseLeft, QtMouseMiddle, QtUserRole if TYPE_CHECKING: # pragma: no cover from novelwriter.guimain import GuiMain @@ -364,10 +364,10 @@ class GuiNovelTree(QTreeWidget): C_EXTRA = 2 C_MORE = 3 - D_HANDLE = Qt.ItemDataRole.UserRole - D_TITLE = Qt.ItemDataRole.UserRole + 1 - D_KEY = Qt.ItemDataRole.UserRole + 2 - D_EXTRA = Qt.ItemDataRole.UserRole + 3 + D_HANDLE = QtUserRole + D_TITLE = QtUserRole + 1 + D_KEY = QtUserRole + 2 + D_EXTRA = QtUserRole + 3 def __init__(self, novelView: GuiNovelView) -> None: super().__init__(parent=novelView) @@ -583,12 +583,12 @@ class GuiNovelTree(QTreeWidget): """ super().mousePressEvent(event) - if event.button() == Qt.MouseButton.LeftButton: + if event.button() == QtMouseLeft: selItem = self.indexAt(event.pos()) if not selItem.isValid(): self.clearSelection() - elif event.button() == Qt.MouseButton.MiddleButton: + elif event.button() == QtMouseMiddle: selItem = self.itemAt(event.pos()) if not isinstance(selItem, QTreeWidgetItem): return @@ -697,11 +697,11 @@ class GuiNovelTree(QTreeWidget): iLevel = nwHeaders.H_LEVEL.get(idxItem.level, 0) hDec = SHARED.theme.getHeaderDecoration(iLevel) - trItem.setData(self.C_TITLE, Qt.ItemDataRole.DecorationRole, hDec) + trItem.setData(self.C_TITLE, QtDecoration, hDec) trItem.setText(self.C_TITLE, idxItem.title) trItem.setFont(self.C_TITLE, self._hFonts[iLevel]) trItem.setText(self.C_WORDS, f"{idxItem.wordCount:n}") - trItem.setData(self.C_MORE, Qt.ItemDataRole.DecorationRole, self._pMore) + trItem.setData(self.C_MORE, QtDecoration, self._pMore) # Custom column mW = int(self._lastColSize * self.viewport().width()) diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py index fc5c9ac9..0d07e5ab 100644 --- a/novelwriter/gui/outline.py +++ b/novelwriter/gui/outline.py @@ -48,7 +48,9 @@ from novelwriter.error import logException from novelwriter.common import checkInt, formatFileFilter, makeFileNameSafe from novelwriter.constants import nwHeaders, trConst, nwKeyWords, nwLabels from novelwriter.extensions.novelselector import NovelSelector -from novelwriter.types import QtAlignLeftTop, QtAlignRight, QtAlignRightTop +from novelwriter.types import ( + QtAlignLeftTop, QtAlignRight, QtAlignRightTop, QtDecoration, QtUserRole +) logger = logging.getLogger(__name__) @@ -68,7 +70,7 @@ class GuiOutlineView(QWidget): self.outlineBar = GuiOutlineToolBar(self) self.outlineBar.setEnabled(False) - self.splitOutline = QSplitter(Qt.Vertical) + self.splitOutline = QSplitter(Qt.Orientation.Vertical, self) self.splitOutline.addWidget(self.outlineTree) self.splitOutline.addWidget(self.outlineData) self.splitOutline.setOpaqueResize(False) @@ -218,7 +220,7 @@ class GuiOutlineToolBar(QToolBar): stretch.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) # Novel Selector - self.novelLabel = QLabel(self.tr("Outline of")) + self.novelLabel = QLabel(self.tr("Outline of"), self) self.novelLabel.setContentsMargins(0, 0, mPx, 0) self.novelValue = NovelSelector(self) @@ -354,8 +356,8 @@ class GuiOutlineTree(QTreeWidget): nwOutline.SYNOP: False, } - D_HANDLE = Qt.ItemDataRole.UserRole - D_TITLE = Qt.ItemDataRole.UserRole + 1 + D_HANDLE = QtUserRole + D_TITLE = QtUserRole + 1 hiddenStateChanged = pyqtSignal() activeItemChanged = pyqtSignal(str, str) @@ -692,7 +694,7 @@ class GuiOutlineTree(QTreeWidget): trItem = QTreeWidgetItem() hDec = SHARED.theme.getHeaderDecoration(iLevel) - trItem.setData(self._colIdx[nwOutline.TITLE], Qt.ItemDataRole.DecorationRole, hDec) + trItem.setData(self._colIdx[nwOutline.TITLE], QtDecoration, hDec) trItem.setText(self._colIdx[nwOutline.TITLE], novIdx.title) trItem.setData(self._colIdx[nwOutline.TITLE], self.D_HANDLE, tHandle) trItem.setData(self._colIdx[nwOutline.TITLE], self.D_TITLE, sTitle) @@ -801,12 +803,12 @@ class GuiOutlineDetails(QScrollArea): bFont = SHARED.theme.guiFontB # Details Area - self.titleLabel = QLabel(self.tr("Title")) - self.fileLabel = QLabel(self.tr("Document")) - self.itemLabel = QLabel(self.tr("Status")) - self.titleValue = QLabel("") - self.fileValue = QLabel("") - self.itemValue = QLabel("") + self.titleLabel = QLabel(self.tr("Title"), self) + self.fileLabel = QLabel(self.tr("Document"), self) + self.itemLabel = QLabel(self.tr("Status"), self) + self.titleValue = QLabel("", self) + self.fileValue = QLabel("", self) + self.itemValue = QLabel("", self) self.titleLabel.setFont(bFont) self.fileLabel.setFont(bFont) @@ -820,12 +822,12 @@ class GuiOutlineDetails(QScrollArea): self.itemValue.setMaximumWidth(maxTitle) # Stats Area - self.cCLabel = QLabel(self.tr("Characters")) - self.wCLabel = QLabel(self.tr("Words")) - self.pCLabel = QLabel(self.tr("Paragraphs")) - self.cCValue = QLabel("") - self.wCValue = QLabel("") - self.pCValue = QLabel("") + self.cCLabel = QLabel(self.tr("Characters"), self) + self.wCLabel = QLabel(self.tr("Words"), self) + self.pCLabel = QLabel(self.tr("Paragraphs"), self) + self.cCValue = QLabel("", self) + self.wCValue = QLabel("", self) + self.pCValue = QLabel("", self) self.cCLabel.setFont(bFont) self.wCLabel.setFont(bFont) @@ -839,10 +841,10 @@ class GuiOutlineDetails(QScrollArea): self.pCValue.setAlignment(QtAlignRight) # Synopsis - self.synopLabel = QLabel(self.tr("Synopsis")) + self.synopLabel = QLabel(self.tr("Synopsis"), self) self.synopLabel.setFont(bFont) - self.synopValue = QLabel("") + self.synopValue = QLabel("", self) self.synopValue.setWordWrap(True) self.synopValue.setAlignment(QtAlignLeftTop) @@ -850,15 +852,15 @@ class GuiOutlineDetails(QScrollArea): self.synopLWrap.addWidget(self.synopValue, 1) # Tags - self.povKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY])) - self.focKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY])) - self.chrKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.CHAR_KEY])) - self.pltKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY])) - self.timKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.TIME_KEY])) - self.wldKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.WORLD_KEY])) - self.objKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.OBJECT_KEY])) - self.entKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.ENTITY_KEY])) - self.cstKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.CUSTOM_KEY])) + self.povKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY]), self) + self.focKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY]), self) + self.chrKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.CHAR_KEY]), self) + self.pltKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY]), self) + self.timKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.TIME_KEY]), self) + self.wldKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.WORLD_KEY]), self) + self.objKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.OBJECT_KEY]), self) + self.entKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.ENTITY_KEY]), self) + self.cstKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.CUSTOM_KEY]), self) self.povKeyLabel.setFont(bFont) self.focKeyLabel.setFont(bFont) @@ -880,15 +882,15 @@ class GuiOutlineDetails(QScrollArea): self.entKeyLWrap = QHBoxLayout() self.cstKeyLWrap = QHBoxLayout() - self.povKeyValue = QLabel("") - self.focKeyValue = QLabel("") - self.chrKeyValue = QLabel("") - self.pltKeyValue = QLabel("") - self.timKeyValue = QLabel("") - self.wldKeyValue = QLabel("") - self.objKeyValue = QLabel("") - self.entKeyValue = QLabel("") - self.cstKeyValue = QLabel("") + self.povKeyValue = QLabel("", self) + self.focKeyValue = QLabel("", self) + self.chrKeyValue = QLabel("", self) + self.pltKeyValue = QLabel("", self) + self.timKeyValue = QLabel("", self) + self.wldKeyValue = QLabel("", self) + self.objKeyValue = QLabel("", self) + self.entKeyValue = QLabel("", self) + self.cstKeyValue = QLabel("", self) self.povKeyValue.setWordWrap(True) self.focKeyValue.setWordWrap(True) @@ -975,7 +977,7 @@ class GuiOutlineDetails(QScrollArea): self.tagsForm.setVerticalSpacing(vSpace) # Assemble - self.outerWidget = QWidget() + self.outerWidget = QWidget(self) self.outerBox = QHBoxLayout() self.outerBox.addWidget(self.mainGroup, 0) self.outerBox.addWidget(self.tagsGroup, 1) diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index 8baed4c3..2ade45d8 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -32,10 +32,10 @@ from enum import Enum from time import time from typing import TYPE_CHECKING +from PyQt5.QtCore import QPoint, QTimer, Qt, pyqtSignal, pyqtSlot from PyQt5.QtGui import ( QDragEnterEvent, QDragMoveEvent, QDropEvent, QIcon, QMouseEvent, QPalette ) -from PyQt5.QtCore import QPoint, QTimer, Qt, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import ( QAbstractItemView, QAction, QDialog, QFrame, QHBoxLayout, QHeaderView, QLabel, QMenu, QShortcut, QSizePolicy, QTreeWidget, QTreeWidgetItem, @@ -54,7 +54,7 @@ from novelwriter.dialogs.projectsettings import GuiProjectSettings from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout from novelwriter.extensions.modified import NIconToolButton from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON -from novelwriter.types import QtAlignLeft, QtAlignRight +from novelwriter.types import QtAlignLeft, QtAlignRight, QtMouseLeft, QtMouseMiddle, QtUserRole if TYPE_CHECKING: # pragma: no cover from novelwriter.guimain import GuiMain @@ -271,7 +271,7 @@ class GuiProjectToolBar(QWidget): self.setAutoFillBackground(True) # Widget Label - self.viewLabel = QLabel(self.tr("Project Content")) + self.viewLabel = QLabel(self.tr("Project Content"), self) self.viewLabel.setFont(SHARED.theme.guiFontB) self.viewLabel.setContentsMargins(0, 0, 0, 0) self.viewLabel.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) @@ -487,8 +487,8 @@ class GuiProjectTree(QTreeWidget): C_ACTIVE = 2 C_STATUS = 3 - D_HANDLE = Qt.ItemDataRole.UserRole - D_WORDS = Qt.ItemDataRole.UserRole + 1 + D_HANDLE = QtUserRole + D_WORDS = QtUserRole + 1 itemRefreshed = pyqtSignal(str, NWItem, QIcon) @@ -1230,7 +1230,7 @@ class GuiProjectTree(QTreeWidget): else: ctxMenu.buildSingleSelectMenu(hasChild) - ctxMenu.exec_(self.viewport().mapToGlobal(clickPos)) + ctxMenu.exec(self.viewport().mapToGlobal(clickPos)) ctxMenu.deleteLater() return True @@ -1256,11 +1256,11 @@ class GuiProjectTree(QTreeWidget): for viewing if the user middle-clicked. """ super().mousePressEvent(event) - if event.button() == Qt.MouseButton.LeftButton: + if event.button() == QtMouseLeft: selItem = self.indexAt(event.pos()) if not selItem.isValid(): self.clearSelection() - elif event.button() == Qt.MouseButton.MiddleButton: + elif event.button() == QtMouseMiddle: selItem = self.itemAt(event.pos()) if selItem: tHandle = selItem.data(self.C_DATA, self.D_HANDLE) @@ -1268,7 +1268,7 @@ class GuiProjectTree(QTreeWidget): self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, "", False) return - def startDrag(self, dropAction: Qt.DropActions) -> None: + def startDrag(self, dropAction: Qt.DropAction) -> None: """Capture the drag and drop handling to pop alerts.""" super().startDrag(dropAction) if self._popAlert: @@ -1410,7 +1410,7 @@ class GuiProjectTree(QTreeWidget): itemList.remove(tHandle) dlgMerge = GuiDocMerge(self.mainGui, tHandle, itemList) - dlgMerge.exec_() + dlgMerge.exec() if dlgMerge.result() == QDialog.DialogCode.Accepted: @@ -1480,7 +1480,7 @@ class GuiProjectTree(QTreeWidget): return False dlgSplit = GuiDocSplit(self.mainGui, tHandle) - dlgSplit.exec_() + dlgSplit.exec() if dlgSplit.result() == QDialog.DialogCode.Accepted: diff --git a/novelwriter/gui/search.py b/novelwriter/gui/search.py index 769689ee..6811c026 100644 --- a/novelwriter/gui/search.py +++ b/novelwriter/gui/search.py @@ -30,15 +30,15 @@ from time import time from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot from PyQt5.QtGui import QCursor, QKeyEvent from PyQt5.QtWidgets import ( - QFrame, QHBoxLayout, QHeaderView, QLabel, QLineEdit, QToolBar, QTreeWidget, - QTreeWidgetItem, QVBoxLayout, QWidget, qApp + QApplication, QFrame, QHBoxLayout, QHeaderView, QLabel, QLineEdit, + QToolBar, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED from novelwriter.common import checkInt, cssCol from novelwriter.core.coretools import DocSearch from novelwriter.core.item import NWItem -from novelwriter.types import QtAlignMiddle, QtAlignRight +from novelwriter.types import QtAlignMiddle, QtAlignRight, QtUserRole logger = logging.getLogger(__name__) @@ -49,8 +49,8 @@ class GuiProjectSearch(QWidget): C_RESULT = 0 C_COUNT = 1 - D_HANDLE = Qt.ItemDataRole.UserRole - D_RESULT = Qt.ItemDataRole.UserRole + 1 + D_HANDLE = QtUserRole + D_RESULT = QtUserRole + 1 selectedItemChanged = pyqtSignal(str) openDocumentSelectRequest = pyqtSignal(str, int, int, bool) @@ -71,7 +71,7 @@ class GuiProjectSearch(QWidget): self._map: dict[str, tuple[int, float]] = {} # Header - self.viewLabel = QLabel(self.tr("Project Search")) + self.viewLabel = QLabel(self.tr("Project Search"), self) self.viewLabel.setFont(SHARED.theme.guiFontB) self.viewLabel.setContentsMargins(mPx, tPx, 0, mPx) @@ -257,7 +257,7 @@ class GuiProjectSearch(QWidget): def _processSearch(self) -> None: """Perform a search.""" if not self._blocked: - qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) + QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) start = time() SHARED.mainGui.saveDocument() self._blocked = True @@ -271,7 +271,7 @@ class GuiProjectSearch(QWidget): self._displayResultSet(item, results, capped) logger.debug("Search took %.3f ms", 1000*(time() - start)) self._time = time() - qApp.restoreOverrideCursor() + QApplication.restoreOverrideCursor() self._blocked = False return @@ -355,7 +355,7 @@ class GuiProjectSearch(QWidget): for i in range(tItem.childCount()): self.searchResult.setFirstColumnSpanned(i, parent, True) - qApp.processEvents() + QApplication.processEvents() return diff --git a/novelwriter/gui/sidebar.py b/novelwriter/gui/sidebar.py index 202a2157..d5dce50d 100644 --- a/novelwriter/gui/sidebar.py +++ b/novelwriter/gui/sidebar.py @@ -125,7 +125,7 @@ class GuiSideBar(QWidget): def updateTheme(self) -> None: """Initialise GUI elements that depend on specific settings.""" qPalette = self.palette() - qPalette.setBrush(QPalette.Window, qPalette.base()) + qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base()) self.setPalette(qPalette) buttonStyle = SHARED.theme.getStyleSheet(STYLES_BIG_TOOLBUTTON) @@ -157,7 +157,7 @@ class _PopRightMenu(QMenu): def event(self, event: QEvent) -> bool: """Overload the show event and move the menu popup location.""" - if event.type() == QEvent.Show: + if event.type() == QEvent.Type.Show: if isinstance(parent := self.parent(), QWidget): offset = QPoint(parent.width(), parent.height() - self.height()) self.move(parent.mapToGlobal(offset)) diff --git a/novelwriter/gui/statusbar.py b/novelwriter/gui/statusbar.py index 85befc60..1992d609 100644 --- a/novelwriter/gui/statusbar.py +++ b/novelwriter/gui/statusbar.py @@ -25,12 +25,12 @@ from __future__ import annotations import logging +from datetime import datetime from time import time from typing import TYPE_CHECKING, Literal -from datetime import datetime from PyQt5.QtCore import pyqtSlot, QLocale -from PyQt5.QtWidgets import qApp, QStatusBar, QLabel +from PyQt5.QtWidgets import QApplication, QStatusBar, QLabel from novelwriter import CONFIG, SHARED from novelwriter.common import formatTime @@ -66,8 +66,8 @@ class GuiMainStatus(QStatusBar): xM = CONFIG.pxInt(8) # The Spell Checker Language - self.langIcon = QLabel("") - self.langText = QLabel(self.tr("None")) + self.langIcon = QLabel("", self) + self.langText = QLabel(self.tr("None"), self) self.langIcon.setContentsMargins(0, 0, 0, 0) self.langText.setContentsMargins(0, 0, xM, 0) self.addPermanentWidget(self.langIcon) @@ -75,7 +75,7 @@ class GuiMainStatus(QStatusBar): # The Editor Status self.docIcon = StatusLED(colNone, colSaved, colUnsaved, iPx, iPx, self) - self.docText = QLabel(self.tr("Editor")) + self.docText = QLabel(self.tr("Editor"), self) self.docIcon.setContentsMargins(0, 0, 0, 0) self.docText.setContentsMargins(0, 0, xM, 0) self.addPermanentWidget(self.docIcon) @@ -83,15 +83,15 @@ class GuiMainStatus(QStatusBar): # The Project Status self.projIcon = StatusLED(colNone, colSaved, colUnsaved, iPx, iPx, self) - self.projText = QLabel(self.tr("Project")) + self.projText = QLabel(self.tr("Project"), self) self.projIcon.setContentsMargins(0, 0, 0, 0) self.projText.setContentsMargins(0, 0, xM, 0) self.addPermanentWidget(self.projIcon) self.addPermanentWidget(self.projText) # The Project and Session Stats - self.statsIcon = QLabel() - self.statsText = QLabel("") + self.statsIcon = QLabel(self) + self.statsText = QLabel("", self) self.statsIcon.setContentsMargins(0, 0, 0, 0) self.statsText.setContentsMargins(0, 0, xM, 0) self.addPermanentWidget(self.statsIcon) @@ -99,8 +99,8 @@ class GuiMainStatus(QStatusBar): # The Session Clock # Set the minimum width so the label doesn't rescale every second - self.timeIcon = QLabel() - self.timeText = QLabel("") + self.timeIcon = QLabel(self) + self.timeText = QLabel("", self) self.timeText.setToolTip(self.tr("Session Time")) self.timeText.setMinimumWidth(SHARED.theme.getTextWidth("00:00:00:")) self.timeIcon.setContentsMargins(0, 0, 0, 0) @@ -198,7 +198,7 @@ class GuiMainStatus(QStatusBar): def setStatusMessage(self, message: str) -> None: """Set the status bar message to display.""" self.showMessage(message, nwConst.STATUS_MSG_TIMEOUT) - qApp.processEvents() + QApplication.processEvents() return @pyqtSlot(str, str) @@ -240,7 +240,7 @@ class GuiMainStatus(QStatusBar): import tracemalloc from collections import Counter - widgets = qApp.allWidgets() + widgets = QApplication.allWidgets() if not self._debugInfo: if tracemalloc.is_tracing(): self._traceMallocRef = "Total" diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py index db993cb3..c636f677 100644 --- a/novelwriter/gui/theme.py +++ b/novelwriter/gui/theme.py @@ -30,16 +30,16 @@ from math import ceil from pathlib import Path from PyQt5.QtCore import QSize, Qt -from PyQt5.QtWidgets import qApp from PyQt5.QtGui import ( QPalette, QColor, QIcon, QFont, QFontMetrics, QFontDatabase, QPixmap ) +from PyQt5.QtWidgets import QApplication from novelwriter import CONFIG -from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType -from novelwriter.error import logException from novelwriter.common import NWConfigParser, cssCol, minmax from novelwriter.constants import nwLabels +from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType +from novelwriter.error import logException logger = logging.getLogger(__name__) @@ -144,15 +144,15 @@ class GuiTheme: self.getHeaderDecorationNarrow = self.iconCache.getHeaderDecorationNarrow # Extract Other Info - self.guiDPI = qApp.primaryScreen().logicalDotsPerInchX() - self.guiScale = qApp.primaryScreen().logicalDotsPerInchX()/96.0 + self.guiDPI = QApplication.primaryScreen().logicalDotsPerInchX() + self.guiScale = QApplication.primaryScreen().logicalDotsPerInchX()/96.0 CONFIG.guiScale = self.guiScale logger.debug("GUI DPI: %.1f", self.guiDPI) logger.debug("GUI Scale: %.2f", self.guiScale) # Fonts - self.guiFont = qApp.font() - self.guiFontB = qApp.font() + self.guiFont = QApplication.font() + self.guiFontB = QApplication.font() self.guiFontB.setBold(True) qMetric = QFontMetrics(self.guiFont) @@ -171,7 +171,9 @@ class GuiTheme: # Monospace Font self.guiFontFixed = QFont() self.guiFontFixed.setPointSizeF(0.95*self.fontPointSize) - self.guiFontFixed.setFamily(QFontDatabase.systemFont(QFontDatabase.FixedFont).family()) + self.guiFontFixed.setFamily( + QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont).family() + ) logger.debug("GUI Font Family: %s", self.guiFont.family()) logger.debug("GUI Font Point Size: %.2f", self.fontPointSize) @@ -255,7 +257,7 @@ class GuiTheme: self._setPalette(parser, sec, "link", QPalette.ColorRole.Link) self._setPalette(parser, sec, "linkvisited", QPalette.ColorRole.LinkVisited) else: - self._guiPalette = qApp.style().standardPalette() + self._guiPalette = QApplication.style().standardPalette() # GUI sec = "GUI" @@ -284,7 +286,7 @@ class GuiTheme: self.iconCache.loadTheme(self.themeIcons or defaultIcons) # Apply Styles - qApp.setPalette(self._guiPalette) + QApplication.setPalette(self._guiPalette) # Reset stylesheets so that they are regenerated self._buildStyleSheets(self._guiPalette) @@ -401,14 +403,14 @@ class GuiTheme: font.setFamily("Arial") font.setPointSize(10) else: - font = fontDB.systemFont(QFontDatabase.GeneralFont) + font = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont) CONFIG.guiFont = font.family() CONFIG.guiFontSize = font.pointSize() else: font.setFamily(CONFIG.guiFont) font.setPointSize(CONFIG.guiFontSize) - qApp.setFont(font) + QApplication.setFont(font) return diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index 14f9a494..cadc1d1e 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -30,11 +30,11 @@ from time import time from pathlib import Path from datetime import datetime -from PyQt5.QtGui import QCloseEvent, QCursor, QIcon from PyQt5.QtCore import Qt, QTimer, pyqtSlot +from PyQt5.QtGui import QCloseEvent, QCursor, QIcon from PyQt5.QtWidgets import ( - QFileDialog, QHBoxLayout, QMainWindow, QMessageBox, QShortcut, QSplitter, - QStackedWidget, QVBoxLayout, QWidget, qApp + QApplication, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox, QShortcut, QSplitter, + QStackedWidget, QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED, __hexversion__, __version__ @@ -109,7 +109,7 @@ class GuiMain(QMainWindow): nwIcon = CONFIG.assetPath("icons") / "novelwriter.svg" self.nwIcon = QIcon(str(nwIcon)) if nwIcon.is_file() else QIcon() self.setWindowIcon(self.nwIcon) - qApp.setWindowIcon(self.nwIcon) + QApplication.setWindowIcon(self.nwIcon) # Build the GUI # ============= @@ -148,7 +148,7 @@ class GuiMain(QMainWindow): self.treePane.setLayout(self.treeBox) # Splitter : Document Viewer / Document Meta - self.splitView = QSplitter(Qt.Vertical, self) + self.splitView = QSplitter(Qt.Orientation.Vertical, self) self.splitView.addWidget(self.docViewer) self.splitView.addWidget(self.docViewerPanel) self.splitView.setHandleWidth(hWd) @@ -158,7 +158,7 @@ class GuiMain(QMainWindow): self.splitView.setCollapsible(1, False) # Splitter : Document Editor / Document Viewer - self.splitDocs = QSplitter(Qt.Horizontal, self) + self.splitDocs = QSplitter(Qt.Orientation.Horizontal, self) self.splitDocs.addWidget(self.docEditor) self.splitDocs.addWidget(self.splitView) self.splitDocs.setOpaqueResize(False) @@ -167,7 +167,7 @@ class GuiMain(QMainWindow): self.splitDocs.setCollapsible(1, False) # Splitter : Project Tree / Document Area - self.splitMain = QSplitter(Qt.Horizontal) + self.splitMain = QSplitter(Qt.Orientation.Horizontal) self.splitMain.setContentsMargins(0, 0, 0, 0) self.splitMain.addWidget(self.treePane) self.splitMain.addWidget(self.splitDocs) @@ -205,7 +205,7 @@ class GuiMain(QMainWindow): self.setMenuBar(self.mainMenu) self.setCentralWidget(self.mainWidget) self.setStatusBar(self.mainStatus) - self.setContextMenuPolicy(Qt.NoContextMenu) # Issue #1147 + self.setContextMenuPolicy(Qt.ContextMenuPolicy.NoContextMenu) # Issue #1147 # Connect Signals # =============== @@ -328,7 +328,7 @@ class GuiMain(QMainWindow): def postLaunchTasks(self, cmdOpen: str | None) -> None: """Process tasks after the main window has been created.""" if cmdOpen: - qApp.processEvents() + QApplication.processEvents() logger.info("Command line path: %s", cmdOpen) self.openProject(cmdOpen) @@ -474,12 +474,12 @@ class GuiMain(QMainWindow): break if lastEdited is not None: - qApp.processEvents() + QApplication.processEvents() self.openDocument(lastEdited, doScroll=True) lastViewed = SHARED.project.data.getLastHandle("viewer") if lastViewed is not None: - qApp.processEvents() + QApplication.processEvents() self.viewDocument(lastViewed) # Check if we need to rebuild the index @@ -488,7 +488,7 @@ class GuiMain(QMainWindow): self.rebuildIndex() # Make sure the changed status is set to false on things opened - qApp.processEvents() + QApplication.processEvents() self.docEditor.setDocumentChanged(False) SHARED.project.setProjectChanged(False) @@ -738,7 +738,7 @@ class GuiMain(QMainWindow): """Rebuild the entire index.""" if SHARED.hasProject: logger.info("Rebuilding index ...") - qApp.setOverrideCursor(QCursor(Qt.WaitCursor)) + QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) tStart = time() self.projView.saveProjectTasks() @@ -752,7 +752,7 @@ class GuiMain(QMainWindow): ) self.docEditor.updateTagHighLighting() self._updateStatusWordCount() - qApp.restoreOverrideCursor() + QApplication.restoreOverrideCursor() if not beQuiet: SHARED.info(self.tr("The project index has been successfully rebuilt.")) @@ -768,7 +768,7 @@ class GuiMain(QMainWindow): """Open the welcome dialog.""" dialog = GuiWelcome(self) dialog.openProjectRequest.connect(self._openProjectFromWelcome) - dialog.exec_() + dialog.exec() return @pyqtSlot() @@ -776,7 +776,7 @@ class GuiMain(QMainWindow): """Open the preferences dialog.""" dialog = GuiPreferences(self) dialog.newPreferencesReady.connect(self._processConfigChanges) - dialog.exec_() + dialog.exec() return @pyqtSlot() @@ -786,7 +786,7 @@ class GuiMain(QMainWindow): if SHARED.hasProject: dialog = GuiProjectSettings(self, gotoPage=focusTab) dialog.newProjectSettingsReady.connect(self._processProjectSettingsChanges) - dialog.exec_() + dialog.exec() return @pyqtSlot() @@ -797,7 +797,7 @@ class GuiMain(QMainWindow): dialog.setModal(True) dialog.show() dialog.raise_() - qApp.processEvents() + QApplication.processEvents() dialog.updateValues() return @@ -810,7 +810,7 @@ class GuiMain(QMainWindow): dialog.setModal(False) dialog.show() dialog.raise_() - qApp.processEvents() + QApplication.processEvents() dialog.loadContent() return @@ -820,7 +820,7 @@ class GuiMain(QMainWindow): if SHARED.hasProject: dialog = GuiWordList(self) dialog.newWordListReady.connect(self._processWordListChanges) - dialog.exec_() + dialog.exec() return @pyqtSlot() @@ -832,7 +832,7 @@ class GuiMain(QMainWindow): dialog.setModal(False) dialog.show() dialog.raise_() - qApp.processEvents() + QApplication.processEvents() dialog.populateGUI() return @@ -843,7 +843,7 @@ class GuiMain(QMainWindow): dialog.setModal(True) dialog.show() dialog.raise_() - qApp.processEvents() + QApplication.processEvents() dialog.populateGUI() return @@ -861,7 +861,7 @@ class GuiMain(QMainWindow): dialog.setModal(True) dialog.show() dialog.raise_() - qApp.processEvents() + QApplication.processEvents() if not dialog.initDialog(): dialog.close() SHARED.error(self.tr("Could not initialise the dialog.")) @@ -899,7 +899,8 @@ class GuiMain(QMainWindow): CONFIG.setViewPanePos(self.splitView.sizes()) CONFIG.showViewerPanel = self.docViewerPanel.isVisible() - if self.windowState() & Qt.WindowFullScreen != Qt.WindowFullScreen: + wFull = Qt.WindowState.WindowFullScreen + if self.windowState() & wFull != wFull: # Ignore window size if in full screen mode CONFIG.setMainWinSize(self.width(), self.height()) @@ -909,7 +910,7 @@ class GuiMain(QMainWindow): CONFIG.saveConfig() self.reportConfErr() - qApp.quit() + QApplication.quit() return True @@ -936,7 +937,7 @@ class GuiMain(QMainWindow): def toggleFullScreenMode(self) -> None: """Toggle full screen mode""" - self.setWindowState(self.windowState() ^ Qt.WindowFullScreen) + self.setWindowState(self.windowState() ^ Qt.WindowState.WindowFullScreen) return ## @@ -1056,7 +1057,7 @@ class GuiMain(QMainWindow): if theme: # We are doing this manually instead of connecting to - # qApp.paletteChanged since the processing order matters + # paletteChanged since the processing order matters SHARED.theme.loadTheme() self.docEditor.updateTheme() self.docViewer.updateTheme() @@ -1115,7 +1116,7 @@ class GuiMain(QMainWindow): @pyqtSlot(Path) def _openProjectFromWelcome(self, path: Path) -> None: """Handle an open project request from the welcome dialog.""" - qApp.processEvents() + QApplication.processEvents() self.openProject(path) if not SHARED.hasProject: self.showWelcomeDialog() @@ -1212,7 +1213,7 @@ class GuiMain(QMainWindow): if SHARED.hasProject: currTime = time() editIdle = currTime - self.docEditor.lastActive > CONFIG.userIdleTime - userIdle = qApp.applicationState() != Qt.ApplicationActive + userIdle = QApplication.applicationState() != Qt.ApplicationState.ApplicationActive self.mainStatus.setUserIdle(editIdle or userIdle) SHARED.updateIdleTime(currTime, editIdle or userIdle) self.mainStatus.updateTime(idleTime=SHARED.projectIdleTime) diff --git a/novelwriter/shared.py b/novelwriter/shared.py index af6767a6..25410871 100644 --- a/novelwriter/shared.py +++ b/novelwriter/shared.py @@ -292,7 +292,7 @@ class SharedData(QObject): self._lastAlert = alert.logMessage if log: logger.info(self._lastAlert, stacklevel=2) - alert.exec_() + alert.exec() alert.deleteLater() return @@ -304,7 +304,7 @@ class SharedData(QObject): self._lastAlert = alert.logMessage if log: logger.warning(self._lastAlert, stacklevel=2) - alert.exec_() + alert.exec() alert.deleteLater() return @@ -319,7 +319,7 @@ class SharedData(QObject): self._lastAlert = alert.logMessage if log: logger.error(self._lastAlert, stacklevel=2) - alert.exec_() + alert.exec() alert.deleteLater() return @@ -329,7 +329,7 @@ class SharedData(QObject): alert.setMessage(text, info, details) alert.setAlertType(_GuiAlert.WARN if warn else _GuiAlert.ASK, True) self._lastAlert = alert.logMessage - alert.exec_() + alert.exec() isYes = alert.result() == QMessageBox.StandardButton.Yes alert.deleteLater() return isYes diff --git a/novelwriter/tools/dictionaries.py b/novelwriter/tools/dictionaries.py index 33d0d7af..a944c745 100644 --- a/novelwriter/tools/dictionaries.py +++ b/novelwriter/tools/dictionaries.py @@ -28,17 +28,18 @@ import logging from pathlib import Path from zipfile import ZipFile -from PyQt5.QtGui import QCloseEvent, QTextCursor from PyQt5.QtCore import pyqtSlot +from PyQt5.QtGui import QCloseEvent, QTextCursor from PyQt5.QtWidgets import ( - QDialog, QDialogButtonBox, QFileDialog, QFrame, QHBoxLayout, QLabel, - QLineEdit, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget, qApp + QApplication, QDialog, QDialogButtonBox, QFileDialog, QFrame, QHBoxLayout, + QLabel, QLineEdit, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED from novelwriter.common import formatFileFilter, openExternalPath, formatInt, getFileSize from novelwriter.error import formatException from novelwriter.extensions.modified import NIconToolButton +from novelwriter.types import QtDialogClose logger = logging.getLogger(__name__) @@ -70,7 +71,7 @@ class GuiDictionaries(QDialog): self.tr("Download a dictionary from one of the links, and add it below."), f" \u203a {foUrl}", f" \u203a {loUrl}", - ])) + ]), self) self.huInfo.setOpenExternalLinks(True) self.huInfo.setWordWrap(True) self.huInput = QLineEdit(self) @@ -89,7 +90,7 @@ class GuiDictionaries(QDialog): self.huAddBox.addWidget(self.huImport) # Install Path - self.inInfo = QLabel(self.tr("Dictionary install location")) + self.inInfo = QLabel(self.tr("Dictionary install location"), self) self.inPath = QLineEdit(self) self.inPath.setReadOnly(True) self.inBrowse = NIconToolButton(self, iSz, "browse") @@ -107,7 +108,7 @@ class GuiDictionaries(QDialog): self.infoBox.setFrameStyle(QFrame.Shape.NoFrame) # Buttons - self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close) + self.buttonBox = QDialogButtonBox(QtDialogClose, self) self.buttonBox.rejected.connect(self._doClose) # Assemble @@ -158,7 +159,7 @@ class GuiDictionaries(QDialog): "Additional dictionaries found: {0}" ).format(len(self._currDicts))) - qApp.processEvents() + QApplication.processEvents() self.adjustSize() return True diff --git a/novelwriter/tools/lipsum.py b/novelwriter/tools/lipsum.py index 3c05d99c..bce851f5 100644 --- a/novelwriter/tools/lipsum.py +++ b/novelwriter/tools/lipsum.py @@ -35,7 +35,7 @@ from PyQt5.QtWidgets import ( from novelwriter import CONFIG, SHARED from novelwriter.common import readTextFile from novelwriter.extensions.switch import NSwitch -from novelwriter.types import QtAlignLeft, QtAlignRight +from novelwriter.types import QtAlignLeft, QtAlignRight, QtRoleAction, QtDialogClose logger = logging.getLogger(__name__) @@ -61,7 +61,7 @@ class GuiLipsum(QDialog): self.innerBox.setSpacing(CONFIG.pxInt(16)) # Icon - self.docIcon = QLabel() + self.docIcon = QLabel(self) self.docIcon.setPixmap(SHARED.theme.getPixmap("proj_document", (nPx, nPx))) self.leftBox = QVBoxLayout() @@ -71,15 +71,16 @@ class GuiLipsum(QDialog): self.innerBox.addLayout(self.leftBox) # Form - self.headLabel = QLabel("{0}".format(self.tr("Insert Lorem Ipsum Text"))) + self.headLabel = QLabel(self.tr("Insert Lorem Ipsum Text")) + self.headLabel.setFont(SHARED.theme.guiFontB) - self.paraLabel = QLabel(self.tr("Number of paragraphs")) - self.paraCount = QSpinBox() + self.paraLabel = QLabel(self.tr("Number of paragraphs"), self) + self.paraCount = QSpinBox(self) self.paraCount.setMinimum(1) self.paraCount.setMaximum(100) self.paraCount.setValue(5) - self.randLabel = QLabel(self.tr("Randomise order")) + self.randLabel = QLabel(self.tr("Randomise order"), self) self.randSwitch = NSwitch(self) self.formBox = QGridLayout() @@ -93,13 +94,13 @@ class GuiLipsum(QDialog): self.innerBox.addLayout(self.formBox) # Buttons - self.buttonBox = QDialogButtonBox() + self.buttonBox = QDialogButtonBox(self) self.buttonBox.rejected.connect(self.close) - self.btnClose = self.buttonBox.addButton(QDialogButtonBox.Close) + self.btnClose = self.buttonBox.addButton(QtDialogClose) self.btnClose.setAutoDefault(False) - self.btnInsert = self.buttonBox.addButton(self.tr("Insert"), QDialogButtonBox.ActionRole) + self.btnInsert = self.buttonBox.addButton(self.tr("Insert"), QtRoleAction) self.btnInsert.clicked.connect(self._doInsert) self.btnInsert.setAutoDefault(False) @@ -129,7 +130,7 @@ class GuiLipsum(QDialog): def getLipsum(cls, parent: QWidget) -> str: """Pop the dialog and return the lipsum text.""" cls = GuiLipsum(parent) - cls.exec_() + cls.exec() text = cls.lipsumText cls.deleteLater() return text diff --git a/novelwriter/tools/manusbuild.py b/novelwriter/tools/manusbuild.py index 5eef8aef..301e4432 100644 --- a/novelwriter/tools/manusbuild.py +++ b/novelwriter/tools/manusbuild.py @@ -27,8 +27,8 @@ import logging from pathlib import Path +from PyQt5.QtCore import QTimer, pyqtSlot from PyQt5.QtGui import QCloseEvent -from PyQt5.QtCore import QTimer, Qt, pyqtSlot from PyQt5.QtWidgets import ( QAbstractButton, QAbstractItemView, QDialog, QDialogButtonBox, QFileDialog, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem, @@ -44,7 +44,9 @@ from novelwriter.core.item import NWItem from novelwriter.enum import nwBuildFmt from novelwriter.extensions.modified import NIconToolButton from novelwriter.extensions.simpleprogress import NProgressSimple -from novelwriter.types import QtAlignCenter +from novelwriter.types import ( + QtAlignCenter, QtDialogClose, QtRoleAction, QtRoleReject, QtUserRole +) logger = logging.getLogger(__name__) @@ -56,7 +58,7 @@ class GuiManuscriptBuild(QDialog): independently of the Manuscript Build Tool. """ - D_KEY = Qt.ItemDataRole.UserRole + D_KEY = QtUserRole def __init__(self, parent: QWidget, build: BuildSettings): super().__init__(parent=parent) @@ -88,8 +90,8 @@ class GuiManuscriptBuild(QDialog): # Output Format # ============= - self.lblFormat = QLabel(self.tr("Output Format")) - self.listFormats = QListWidget() + self.lblFormat = QLabel(self.tr("Output Format"), self) + self.listFormats = QListWidget(self) self.listFormats.setIconSize(iSz) current = None for key in nwBuildFmt: @@ -107,14 +109,14 @@ class GuiManuscriptBuild(QDialog): self.formatBox.addWidget(self.listFormats, 1) self.formatBox.setContentsMargins(0, 0, 0, 0) - self.formatWidget = QWidget() + self.formatWidget = QWidget(self) self.formatWidget.setLayout(self.formatBox) self.formatWidget.setContentsMargins(0, 0, 0, 0) # Table of Contents # ================= - self.lblContent = QLabel(self.tr("Table of Contents")) + self.lblContent = QLabel(self.tr("Table of Contents"), self) self.listContent = QListWidget(self) self.listContent.setIconSize(iSz) @@ -125,7 +127,7 @@ class GuiManuscriptBuild(QDialog): self.contentBox.addWidget(self.listContent, 0) self.contentBox.setContentsMargins(0, 0, 0, 0) - self.contentWidget = QWidget() + self.contentWidget = QWidget(self) self.contentWidget.setLayout(self.contentBox) self.contentWidget.setContentsMargins(0, 0, 0, 0) @@ -137,12 +139,12 @@ class GuiManuscriptBuild(QDialog): font.setUnderline(True) font.setPointSizeF(1.5*font.pointSizeF()) - self.lblMain = QLabel(self._build.name) + self.lblMain = QLabel(self._build.name, self) self.lblMain.setWordWrap(True) self.lblMain.setFont(font) # Build Path - self.lblPath = QLabel(self.tr("Path")) + self.lblPath = QLabel(self.tr("Path"), self) self.buildPath = QLineEdit(self) self.btnBrowse = NIconToolButton(self, iSz, "browse") @@ -152,7 +154,7 @@ class GuiManuscriptBuild(QDialog): self.pathBox.setSpacing(sp8) # Build Name - self.lblName = QLabel(self.tr("File Name")) + self.lblName = QLabel(self.tr("File Name"), self) self.buildName = QLineEdit(self) self.btnReset = NIconToolButton(self, iSz, "revert") self.btnReset.setToolTip(self.tr("Reset file name to default")) @@ -179,19 +181,19 @@ class GuiManuscriptBuild(QDialog): self.buildBox.setVerticalSpacing(sp4) # Dialog Buttons - self.btnOpen = QPushButton(SHARED.theme.getIcon("browse"), self.tr("Open Folder")) + self.btnOpen = QPushButton(SHARED.theme.getIcon("browse"), self.tr("Open Folder"), self) self.btnOpen.setIconSize(bSz) - self.btnBuild = QPushButton(SHARED.theme.getIcon("export"), self.tr("&Build")) + self.btnBuild = QPushButton(SHARED.theme.getIcon("export"), self.tr("&Build"), self) self.btnBuild.setIconSize(bSz) - self.dlgButtons = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) - self.dlgButtons.addButton(self.btnOpen, QDialogButtonBox.ButtonRole.ActionRole) - self.dlgButtons.addButton(self.btnBuild, QDialogButtonBox.ButtonRole.ActionRole) + self.dlgButtons = QDialogButtonBox(QtDialogClose, self) + self.dlgButtons.addButton(self.btnOpen, QtRoleAction) + self.dlgButtons.addButton(self.btnBuild, QtRoleAction) # Assemble GUI # ============ - self.mainSplit = QSplitter() + self.mainSplit = QSplitter(self) self.mainSplit.addWidget(self.formatWidget) self.mainSplit.addWidget(self.contentWidget) self.mainSplit.setHandleWidth(sp16) @@ -261,12 +263,12 @@ class GuiManuscriptBuild(QDialog): def _dialogButtonClicked(self, button: QAbstractButton): """Handle button clicks from the dialog button box.""" role = self.dlgButtons.buttonRole(button) - if role == QDialogButtonBox.ActionRole: + if role == QtRoleAction: if button == self.btnBuild: self._runBuild() elif button == self.btnOpen: self._openOutputFolder() - elif role == QDialogButtonBox.RejectRole: + elif role == QtRoleReject: self.close() return diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py index 7528477a..0fac65fa 100644 --- a/novelwriter/tools/manuscript.py +++ b/novelwriter/tools/manuscript.py @@ -26,19 +26,19 @@ from __future__ import annotations import json import logging +from datetime import datetime from time import time from typing import TYPE_CHECKING -from datetime import datetime -from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent from PyQt5.QtCore import QTimer, QUrl, Qt, pyqtSignal, pyqtSlot -from PyQt5.QtWidgets import ( - QAbstractItemView, QDialog, QFormLayout, QGridLayout, QHBoxLayout, QLabel, - QListWidget, QListWidgetItem, QPushButton, QSizePolicy, QSplitter, - QStackedWidget, QTabWidget, QTextBrowser, QTreeWidget, QTreeWidgetItem, - QVBoxLayout, QWidget, qApp -) +from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent from PyQt5.QtPrintSupport import QPrintPreviewDialog, QPrinter +from PyQt5.QtWidgets import ( + QAbstractItemView, QApplication, QDialog, QFormLayout, QGridLayout, + QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPushButton, + QSizePolicy, QSplitter, QStackedWidget, QTabWidget, QTextBrowser, + QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget +) from novelwriter import CONFIG, SHARED from novelwriter.common import checkInt, fuzzyTime @@ -53,7 +53,8 @@ from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON from novelwriter.tools.manusbuild import GuiManuscriptBuild from novelwriter.tools.manussettings import GuiBuildSettings from novelwriter.types import ( - QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignRight, QtAlignTop + QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignRight, QtAlignTop, + QtUserRole ) if TYPE_CHECKING: # pragma: no cover @@ -70,7 +71,7 @@ class GuiManuscript(QDialog): a document directly to disk. """ - D_KEY = Qt.ItemDataRole.UserRole + D_KEY = QtUserRole def __init__(self, mainGui: GuiMain) -> None: super().__init__(parent=mainGui) @@ -103,7 +104,7 @@ class GuiManuscript(QDialog): # ============== qPalette = self.palette() - qPalette.setBrush(QPalette.Window, qPalette.base()) + qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base()) self.setPalette(qPalette) buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON) @@ -123,7 +124,7 @@ class GuiManuscript(QDialog): self.tbEdit.setStyleSheet(buttonStyle) self.tbEdit.clicked.connect(self._editSelectedBuild) - self.lblBuilds = QLabel("{0}".format(self.tr("Builds"))) + self.lblBuilds = QLabel("{0}".format(self.tr("Builds")), self) self.listToolBox = QHBoxLayout() self.listToolBox.addWidget(self.lblBuilds) @@ -140,8 +141,8 @@ class GuiManuscript(QDialog): self.buildList.setIconSize(iSz) self.buildList.doubleClicked.connect(self._editSelectedBuild) self.buildList.currentItemChanged.connect(self._updateBuildDetails) - self.buildList.setSelectionMode(QAbstractItemView.SingleSelection) - self.buildList.setDragDropMode(QAbstractItemView.InternalMove) + self.buildList.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) + self.buildList.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove) # Details Tabs # ============ @@ -169,16 +170,16 @@ class GuiManuscript(QDialog): # Process Controls # ================ - self.btnPreview = QPushButton(self.tr("Preview")) + self.btnPreview = QPushButton(self.tr("Preview"), self) self.btnPreview.clicked.connect(self._generatePreview) - self.btnPrint = QPushButton(self.tr("Print")) + self.btnPrint = QPushButton(self.tr("Print"), self) self.btnPrint.clicked.connect(self._printDocument) - self.btnBuild = QPushButton(self.tr("Build")) + self.btnBuild = QPushButton(self.tr("Build"), self) self.btnBuild.clicked.connect(self._buildManuscript) - self.btnClose = QPushButton(self.tr("Close")) + self.btnClose = QPushButton(self.tr("Close"), self) self.btnClose.clicked.connect(self.close) self.processBox = QGridLayout() @@ -210,7 +211,7 @@ class GuiManuscript(QDialog): self.optsWidget = QWidget(self) self.optsWidget.setLayout(self.controlBox) - self.mainSplit = QSplitter() + self.mainSplit = QSplitter(self) self.mainSplit.addWidget(self.optsWidget) self.mainSplit.addWidget(self.docWdiget) self.mainSplit.setCollapsible(0, False) @@ -352,7 +353,7 @@ class GuiManuscript(QDialog): self.docPreview.beginNewBuild(len(docBuild)) for step, _ in docBuild.iterBuildHTML(None): self.docPreview.buildStep(step + 1) - qApp.processEvents() + QApplication.processEvents() buildObj = docBuild.lastBuild assert isinstance(buildObj, ToHtml) @@ -385,7 +386,7 @@ class GuiManuscript(QDialog): build = self._getSelectedBuild() if isinstance(build, BuildSettings): dlgBuild = GuiManuscriptBuild(self, build) - dlgBuild.exec_() + dlgBuild.exec() # After the build is done, save build settings changes if build.changed: @@ -398,7 +399,7 @@ class GuiManuscript(QDialog): """Open the print preview dialog.""" preview = QPrintPreviewDialog(self) preview.paintRequested.connect(self.docPreview.printPreview) - preview.exec_() + preview.exec() return ## @@ -486,7 +487,7 @@ class GuiManuscript(QDialog): dlgSettings.setModal(False) dlgSettings.show() dlgSettings.raise_() - qApp.processEvents() + QApplication.processEvents() dlgSettings.loadContent() dlgSettings.newSettingsReady.connect(self._processNewSettings) @@ -661,7 +662,7 @@ class _DetailsWidget(QWidget): class _OutlineWidget(QWidget): - D_LINE = Qt.ItemDataRole.UserRole + D_LINE = QtUserRole outlineEntryClicked = pyqtSignal(str) @@ -750,8 +751,8 @@ class _PreviewWidget(QTextBrowser): # Document Setup dPalette = self.palette() - dPalette.setColor(QPalette.Base, QColor(255, 255, 255)) - dPalette.setColor(QPalette.Text, QColor(0, 0, 0)) + dPalette.setColor(QPalette.ColorRole.Base, QColor(255, 255, 255)) + dPalette.setColor(QPalette.ColorRole.Text, QColor(0, 0, 0)) self.setPalette(dPalette) self.setMinimumWidth(40*SHARED.theme.textNWidth) @@ -768,8 +769,8 @@ class _PreviewWidget(QTextBrowser): # Document Age aPalette = self.palette() - aPalette.setColor(QPalette.Background, aPalette.toolTipBase().color()) - aPalette.setColor(QPalette.Foreground, aPalette.toolTipText().color()) + aPalette.setColor(QPalette.ColorRole.Window, aPalette.toolTipBase().color()) + aPalette.setColor(QPalette.ColorRole.WindowText, aPalette.toolTipText().color()) aFont = self.font() aFont.setPointSizeF(0.9*SHARED.theme.fontPointSize) @@ -850,16 +851,16 @@ class _PreviewWidget(QTextBrowser): def buildStep(self, value: int) -> None: """Update the progress bar value.""" self.buildProgress.setValue(value) - qApp.processEvents() + QApplication.processEvents() return def setContent(self, data: dict) -> None: """Set the content of the preview widget.""" sPos = self.verticalScrollBar().value() - qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) + QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) self.buildProgress.setCentreText(self.tr("Processing ...")) - qApp.processEvents() + QApplication.processEvents() styles = "\n".join(data.get("styles", [])) self.document().setDefaultStyleSheet(styles) @@ -867,7 +868,7 @@ class _PreviewWidget(QTextBrowser): html = "".join(data.get("html", [])) html = html.replace("\t", "!!tab!!") self.setHtml(html) - qApp.processEvents() + QApplication.processEvents() while self.find("!!tab!!"): cursor = self.textCursor() cursor.insertText("\t") @@ -881,8 +882,8 @@ class _PreviewWidget(QTextBrowser): self.document().markContentsDirty(0, self.document().characterCount()) self.buildProgress.setCentreText(self.tr("Done")) - qApp.restoreOverrideCursor() - qApp.processEvents() + QApplication.restoreOverrideCursor() + QApplication.processEvents() QTimer.singleShot(300, self._hideProgress) return @@ -904,10 +905,10 @@ class _PreviewWidget(QTextBrowser): @pyqtSlot("QPrinter*") def printPreview(self, printer: QPrinter) -> None: """Connect the print preview painter to the document viewer.""" - qApp.setOverrideCursor(QCursor(Qt.WaitCursor)) - printer.setOrientation(QPrinter.Portrait) + QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) + printer.setOrientation(QPrinter.Orientation.Portrait) self.document().print(printer) - qApp.restoreOverrideCursor() + QApplication.restoreOverrideCursor() return @pyqtSlot(str) @@ -1053,10 +1054,10 @@ class _StatsWidget(QWidget): """Build the minimal stats page.""" mPx = CONFIG.pxInt(8) - self.lblWordCount = QLabel(self.tr("Words")) + self.lblWordCount = QLabel(self.tr("Words"), self) self.minWordCount = QLabel(self) - self.lblCharCount = QLabel(self.tr("Characters")) + self.lblCharCount = QLabel(self.tr("Characters"), self) self.minCharCount = QLabel(self) # Assemble diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index a575fead..ebbcbb17 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -46,7 +46,10 @@ from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NIconTool from novelwriter.extensions.pagedsidebar import NPagedSideBar from novelwriter.extensions.switch import NSwitch from novelwriter.extensions.switchbox import NSwitchBox -from novelwriter.types import QtAlignLeft +from novelwriter.types import ( + QtAlignLeft, QtDialogApply, QtDialogClose, QtDialogSave, QtRoleAccept, + QtRoleApply, QtRoleReject, QtUserRole +) if TYPE_CHECKING: # pragma: no cover from novelwriter.guimain import GuiMain @@ -99,7 +102,7 @@ class GuiBuildSettings(QDialog): ) # Settings Name - self.lblBuildName = QLabel(self.tr("Name")) + self.lblBuildName = QLabel(self.tr("Name"), self) self.editBuildName = QLineEdit(self) # SideBar @@ -131,11 +134,7 @@ class GuiBuildSettings(QDialog): self.toolStack.addWidget(self.optTabOutput) # Buttons - self.buttonBox = QDialogButtonBox( - QDialogButtonBox.StandardButton.Apply - | QDialogButtonBox.StandardButton.Save - | QDialogButtonBox.StandardButton.Close - ) + self.buttonBox = QDialogButtonBox(QtDialogApply | QtDialogSave | QtDialogClose, self) self.buttonBox.clicked.connect(self._dialogButtonClicked) # Assemble @@ -226,12 +225,12 @@ class GuiBuildSettings(QDialog): def _dialogButtonClicked(self, button: QAbstractButton) -> None: """Handle button clicks from the dialog button box.""" role = self.buttonBox.buttonRole(button) - if role == QDialogButtonBox.ApplyRole: + if role == QtRoleApply: self._emitBuildData() - elif role == QDialogButtonBox.AcceptRole: + elif role == QtRoleAccept: self._emitBuildData() self.close() - elif role == QDialogButtonBox.RejectRole: + elif role == QtRoleReject: self.close() return @@ -289,8 +288,8 @@ class _FilterTab(NFixedPage): C_ACTIVE = 1 C_STATUS = 2 - D_HANDLE = Qt.ItemDataRole.UserRole - D_FILE = Qt.ItemDataRole.UserRole + 1 + D_HANDLE = QtUserRole + D_FILE = QtUserRole + 1 F_NONE = 0 F_FILTERED = 1 @@ -332,15 +331,15 @@ class _FilterTab(NFixedPage): treeHeader = self.optTree.header() treeHeader.setStretchLastSection(False) treeHeader.setMinimumSectionSize(iPx + cMg) # See Issue #1551 - treeHeader.setSectionResizeMode(self.C_NAME, QHeaderView.Stretch) - treeHeader.setSectionResizeMode(self.C_ACTIVE, QHeaderView.Fixed) - treeHeader.setSectionResizeMode(self.C_STATUS, QHeaderView.Fixed) + treeHeader.setSectionResizeMode(self.C_NAME, QHeaderView.ResizeMode.Stretch) + treeHeader.setSectionResizeMode(self.C_ACTIVE, QHeaderView.ResizeMode.Fixed) + treeHeader.setSectionResizeMode(self.C_STATUS, QHeaderView.ResizeMode.Fixed) treeHeader.resizeSection(self.C_ACTIVE, iPx + cMg) treeHeader.resizeSection(self.C_STATUS, iPx + cMg) - self.optTree.setDragDropMode(QAbstractItemView.NoDragDrop) - self.optTree.setSelectionMode(QAbstractItemView.ExtendedSelection) - self.optTree.setSelectionBehavior(QAbstractItemView.SelectRows) + self.optTree.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop) + self.optTree.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) + self.optTree.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) # Filters # ======= @@ -360,7 +359,7 @@ class _FilterTab(NFixedPage): self.resetButton.clicked.connect(lambda: self._setSelectedMode(self.F_FILTERED)) self.modeBox = QHBoxLayout() - self.modeBox.addWidget(QLabel(self.tr("Mark selection as"))) + self.modeBox.addWidget(QLabel(self.tr("Mark selection as"), self)) self.modeBox.addStretch(1) self.modeBox.addWidget(self.includedButton) self.modeBox.addWidget(self.excludedButton) @@ -370,7 +369,7 @@ class _FilterTab(NFixedPage): # Filer Options self.filterOpt = NSwitchBox(self, iPx) self.filterOpt.switchToggled.connect(self._applyFilterSwitch) - self.filterOpt.setFrameStyle(QFrame.NoFrame) + self.filterOpt.setFrameStyle(QFrame.Shape.NoFrame) # Assemble GUI # ============ @@ -382,10 +381,10 @@ class _FilterTab(NFixedPage): self.selectionBox.addLayout(self.modeBox) self.selectionBox.setContentsMargins(0, 0, 0, 0) - self.selectionWidget = QWidget() + self.selectionWidget = QWidget(self) self.selectionWidget.setLayout(self.selectionBox) - self.mainSplit = QSplitter() + self.mainSplit = QSplitter(self) self.mainSplit.addWidget(self.selectionWidget) self.mainSplit.addWidget(self.filterOpt) self.mainSplit.setCollapsible(0, False) @@ -704,7 +703,7 @@ class _HeadingsTab(NScrollablePage): # Edit Form # ========= - self.lblEditForm = QLabel(self.tr("Editing: {0}").format(self.tr("None"))) + self.lblEditForm = QLabel(self.tr("Editing: {0}").format(self.tr("None")), self) self.editTextBox = QPlainTextEdit(self) self.editTextBox.setFixedHeight(5*iPx) @@ -760,12 +759,12 @@ class _HeadingsTab(NScrollablePage): self.layoutMatrix.addWidget(self.layoutHeading, 0, 0, 1, 5) # Title Layout - self.mtxTitle = QLabel(self._build.getLabel("headings.fmtTitle")) + self.mtxTitle = QLabel(self._build.getLabel("headings.fmtTitle"), self) self.centerTitle = NSwitch(self, height=iPx) self.breakTitle = NSwitch(self, height=iPx) - lblCenterT = QLabel(self.tr("Centre")) + lblCenterT = QLabel(self.tr("Centre"), self) lblCenterT.setIndent(sSp) - lblBreakT = QLabel(self.tr("Page Break")) + lblBreakT = QLabel(self.tr("Page Break"), self) lblBreakT.setIndent(sSp) self.layoutMatrix.addWidget(self.mtxTitle, 1, 0) @@ -775,12 +774,12 @@ class _HeadingsTab(NScrollablePage): self.layoutMatrix.addWidget(self.breakTitle, 1, 4) # Chapter Layout - self.mtxChapter = QLabel(self._build.getLabel("headings.fmtChapter")) + self.mtxChapter = QLabel(self._build.getLabel("headings.fmtChapter"), self) self.centerChapter = NSwitch(self, height=iPx) self.breakChapter = NSwitch(self, height=iPx) - lblCenterC = QLabel(self.tr("Centre")) + lblCenterC = QLabel(self.tr("Centre"), self) lblCenterC.setIndent(sSp) - lblBreakC = QLabel(self.tr("Page Break")) + lblBreakC = QLabel(self.tr("Page Break"), self) lblBreakC.setIndent(sSp) self.layoutMatrix.addWidget(self.mtxChapter, 2, 0) @@ -790,12 +789,12 @@ class _HeadingsTab(NScrollablePage): self.layoutMatrix.addWidget(self.breakChapter, 2, 4) # Scene Layout - self.mtxScene = QLabel(self._build.getLabel("headings.fmtScene")) + self.mtxScene = QLabel(self._build.getLabel("headings.fmtScene"), self) self.centerScene = NSwitch(self, height=iPx) self.breakScene = NSwitch(self, height=iPx) - lblCenterS = QLabel(self.tr("Centre")) + lblCenterS = QLabel(self.tr("Centre"), self) lblCenterS.setIndent(sSp) - lblBreakS = QLabel(self.tr("Page Break")) + lblBreakS = QLabel(self.tr("Page Break"), self) lblBreakS.setIndent(sSp) self.layoutMatrix.addWidget(self.mtxScene, 3, 0) diff --git a/novelwriter/tools/noveldetails.py b/novelwriter/tools/noveldetails.py index 17780c0c..08755425 100644 --- a/novelwriter/tools/noveldetails.py +++ b/novelwriter/tools/noveldetails.py @@ -26,8 +26,8 @@ from __future__ import annotations import math import logging +from PyQt5.QtCore import pyqtSlot from PyQt5.QtGui import QCloseEvent -from PyQt5.QtCore import Qt, pyqtSlot from PyQt5.QtWidgets import ( QAbstractItemView, QDialog, QDialogButtonBox, QFormLayout, QGridLayout, QHBoxLayout, QLabel, QSpinBox, QStackedWidget, QTreeWidget, @@ -41,7 +41,7 @@ from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrol from novelwriter.extensions.novelselector import NovelSelector from novelwriter.extensions.pagedsidebar import NPagedSideBar from novelwriter.extensions.switch import NSwitch -from novelwriter.types import QtAlignRight +from novelwriter.types import QtAlignRight, QtDecoration, QtDialogClose logger = logging.getLogger(__name__) @@ -95,7 +95,7 @@ class GuiNovelDetails(QDialog): self.mainStack.addWidget(self.contentsPage) # Buttons - self.buttonBox = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) + self.buttonBox = QDialogButtonBox(QtDialogClose, self) self.buttonBox.rejected.connect(self.close) # Assemble @@ -366,7 +366,7 @@ class _ContentsPage(NFixedPage): countFrom = options.getInt("GuiNovelDetails", "countFrom", 1) clearDouble = options.getBool("GuiNovelDetails", "clearDouble", True) - self.wpLabel = QLabel(self.tr("Words per page")) + self.wpLabel = QLabel(self.tr("Words per page"), self) self.wpValue = QSpinBox(self) self.wpValue.setMinimum(10) @@ -375,7 +375,7 @@ class _ContentsPage(NFixedPage): self.wpValue.setValue(wordsPerPage) self.wpValue.valueChanged.connect(self._populateTree) - self.poLabel = QLabel(self.tr("First page offset")) + self.poLabel = QLabel(self.tr("First page offset"), self) self.poValue = QSpinBox(self) self.poValue.setMinimum(1) @@ -384,7 +384,7 @@ class _ContentsPage(NFixedPage): self.poValue.setValue(countFrom) self.poValue.valueChanged.connect(self._populateTree) - self.dblLabel = QLabel(self.tr("Chapters on odd pages")) + self.dblLabel = QLabel(self.tr("Chapters on odd pages"), self) self.dblValue = NSwitch(self, height=iPx) self.dblValue.setChecked(clearDouble) @@ -485,7 +485,7 @@ class _ContentsPage(NFixedPage): if tTitle.strip() == "": tTitle = self.tr("Untitled") - newItem.setData(self.C_TITLE, Qt.DecorationRole, hDec) + newItem.setData(self.C_TITLE, QtDecoration, hDec) newItem.setText(self.C_TITLE, tTitle) newItem.setText(self.C_WORDS, f"{wCount:n}") newItem.setText(self.C_PAGES, f"{pCount:n}") diff --git a/novelwriter/tools/welcome.py b/novelwriter/tools/welcome.py index 4a680e69..c8f26727 100644 --- a/novelwriter/tools/welcome.py +++ b/novelwriter/tools/welcome.py @@ -25,19 +25,19 @@ from __future__ import annotations import logging -from pathlib import Path from datetime import datetime +from pathlib import Path -from PyQt5.QtGui import QCloseEvent, QColor, QFont, QPaintEvent, QPainter, QPen from PyQt5.QtCore import ( QAbstractListModel, QEvent, QModelIndex, QObject, QPoint, QSize, Qt, pyqtSignal, pyqtSlot ) +from PyQt5.QtGui import QCloseEvent, QColor, QFont, QPaintEvent, QPainter, QPen from PyQt5.QtWidgets import ( - QAction, QDialog, QFileDialog, QFormLayout, QHBoxLayout, QLabel, QLineEdit, - QListView, QMenu, QPushButton, QScrollArea, QShortcut, QStackedWidget, - QStyle, QStyleOptionViewItem, QStyledItemDelegate, QVBoxLayout, QWidget, - qApp + QAction, QApplication, QDialog, QFileDialog, QFormLayout, QHBoxLayout, + QLabel, QLineEdit, QListView, QMenu, QPushButton, QScrollArea, QShortcut, + QStackedWidget, QStyleOptionViewItem, QStyledItemDelegate, QVBoxLayout, + QWidget ) from novelwriter import CONFIG, SHARED @@ -49,7 +49,7 @@ from novelwriter.extensions.configlayout import NWrappedWidgetBox from novelwriter.extensions.modified import NIconToolButton, NSpinBox from novelwriter.extensions.switch import NSwitch from novelwriter.extensions.versioninfo import VersionInfoWidget -from novelwriter.types import QtAlignLeft, QtAlignRightTop +from novelwriter.types import QtAlignLeft, QtAlignRightTop, QtSelected logger = logging.getLogger(__name__) @@ -377,7 +377,7 @@ class _OpenProjectPage(QWidget): action.triggered.connect(self.openSelectedItem) action = ctxMenu.addAction(self.tr("Remove Project")) action.triggered.connect(self._deleteSelectedItem) - ctxMenu.exec_(self.mapToGlobal(pos)) + ctxMenu.exec(self.mapToGlobal(pos)) ctxMenu.deleteLater() return @@ -411,11 +411,11 @@ class _ProjectListItem(QStyledItemDelegate): self._pPx = (mPx//2, 3*mPx//2, iPx + mPx, mPx, mPx + tPx) # Painter coordinates self._hPx = 2*mPx + tPx + fPx # Fixed height - self._tFont = qApp.font() + self._tFont = QApplication.font() self._tFont.setPointSizeF(1.2*fPt) self._tFont.setWeight(QFont.Weight.Bold) - self._dFont = qApp.font() + self._dFont = QApplication.font() self._dFont.setPointSizeF(fPt) self._dPen = QPen(SHARED.theme.helpText) @@ -431,9 +431,9 @@ class _ProjectListItem(QStyledItemDelegate): ix, iy, x, y1, y2 = self._pPx painter.save() - if opt.state & QStyle.StateFlag.State_Selected == QStyle.StateFlag.State_Selected: + if opt.state & QtSelected == QtSelected: painter.setOpacity(0.25) - painter.fillRect(rect, qApp.palette().highlight()) + painter.fillRect(rect, QApplication.palette().highlight()) painter.setOpacity(1.0) painter.drawPixmap(ix, rect.top() + iy, self._icon) @@ -682,10 +682,10 @@ class _NewProjectForm(QWidget): # ======== self.extraBox = QVBoxLayout() - self.extraBox.addWidget(QLabel("{0}".format(self.tr("Chapters and Scenes")))) + self.extraBox.addWidget(QLabel("{0}".format(self.tr("Chapters and Scenes")), self)) self.extraBox.addLayout(self.novelForm) self.extraBox.addSpacing(sPx) - self.extraBox.addWidget(QLabel("{0}".format(self.tr("Project Notes")))) + self.extraBox.addWidget(QLabel("{0}".format(self.tr("Project Notes")), self)) self.extraBox.addLayout(self.notesForm) self.extraBox.setContentsMargins(0, 0, 0, 0) @@ -694,7 +694,7 @@ class _NewProjectForm(QWidget): self.extraWidget.setContentsMargins(0, 0, 0, 0) self.formBox = QVBoxLayout() - self.formBox.addWidget(QLabel("{0}".format(self.tr("Create New Project")))) + self.formBox.addWidget(QLabel("{0}".format(self.tr("Create New Project")), self)) self.formBox.addLayout(self.projectForm) self.formBox.addSpacing(sPx) self.formBox.addWidget(self.extraWidget) @@ -738,7 +738,7 @@ class _NewProjectForm(QWidget): """Select a project folder.""" if projDir := QFileDialog.getExistingDirectory( self, self.tr("Select Project Folder"), - str(self._basePath), options=QFileDialog.ShowDirsOnly + str(self._basePath), options=QFileDialog.Option.ShowDirsOnly ): self._basePath = Path(projDir) self._updateProjPath() @@ -813,7 +813,7 @@ class _PopLeftDirectionMenu(QMenu): def event(self, event: QEvent) -> bool: """Overload the show event and move the menu popup location.""" - if event.type() == QEvent.Show: + if event.type() == QEvent.Type.Show: if isinstance(parent := self.parent(), QWidget): offset = QPoint(parent.width() - self.width(), parent.height()) self.move(parent.mapToGlobal(offset)) diff --git a/novelwriter/tools/writingstats.py b/novelwriter/tools/writingstats.py index 4a8e09a9..1a12e40f 100644 --- a/novelwriter/tools/writingstats.py +++ b/novelwriter/tools/writingstats.py @@ -29,11 +29,12 @@ import logging from datetime import datetime from typing import TYPE_CHECKING -from PyQt5.QtGui import QCloseEvent, QPixmap, QCursor from PyQt5.QtCore import Qt, pyqtSlot +from PyQt5.QtGui import QCloseEvent, QCursor, QPixmap from PyQt5.QtWidgets import ( - qApp, QDialog, QTreeWidget, QTreeWidgetItem, QDialogButtonBox, QGridLayout, - QLabel, QGroupBox, QMenu, QAction, QFileDialog, QSpinBox, QHBoxLayout + QAction, QApplication, QDialog, QDialogButtonBox, QFileDialog, QGridLayout, + QGroupBox, QHBoxLayout, QLabel, QMenu, QSpinBox, QTreeWidget, + QTreeWidgetItem ) from novelwriter import CONFIG, SHARED @@ -41,7 +42,10 @@ from novelwriter.common import formatTime, checkInt, checkIntTuple, minmax from novelwriter.constants import nwConst from novelwriter.error import formatException from novelwriter.extensions.switch import NSwitch -from novelwriter.types import QtAlignLeftMiddle, QtAlignRight, QtAlignRightMiddle +from novelwriter.types import ( + QtAlignLeftMiddle, QtAlignRight, QtAlignRightMiddle, QtDecoration, + QtDialogClose, QtRoleAction +) if TYPE_CHECKING: # pragma: no cover from novelwriter.guimain import GuiMain @@ -101,7 +105,7 @@ class GuiWritingStats(QDialog): pOptions.getInt("GuiWritingStats", "widthCol3", 80) ) - self.listBox = QTreeWidget() + self.listBox = QTreeWidget(self) self.listBox.setHeaderLabels([ self.tr("Session Start"), self.tr("Length"), @@ -121,10 +125,11 @@ class GuiWritingStats(QDialog): hHeader.setTextAlignment(self.C_IDLE, QtAlignRight) hHeader.setTextAlignment(self.C_COUNT, QtAlignRight) + sDec = Qt.SortOrder.DescendingOrder + sAsc = Qt.SortOrder.AscendingOrder sortCol = minmax(pOptions.getInt("GuiWritingStats", "sortCol", 0), 0, 2) sortOrder = checkIntTuple( - pOptions.getInt("GuiWritingStats", "sortOrder", Qt.DescendingOrder), - (Qt.AscendingOrder, Qt.DescendingOrder), Qt.DescendingOrder + pOptions.getInt("GuiWritingStats", "sortOrder", sDec), (sAsc, sDec), sDec ) self.listBox.sortByColumn(sortCol, sortOrder) # type: ignore self.listBox.setSortingEnabled(True) @@ -140,36 +145,36 @@ class GuiWritingStats(QDialog): self.infoForm = QGridLayout(self) self.infoBox.setLayout(self.infoForm) - self.labelTotal = QLabel(formatTime(0)) + self.labelTotal = QLabel(formatTime(0), self) self.labelTotal.setFont(SHARED.theme.guiFontFixed) self.labelTotal.setAlignment(QtAlignRightMiddle) - self.labelIdleT = QLabel(formatTime(0)) + self.labelIdleT = QLabel(formatTime(0), self) self.labelIdleT.setFont(SHARED.theme.guiFontFixed) self.labelIdleT.setAlignment(QtAlignRightMiddle) - self.labelFilter = QLabel(formatTime(0)) + self.labelFilter = QLabel(formatTime(0), self) self.labelFilter.setFont(SHARED.theme.guiFontFixed) self.labelFilter.setAlignment(QtAlignRightMiddle) - self.novelWords = QLabel("0") + self.novelWords = QLabel("0", self) self.novelWords.setFont(SHARED.theme.guiFontFixed) self.novelWords.setAlignment(QtAlignRightMiddle) - self.notesWords = QLabel("0") + self.notesWords = QLabel("0", self) self.notesWords.setFont(SHARED.theme.guiFontFixed) self.notesWords.setAlignment(QtAlignRightMiddle) - self.totalWords = QLabel("0") + self.totalWords = QLabel("0", self) self.totalWords.setFont(SHARED.theme.guiFontFixed) self.totalWords.setAlignment(QtAlignRightMiddle) - lblTTime = QLabel(self.tr("Total Time:")) - lblITime = QLabel(self.tr("Idle Time:")) - lblFTime = QLabel(self.tr("Filtered Time:")) - lblNvCount = QLabel(self.tr("Novel Word Count:")) - lblNtCount = QLabel(self.tr("Notes Word Count:")) - lblTtCount = QLabel(self.tr("Total Word Count:")) + lblTTime = QLabel(self.tr("Total Time:"), self) + lblITime = QLabel(self.tr("Idle Time:"), self) + lblFTime = QLabel(self.tr("Filtered Time:"), self) + lblNvCount = QLabel(self.tr("Novel Word Count:"), self) + lblNtCount = QLabel(self.tr("Notes Word Count:"), self) + lblTtCount = QLabel(self.tr("Total Word Count:"), self) self.infoForm.addWidget(lblTTime, 0, 0) self.infoForm.addWidget(lblITime, 1, 0) @@ -230,12 +235,12 @@ class GuiWritingStats(QDialog): ) self.showIdleTime.clicked.connect(self._updateListBox) - self.filterForm.addWidget(QLabel(self.tr("Count novel files")), 0, 0) - self.filterForm.addWidget(QLabel(self.tr("Count note files")), 1, 0) - self.filterForm.addWidget(QLabel(self.tr("Hide zero word count")), 2, 0) - self.filterForm.addWidget(QLabel(self.tr("Hide negative word count")), 3, 0) - self.filterForm.addWidget(QLabel(self.tr("Group entries by day")), 4, 0) - self.filterForm.addWidget(QLabel(self.tr("Show idle time")), 5, 0) + self.filterForm.addWidget(QLabel(self.tr("Count novel files"), self), 0, 0) + self.filterForm.addWidget(QLabel(self.tr("Count note files"), self), 1, 0) + self.filterForm.addWidget(QLabel(self.tr("Hide zero word count"), self), 2, 0) + self.filterForm.addWidget(QLabel(self.tr("Hide negative word count"), self), 3, 0) + self.filterForm.addWidget(QLabel(self.tr("Group entries by day"), self), 4, 0) + self.filterForm.addWidget(QLabel(self.tr("Show idle time"), self), 5, 0) self.filterForm.addWidget(self.incNovel, 0, 1) self.filterForm.addWidget(self.incNotes, 1, 1) self.filterForm.addWidget(self.hideZeros, 2, 1) @@ -256,17 +261,17 @@ class GuiWritingStats(QDialog): self.optsBox = QHBoxLayout() self.optsBox.addStretch(1) - self.optsBox.addWidget(QLabel(self.tr("Word count cap for the histogram")), 0) + self.optsBox.addWidget(QLabel(self.tr("Word count cap for the histogram"), self), 0) self.optsBox.addWidget(self.histMax, 0) # Buttons - self.buttonBox = QDialogButtonBox() + self.buttonBox = QDialogButtonBox(self) self.buttonBox.rejected.connect(self._doClose) - self.btnClose = self.buttonBox.addButton(QDialogButtonBox.Close) + self.btnClose = self.buttonBox.addButton(QtDialogClose) self.btnClose.setAutoDefault(False) - self.btnSave = self.buttonBox.addButton(self.tr("Save As"), QDialogButtonBox.ActionRole) + self.btnSave = self.buttonBox.addButton(self.tr("Save As"), QtRoleAction) self.btnSave.setAutoDefault(False) self.saveMenu = QMenu(self) @@ -301,10 +306,10 @@ class GuiWritingStats(QDialog): def populateGUI(self) -> None: """Populate list box with data from the log file.""" - qApp.setOverrideCursor(QCursor(Qt.WaitCursor)) + QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) self._loadLogFile() self._updateListBox() - qApp.restoreOverrideCursor() + QApplication.restoreOverrideCursor() return ## @@ -570,6 +575,8 @@ class GuiWritingStats(QDialog): pcTotal = wcTotal # Populate the list + mTrans = Qt.TransformationMode.FastTransformation + mAspect = Qt.AspectRatioMode.IgnoreAspectRatio showIdleTime = self.showIdleTime.isChecked() for _, sStart, sDiff, nWords, _, _, sIdle in self.filterData: @@ -588,11 +595,9 @@ class GuiWritingStats(QDialog): if nWords > 0 and listMax > 0: wBar = self.barImage.scaled( int(200*min(nWords, histMax)/listMax), - self.barHeight, - Qt.IgnoreAspectRatio, - Qt.FastTransformation + self.barHeight, mAspect, mTrans ) - newItem.setData(self.C_BAR, Qt.DecorationRole, wBar) + newItem.setData(self.C_BAR, QtDecoration, wBar) newItem.setTextAlignment(self.C_LENGTH, QtAlignRight) newItem.setTextAlignment(self.C_IDLE, QtAlignRight) diff --git a/novelwriter/types.py b/novelwriter/types.py index eb20dce3..56e59604 100644 --- a/novelwriter/types.py +++ b/novelwriter/types.py @@ -24,6 +24,8 @@ along with this program. If not, see . from __future__ import annotations from PyQt5.QtCore import Qt +from PyQt5.QtGui import QColor, QPainter, QTextCursor +from PyQt5.QtWidgets import QDialogButtonBox, QStyle # Qt Alignment Flags @@ -41,3 +43,48 @@ QtAlignRightBase = Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignBaseline QtAlignRightMiddle = Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter QtAlignRightTop = Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTop QtAlignTop = Qt.AlignmentFlag.AlignTop + +# Qt Painter Types + +QtTransparent = QColor(0, 0, 0, 0) +QtNoBrush = Qt.BrushStyle.NoBrush +QtNoPen = Qt.PenStyle.NoPen +QtRoundCap = Qt.PenCapStyle.RoundCap +QtSolidLine = Qt.PenStyle.SolidLine +QtPaintAnitAlias = QPainter.RenderHint.Antialiasing +QtMouseOver = QStyle.StateFlag.State_MouseOver +QtSelected = QStyle.StateFlag.State_Selected + +# Qt Tree and Table Types + +QtDecoration = Qt.ItemDataRole.DecorationRole +QtUserRole = Qt.ItemDataRole.UserRole + +# Keyboard and Mouse Buttons + +QtModCtrl = Qt.KeyboardModifier.ControlModifier +QtModeNone = Qt.KeyboardModifier.NoModifier +QtModShift = Qt.KeyboardModifier.ShiftModifier +QtMouseLeft = Qt.MouseButton.LeftButton +QtMouseMiddle = Qt.MouseButton.MiddleButton + +# Dialog Button Box Types + +QtDialogApply = QDialogButtonBox.StandardButton.Apply +QtDialogCancel = QDialogButtonBox.StandardButton.Cancel +QtDialogClose = QDialogButtonBox.StandardButton.Close +QtDialogOk = QDialogButtonBox.StandardButton.Ok +QtDialogReset = QDialogButtonBox.StandardButton.Reset +QtDialogSave = QDialogButtonBox.StandardButton.Save + +QtRoleAccept = QDialogButtonBox.ButtonRole.AcceptRole +QtRoleAction = QDialogButtonBox.ButtonRole.ActionRole +QtRoleApply = QDialogButtonBox.ButtonRole.ApplyRole +QtRoleReject = QDialogButtonBox.ButtonRole.RejectRole + +# Cursor Types + +QtKeepAnchor = QTextCursor.MoveMode.KeepAnchor +QtMoveAnchor = QTextCursor.MoveMode.MoveAnchor +QtMoveLeft = QTextCursor.MoveOperation.Left +QtMoveRight = QTextCursor.MoveOperation.Right diff --git a/tests/conftest.py b/tests/conftest.py index 0a24ab11..9ca87f06 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -142,7 +142,7 @@ def projPath(fncPath): @pytest.fixture(scope="function") def mockGUI(qtbot, monkeypatch): """Create a mock instance of novelWriter's main GUI class.""" - monkeypatch.setattr(QMessageBox, "exec_", lambda *a: None) + monkeypatch.setattr(QMessageBox, "exec", lambda *a: None) monkeypatch.setattr(QMessageBox, "result", lambda *a: QMessageBox.Yes) gui = MockGuiMain() theme = MockTheme() @@ -154,7 +154,7 @@ def mockGUI(qtbot, monkeypatch): @pytest.fixture(scope="function") def nwGUI(qtbot, monkeypatch, functionFixture): """Create an instance of the novelWriter GUI.""" - monkeypatch.setattr(QMessageBox, "exec_", lambda *a: None) + monkeypatch.setattr(QMessageBox, "exec", lambda *a: None) monkeypatch.setattr(QMessageBox, "result", lambda *a: QMessageBox.Yes) nwGUI = main(["--testmode", f"--config={_TMP_CONF}", f"--data={_TMP_CONF}"]) diff --git a/tests/test_base/test_base_error.py b/tests/test_base/test_base_error.py index b4db2d5f..1f8c2205 100644 --- a/tests/test_base/test_base_error.py +++ b/tests/test_base/test_base_error.py @@ -36,13 +36,13 @@ def testBaseError_Dialog(qtbot, monkeypatch, nwGUI): nwErr.show() # Invalid Error Message - nwErr.setMessage(Exception, "Faulty Error", 123) + nwErr.setMessage(Exception, "Faulty Error", 123) # type: ignore assert nwErr.msgBody.toPlainText() == "Failed to generate error report ..." # Valid Error Message with monkeypatch.context() as mp: mp.setattr("PyQt5.QtCore.QSysInfo.kernelVersion", lambda: "1.2.3") - nwErr.setMessage(Exception, "Fine Error", None) + nwErr.setMessage(Exception, "Fine Error", None) # type: ignore message = nwErr.msgBody.toPlainText() assert message != "" assert "Fine Error" in message @@ -52,7 +52,7 @@ def testBaseError_Dialog(qtbot, monkeypatch, nwGUI): # No kernel version retrieved with monkeypatch.context() as mp: mp.setattr("PyQt5.QtCore.QSysInfo.kernelVersion", causeException) - nwErr.setMessage(Exception, "Almost Fine Error", None) + nwErr.setMessage(Exception, "Almost Fine Error", None) # type: ignore message = nwErr.msgBody.toPlainText() assert message != "" assert "(Unknown)" in message @@ -66,36 +66,36 @@ def testBaseError_Dialog(qtbot, monkeypatch, nwGUI): @pytest.mark.base def testBaseError_Handler(qtbot, monkeypatch, nwGUI): - """Test the error handler. This test doesn'thave any asserts, but it - checks that the error handler handles potential exceptions. The test - will fail if exceptions are not handled. + """Test the error handler. This test doesn't have any asserts, but + it checks that the error handler handles potential exceptions. The + test will fail if exceptions are not handled. """ # Normal shutdown with monkeypatch.context() as mp: - mp.setattr(NWErrorMessage, "exec_", lambda *a: None) - mp.setattr("PyQt5.QtWidgets.qApp.exit", lambda *a: None) - exceptionHandler(Exception, "Error Message", None) + mp.setattr(NWErrorMessage, "exec", lambda *a: None) + mp.setattr("PyQt5.QtWidgets.QApplication.exit", lambda *a: None) + exceptionHandler(Exception, "Error Message", None) # type: ignore # Should not crash when no GUI is found with monkeypatch.context() as mp: - mp.setattr(NWErrorMessage, "exec_", lambda *a: None) - mp.setattr("PyQt5.QtWidgets.qApp.exit", lambda *a: None) - mp.setattr("PyQt5.QtWidgets.qApp.topLevelWidgets", lambda: []) - exceptionHandler(Exception, "Error Message", None) + mp.setattr(NWErrorMessage, "exec", lambda *a: None) + mp.setattr("PyQt5.QtWidgets.QApplication.exit", lambda *a: None) + mp.setattr("PyQt5.QtWidgets.QApplication.topLevelWidgets", lambda: []) + exceptionHandler(Exception, "Error Message", None) # type: ignore - # Should handle qApp failing + # Should handle QApplication failing with monkeypatch.context() as mp: - mp.setattr(NWErrorMessage, "exec_", lambda *a: None) - mp.setattr("PyQt5.QtWidgets.qApp.exit", lambda *a: None) - mp.setattr("PyQt5.QtWidgets.qApp.topLevelWidgets", causeException) - exceptionHandler(Exception, "Error Message", None) + mp.setattr(NWErrorMessage, "exec", lambda *a: None) + mp.setattr("PyQt5.QtWidgets.QApplication.exit", lambda *a: None) + mp.setattr("PyQt5.QtWidgets.QApplication.topLevelWidgets", causeException) + exceptionHandler(Exception, "Error Message", None) # type: ignore # Should handle failing to close main GUI with monkeypatch.context() as mp: - mp.setattr(NWErrorMessage, "exec_", lambda *a: None) - mp.setattr("PyQt5.QtWidgets.qApp.exit", lambda *a: None) + mp.setattr(NWErrorMessage, "exec", lambda *a: None) + mp.setattr("PyQt5.QtWidgets.QApplication.exit", lambda *a: None) mp.setattr(nwGUI, "closeMain", causeException) - exceptionHandler(Exception, "Error Message", None) + exceptionHandler(Exception, "Error Message", None) # type: ignore nwGUI.closeMain() diff --git a/tests/test_base/test_base_init.py b/tests/test_base/test_base_init.py index 113286a8..5326df7c 100644 --- a/tests/test_base/test_base_init.py +++ b/tests/test_base/test_base_init.py @@ -70,7 +70,7 @@ def testBaseInit_Launch(caplog, monkeypatch, fncPath): monkeypatch.setattr("PyQt5.QtWidgets.QApplication.setApplicationVersion", lambda *a: None) monkeypatch.setattr("PyQt5.QtWidgets.QApplication.setWindowIcon", lambda *a: None) monkeypatch.setattr("PyQt5.QtWidgets.QApplication.setOrganizationDomain", lambda *a: None) - monkeypatch.setattr("PyQt5.QtWidgets.QApplication.exec_", lambda *a: 0) + monkeypatch.setattr("PyQt5.QtWidgets.QApplication.exec", lambda *a: 0) with pytest.raises(SystemExit) as ex: main([f"--config={fncPath}", f"--data={fncPath}"]) assert ex.value.code == 0 @@ -148,7 +148,7 @@ def testBaseInit_Imports(caplog, monkeypatch, fncPath): """Check import error handling.""" monkeypatch.setattr("novelwriter.guimain.GuiMain", MockGuiMain) monkeypatch.setattr("PyQt5.QtWidgets.QApplication.__init__", lambda *a: None) - monkeypatch.setattr("PyQt5.QtWidgets.QApplication.exec_", lambda *a: 0) + monkeypatch.setattr("PyQt5.QtWidgets.QApplication.exec", lambda *a: 0) monkeypatch.setattr("PyQt5.QtWidgets.QErrorMessage.__init__", lambda *a: None) monkeypatch.setattr("PyQt5.QtWidgets.QErrorMessage.resize", lambda *a: None) monkeypatch.setattr("PyQt5.QtWidgets.QErrorMessage.showMessage", lambda *a: None) diff --git a/tests/test_base/test_base_shared.py b/tests/test_base/test_base_shared.py index 2aed97c0..6cdb8dfe 100644 --- a/tests/test_base/test_base_shared.py +++ b/tests/test_base/test_base_shared.py @@ -129,7 +129,7 @@ def testBaseSharedData_Projects(monkeypatch, caplog, fncPath): @pytest.mark.base def testBaseSharedData_Alerts(qtbot, monkeypatch, caplog): """Test SharedData class alert helper functions.""" - monkeypatch.setattr(QMessageBox, "exec_", lambda *a: None) + monkeypatch.setattr(QMessageBox, "exec", lambda *a: None) monkeypatch.setattr(QMessageBox, "result", lambda *a: QMessageBox.Yes) shared = SharedData() diff --git a/tests/test_dialogs/test_dlg_dialogs.py b/tests/test_dialogs/test_dlg_dialogs.py index 7cf9d9f6..2a25f65e 100644 --- a/tests/test_dialogs/test_dlg_dialogs.py +++ b/tests/test_dialogs/test_dlg_dialogs.py @@ -32,7 +32,7 @@ from novelwriter.dialogs.editlabel import GuiEditLabel @pytest.mark.gui def testDlgOther_QuoteSelect(qtbot, monkeypatch, nwGUI): """Test the quote symbols dialog.""" - monkeypatch.setattr(GuiQuoteSelect, "exec_", lambda *a: None) + monkeypatch.setattr(GuiQuoteSelect, "exec", lambda *a: None) nwQuot = GuiQuoteSelect(nwGUI) nwQuot.show() @@ -47,7 +47,7 @@ def testDlgOther_QuoteSelect(qtbot, monkeypatch, nwGUI): assert nwQuot.previewLabel.text() == lastItem nwQuot.accept() - assert nwQuot.result() == QDialog.Accepted + assert nwQuot.result() == QDialog.DialogCode.Accepted assert nwQuot.selectedQuote == lastItem nwQuot.close() @@ -68,16 +68,16 @@ def testDlgOther_QuoteSelect(qtbot, monkeypatch, nwGUI): @pytest.mark.gui def testDlgOther_EditLabel(qtbot, monkeypatch): """Test the label editor dialog.""" - monkeypatch.setattr(GuiEditLabel, "exec_", lambda *a: None) + monkeypatch.setattr(GuiEditLabel, "exec", lambda *a: None) with monkeypatch.context() as mp: - mp.setattr(GuiEditLabel, "result", lambda *a: QDialog.Accepted) + mp.setattr(GuiEditLabel, "result", lambda *a: QDialog.DialogCode.Accepted) newLabel, dlgOk = GuiEditLabel.getLabel(None, text="Hello World") # type: ignore assert dlgOk is True assert newLabel == "Hello World" with monkeypatch.context() as mp: - mp.setattr(GuiEditLabel, "result", lambda *a: QDialog.Rejected) + mp.setattr(GuiEditLabel, "result", lambda *a: QDialog.DialogCode.Rejected) newLabel, dlgOk = GuiEditLabel.getLabel(None, text="Hello World") # type: ignore assert dlgOk is False assert newLabel == "Hello World" diff --git a/tests/test_dialogs/test_dlg_docmerge.py b/tests/test_dialogs/test_dlg_docmerge.py index 090c2319..2653f256 100644 --- a/tests/test_dialogs/test_dlg_docmerge.py +++ b/tests/test_dialogs/test_dlg_docmerge.py @@ -27,6 +27,7 @@ from tools import buildTestProject, C from PyQt5.QtCore import Qt from novelwriter.dialogs.docmerge import GuiDocMerge +from novelwriter.types import QtUserRole @pytest.mark.gui @@ -53,11 +54,11 @@ def testDlgMerge_Main(qtbot, nwGUI, projPath, mockRnd): itemOne = nwMerge.listBox.item(0) itemTwo = nwMerge.listBox.item(1) - assert itemOne.data(Qt.ItemDataRole.UserRole) == C.hChapterDoc - assert itemTwo.data(Qt.ItemDataRole.UserRole) == C.hSceneDoc + assert itemOne.data(QtUserRole) == C.hChapterDoc + assert itemTwo.data(QtUserRole) == C.hSceneDoc - assert itemOne.checkState() == Qt.Checked - assert itemTwo.checkState() == Qt.Checked + assert itemOne.checkState() == Qt.CheckState.Checked + assert itemTwo.checkState() == Qt.CheckState.Checked data = nwMerge.getData() assert data["sHandle"] == C.hChapterDir @@ -66,7 +67,7 @@ def testDlgMerge_Main(qtbot, nwGUI, projPath, mockRnd): assert data["finalItems"] == [C.hChapterDoc, C.hSceneDoc] # Uncheck second item and toggle trash switch - itemTwo.setCheckState(Qt.Unchecked) + itemTwo.setCheckState(Qt.CheckState.Unchecked) nwMerge.trashSwitch.setChecked(True) data = nwMerge.getData() diff --git a/tests/test_dialogs/test_dlg_preferences.py b/tests/test_dialogs/test_dlg_preferences.py index 95d2eb59..d193240f 100644 --- a/tests/test_dialogs/test_dlg_preferences.py +++ b/tests/test_dialogs/test_dlg_preferences.py @@ -24,12 +24,13 @@ import pytest from PyQt5.QtGui import QFontDatabase, QKeyEvent from PyQt5.QtCore import QEvent, Qt -from PyQt5.QtWidgets import QAction, QDialogButtonBox, QFileDialog, QFontDialog +from PyQt5.QtWidgets import QAction, QFileDialog, QFontDialog from novelwriter import CONFIG, SHARED from novelwriter.constants import nwConst, nwUnicode from novelwriter.dialogs.preferences import GuiPreferences from novelwriter.dialogs.quotes import GuiQuoteSelect +from novelwriter.types import QtDialogApply, QtDialogClose, QtDialogSave, QtModeNone KEY_DELAY = 1 @@ -38,7 +39,7 @@ KEY_DELAY = 1 def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, tstPaths): """Test the preferences dialog loading.""" monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda: [("en", "English [en]")]) - monkeypatch.setattr(GuiPreferences, "exec_", lambda *a: None) + monkeypatch.setattr(GuiPreferences, "exec", lambda *a: None) # Load GUI with standard values nwGUI.mainMenu.aPreferences.activate(QAction.ActionEvent.Trigger) @@ -121,27 +122,27 @@ def testDlgPreferences_Actions(qtbot, monkeypatch, nwGUI): # Check Apply Button prefs.show() with qtbot.waitSignal(prefs.newPreferencesReady) as signal: - prefs.buttonBox.button(QDialogButtonBox.StandardButton.Apply).click() + prefs.buttonBox.button(QtDialogApply).click() assert signal.args == [False, False, False, False] # Check Save Button prefs.show() with qtbot.waitSignal(prefs.newPreferencesReady) as signal: with qtbot.waitSignal(prefs.finished) as status: - prefs.buttonBox.button(QDialogButtonBox.StandardButton.Save).click() + prefs.buttonBox.button(QtDialogSave).click() assert signal.args == [False, False, False, False] assert status.args == [nwConst.DLG_FINISHED] # Check Close Button prefs.show() with qtbot.waitSignal(prefs.finished) as status: - prefs.buttonBox.button(QDialogButtonBox.StandardButton.Close).click() + prefs.buttonBox.button(QtDialogClose).click() assert status.args == [nwConst.DLG_FINISHED] # Close Using Escape Key prefs.show() with qtbot.waitSignal(prefs.finished) as status: - event = QKeyEvent(QEvent.Type.KeyPress, Qt.Key.Key_Escape, Qt.KeyboardModifier.NoModifier) + event = QKeyEvent(QEvent.Type.KeyPress, Qt.Key.Key_Escape, QtModeNone) prefs.keyPressEvent(event) assert status.args == [nwConst.DLG_FINISHED] @@ -332,7 +333,7 @@ def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, tstPaths): with monkeypatch.context() as mp: mp.setattr(QFontDatabase, "families", lambda *a: ["TestFont"]) with qtbot.waitSignal(prefs.newPreferencesReady) as signal: - prefs.buttonBox.button(QDialogButtonBox.StandardButton.Apply).click() + prefs.buttonBox.button(QtDialogApply).click() assert signal.args == [True, True, True, True] # Check Settings diff --git a/tests/test_dialogs/test_dlg_projectsettings.py b/tests/test_dialogs/test_dlg_projectsettings.py index 74cfd24a..9831ea1f 100644 --- a/tests/test_dialogs/test_dlg_projectsettings.py +++ b/tests/test_dialogs/test_dlg_projectsettings.py @@ -24,14 +24,15 @@ import pytest from tools import C, buildTestProject -from PyQt5.QtGui import QColor from PyQt5.QtCore import Qt +from PyQt5.QtGui import QColor from PyQt5.QtWidgets import QDialog, QAction, QColorDialog from novelwriter import CONFIG, SHARED -from novelwriter.enum import nwItemType from novelwriter.dialogs.editlabel import GuiEditLabel from novelwriter.dialogs.projectsettings import GuiProjectSettings +from novelwriter.enum import nwItemType +from novelwriter.types import QtMouseLeft KEY_DELAY = 1 @@ -42,8 +43,8 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI): test, but are instead tested in the individual tab tests. """ # Block the GUI blocking thread - monkeypatch.setattr(GuiProjectSettings, "exec_", lambda *a: None) - monkeypatch.setattr(GuiProjectSettings, "result", lambda *a: QDialog.Accepted) + monkeypatch.setattr(GuiProjectSettings, "exec", lambda *a: None) + monkeypatch.setattr(GuiProjectSettings, "result", lambda *a: QDialog.DialogCode.Accepted) # Check that we cannot open when there is no project nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger) @@ -188,13 +189,13 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, projPath, mockRn # Can't delete the first item (it's in use) status.listBox.clearSelection() status.listBox.setCurrentItem(status.listBox.topLevelItem(0)) - qtbot.mouseClick(status.delButton, Qt.LeftButton) + qtbot.mouseClick(status.delButton, QtMouseLeft) assert status.listBox.topLevelItemCount() == 4 # Can delete the second item status.listBox.clearSelection() status.listBox.setCurrentItem(status.listBox.topLevelItem(1)) - qtbot.mouseClick(status.delButton, Qt.LeftButton) + qtbot.mouseClick(status.delButton, QtMouseLeft) assert status.listBox.topLevelItemCount() == 3 # Add a new item @@ -270,21 +271,21 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, projPath, mockRn # Delete unused entry importance.listBox.clearSelection() importance.listBox.setCurrentItem(importance.listBox.topLevelItem(1)) - qtbot.mouseClick(importance.delButton, Qt.LeftButton) + qtbot.mouseClick(importance.delButton, QtMouseLeft) assert importance.listBox.topLevelItemCount() == 3 # Add a new entry with monkeypatch.context() as mp: mp.setattr(QColorDialog, "getColor", lambda *a: QColor(20, 30, 40)) - qtbot.mouseClick(importance.addButton, Qt.LeftButton) + qtbot.mouseClick(importance.addButton, QtMouseLeft) importance.listBox.clearSelection() importance.listBox.setCurrentItem(importance.listBox.topLevelItem(3)) for _ in range(8): - qtbot.keyClick(importance.editName, Qt.Key_Backspace, delay=KEY_DELAY) + qtbot.keyClick(importance.editName, Qt.Key.Key_Backspace, delay=KEY_DELAY) for c in "Final": qtbot.keyClick(importance.editName, c, delay=KEY_DELAY) - qtbot.mouseClick(importance.colButton, Qt.LeftButton) - qtbot.mouseClick(importance.saveButton, Qt.LeftButton) + qtbot.mouseClick(importance.colButton, QtMouseLeft) + qtbot.mouseClick(importance.saveButton, QtMouseLeft) assert importance.listBox.topLevelItemCount() == 4 assert importance.wasChanged is True @@ -367,7 +368,7 @@ def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, projPath, mockRnd): assert replace.listBox.topLevelItemCount() == 2 # Create a new entry - qtbot.mouseClick(replace.addButton, Qt.LeftButton) + qtbot.mouseClick(replace.addButton, QtMouseLeft) assert replace.listBox.topLevelItemCount() == 3 assert replace.listBox.topLevelItem(2).text(0) == "" # type: ignore assert replace.listBox.topLevelItem(2).text(1) == "" # type: ignore @@ -380,13 +381,13 @@ def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, projPath, mockRnd): replace.editValue.setText("") for c in "With This Stuff ": qtbot.keyClick(replace.editValue, c, delay=KEY_DELAY) - qtbot.mouseClick(replace.saveButton, Qt.LeftButton) + qtbot.mouseClick(replace.saveButton, QtMouseLeft) assert replace.listBox.topLevelItem(2).text(0) == "" # type: ignore assert replace.listBox.topLevelItem(2).text(1) == "With This Stuff " # type: ignore # Create a new entry again replace.listBox.clearSelection() - qtbot.mouseClick(replace.addButton, Qt.LeftButton) + qtbot.mouseClick(replace.addButton, QtMouseLeft) assert replace.listBox.topLevelItemCount() == 4 # The list is sorted, so we must find it @@ -399,7 +400,7 @@ def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, projPath, mockRnd): # Then delete the new item replace.listBox.setCurrentItem(replace.listBox.topLevelItem(newIdx)) - qtbot.mouseClick(replace.delButton, Qt.LeftButton) + qtbot.mouseClick(replace.delButton, QtMouseLeft) assert replace.listBox.topLevelItemCount() == 3 # Check Project diff --git a/tests/test_dialogs/test_dlg_wordlist.py b/tests/test_dialogs/test_dlg_wordlist.py index 8f7483a2..4972481d 100644 --- a/tests/test_dialogs/test_dlg_wordlist.py +++ b/tests/test_dialogs/test_dlg_wordlist.py @@ -38,8 +38,8 @@ def testDlgWordList_Dialog(qtbot, monkeypatch, nwGUI, fncPath, projPath): """test the word list editor.""" buildTestProject(nwGUI, projPath) - monkeypatch.setattr(GuiWordList, "exec_", lambda *a: None) - monkeypatch.setattr(GuiWordList, "result", lambda *a: QDialog.Accepted) + monkeypatch.setattr(GuiWordList, "exec", lambda *a: None) + monkeypatch.setattr(GuiWordList, "result", lambda *a: QDialog.DialogCode.Accepted) monkeypatch.setattr(GuiWordList, "accept", lambda *a: None) # Open project diff --git a/tests/test_ext/test_ext_eventfilters.py b/tests/test_ext/test_ext_eventfilters.py index 68a56bab..a68a2eb9 100644 --- a/tests/test_ext/test_ext_eventfilters.py +++ b/tests/test_ext/test_ext_eventfilters.py @@ -27,6 +27,7 @@ from PyQt5.QtCore import QEvent, QObject, QPoint, Qt from PyQt5.QtWidgets import QWidget from novelwriter.extensions.eventfilters import WheelEventFilter +from novelwriter.types import QtModShift class MockWidget(QWidget): @@ -50,7 +51,7 @@ def testExtEventFilters_WheelEventFilter(): assert widget.count == 0 # Sending a key event does nothing - event = QKeyEvent(QEvent.KeyPress, 1, Qt.ShiftModifier) + event = QKeyEvent(QEvent.Type.KeyPress, 1, QtModShift) eFilter.eventFilter(obj, event) assert widget.count == 0 diff --git a/tests/test_gui/test_gui_doceditor.py b/tests/test_gui/test_gui_doceditor.py index fd947cda..d947377a 100644 --- a/tests/test_gui/test_gui_doceditor.py +++ b/tests/test_gui/test_gui_doceditor.py @@ -22,12 +22,12 @@ from __future__ import annotations import pytest -from tools import C, buildTestProject from mocked import causeOSError +from tools import C, buildTestProject -from PyQt5.QtGui import QClipboard, QTextBlock, QTextCursor, QTextOption from PyQt5.QtCore import QThreadPool, Qt -from PyQt5.QtWidgets import QAction, QMenu, qApp +from PyQt5.QtGui import QClipboard, QTextBlock, QTextCursor, QTextOption +from PyQt5.QtWidgets import QAction, QApplication, QMenu from novelwriter import CONFIG, SHARED from novelwriter.constants import nwKeyWords, nwUnicode @@ -37,7 +37,7 @@ from novelwriter.enum import ( ) from novelwriter.gui.doceditor import GuiDocEditor, GuiDocToolBar from novelwriter.text.counting import standardCounter -from novelwriter.types import QtAlignJustify, QtAlignLeft +from novelwriter.types import QtAlignJustify, QtAlignLeft, QtKeepAnchor, QtMouseLeft, QtMoveRight KEY_DELAY = 1 @@ -95,7 +95,7 @@ def testGuiEditor_Init(qtbot, nwGUI, projPath, ipsumText, mockRnd): # Select item from header with qtbot.waitSignal(nwGUI.docEditor.requestProjectItemSelected, timeout=1000) as signal: - qtbot.mouseClick(nwGUI.docEditor.docHeader, Qt.MouseButton.LeftButton) + qtbot.mouseClick(nwGUI.docEditor.docHeader, QtMouseLeft) assert signal.args == [nwGUI.docEditor.docHeader._docHandle, True] # Close from header @@ -109,7 +109,7 @@ def testGuiEditor_Init(qtbot, nwGUI, projPath, ipsumText, mockRnd): # Select item from header with qtbot.waitSignal(nwGUI.docEditor.requestProjectItemSelected, timeout=1000) as signal: - qtbot.mouseClick(nwGUI.docEditor.docHeader, Qt.MouseButton.LeftButton) + qtbot.mouseClick(nwGUI.docEditor.docHeader, QtMouseLeft) assert signal.args == ["", True] # qtbot.stop() @@ -244,7 +244,7 @@ def testGuiEditor_MetaData(qtbot, nwGUI, projPath, mockRnd): @pytest.mark.gui def testGuiEditor_ContextMenu(monkeypatch, qtbot, nwGUI, projPath, mockRnd): """Test the editor context menu.""" - monkeypatch.setattr(QMenu, "exec_", lambda *a: None) + monkeypatch.setattr(QMenu, "exec", lambda *a: None) buildTestProject(nwGUI, projPath) assert nwGUI.openDocument(C.hSceneDoc) is True @@ -361,14 +361,14 @@ def testGuiEditor_ContextMenu(monkeypatch, qtbot, nwGUI, projPath, mockRnd): assert actions == [ "Cut", "Copy", "Paste", "Select All", "Select Word", "Select Paragraph" ] - qApp.clipboard().clear() + QApplication.clipboard().clear() ctxMenu.actions()[1].trigger() - assert qApp.clipboard().text(QClipboard.Mode.Clipboard) == "text" + assert QApplication.clipboard().text(QClipboard.Mode.Clipboard) == "text" # Cut Text - qApp.clipboard().clear() + QApplication.clipboard().clear() ctxMenu.actions()[0].trigger() - assert qApp.clipboard().text(QClipboard.Mode.Clipboard) == "text" + assert QApplication.clipboard().text(QClipboard.Mode.Clipboard) == "text" assert "text" not in docEditor.getText() # Paste Text @@ -400,7 +400,7 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd): # Select/Cut/Copy/Paste/Undo/Redo # =============================== - qApp.clipboard().clear() + QApplication.clipboard().clear() # Select All assert nwGUI.docEditor.docAction(nwDocAction.SEL_ALL) is True @@ -452,7 +452,7 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd): assert newPara[5] == ipsumText[4] assert newPara[6] == ipsumText[2] - qApp.clipboard().clear() + QApplication.clipboard().clear() # Emphasis/Undo/Redo # ================== @@ -1413,7 +1413,7 @@ def testGuiEditor_MultiBlockFormatting(qtbot, nwGUI, projPath, ipsumText, mockRn # Toggle Comment cursor = nwGUI.docEditor.textCursor() cursor.setPosition(50) - cursor.movePosition(QTextCursor.MoveOperation.Right, QTextCursor.MoveMode.KeepAnchor, 2000) + cursor.movePosition(QtMoveRight, QtKeepAnchor, 2000) nwGUI.docEditor.setTextCursor(cursor) nwGUI.docEditor._iterFormatBlocks(nwDocAction.BLOCK_COM) @@ -1434,7 +1434,7 @@ def testGuiEditor_MultiBlockFormatting(qtbot, nwGUI, projPath, ipsumText, mockRn # Un-toggle all cursor = nwGUI.docEditor.textCursor() cursor.setPosition(50) - cursor.movePosition(QTextCursor.MoveOperation.Right, QTextCursor.MoveMode.KeepAnchor, 3000) + cursor.movePosition(QtMoveRight, QtKeepAnchor, 3000) nwGUI.docEditor.setTextCursor(cursor) nwGUI.docEditor._iterFormatBlocks(nwDocAction.BLOCK_COM) @@ -1445,7 +1445,7 @@ def testGuiEditor_MultiBlockFormatting(qtbot, nwGUI, projPath, ipsumText, mockRn # Toggle Ignore Text cursor = nwGUI.docEditor.textCursor() cursor.setPosition(50) - cursor.movePosition(QTextCursor.MoveOperation.Right, QTextCursor.MoveMode.KeepAnchor, 2000) + cursor.movePosition(QtMoveRight, QtKeepAnchor, 2000) nwGUI.docEditor.setTextCursor(cursor) nwGUI.docEditor._iterFormatBlocks(nwDocAction.BLOCK_IGN) @@ -1456,7 +1456,7 @@ def testGuiEditor_MultiBlockFormatting(qtbot, nwGUI, projPath, ipsumText, mockRn # Clear all paragraphs cursor = nwGUI.docEditor.textCursor() cursor.setPosition(50) - cursor.movePosition(QTextCursor.MoveOperation.Right, QTextCursor.MoveMode.KeepAnchor, 3000) + cursor.movePosition(QtMoveRight, QtKeepAnchor, 3000) nwGUI.docEditor.setTextCursor(cursor) nwGUI.docEditor._iterFormatBlocks(nwDocAction.BLOCK_TXT) @@ -1788,7 +1788,7 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, prjLipsum): assert abs(docEditor.getCursorPosition() - 1299) < 3 # Find next by button - qtbot.mouseClick(docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY) + qtbot.mouseClick(docSearch.searchButton, QtMouseLeft, delay=KEY_DELAY) assert abs(docEditor.getCursorPosition() - 1513) < 3 # Activate loop search @@ -1806,14 +1806,14 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, prjLipsum): docEditor.setCursorPosition(15) # Toggle search again with header button - qtbot.mouseClick(docEditor.docHeader.searchButton, Qt.LeftButton, delay=KEY_DELAY) + qtbot.mouseClick(docEditor.docHeader.searchButton, QtMouseLeft, delay=KEY_DELAY) docSearch.setSearchText("") assert docSearch.isVisible() is True # Search for non-existing docEditor.setCursorPosition(0) docSearch.setSearchText("abcdef") - qtbot.mouseClick(docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY) + qtbot.mouseClick(docSearch.searchButton, QtMouseLeft, delay=KEY_DELAY) assert docEditor.getCursorPosition() < 3 # No result # Enable RegEx search @@ -1824,19 +1824,19 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, prjLipsum): # Set invalid RegEx docEditor.setCursorPosition(0) docSearch.setSearchText(r"\bSus[") - qtbot.mouseClick(docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY) + qtbot.mouseClick(docSearch.searchButton, QtMouseLeft, delay=KEY_DELAY) assert docEditor.getCursorPosition() < 3 # No result # Set dangerous RegEx (issue #1015) # If this doesn't get caught, the app will hang docEditor.setCursorPosition(0) docSearch.setSearchText(r".*") - qtbot.mouseClick(docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY) + qtbot.mouseClick(docSearch.searchButton, QtMouseLeft, delay=KEY_DELAY) assert abs(docEditor.getCursorPosition() - 14) < 3 # Set valid RegEx docSearch.setSearchText(r"\bSus") - qtbot.mouseClick(docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY) + qtbot.mouseClick(docSearch.searchButton, QtMouseLeft, delay=KEY_DELAY) assert abs(docEditor.getCursorPosition() - 223) < 3 # Find next and then prev @@ -1887,7 +1887,7 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, prjLipsum): assert abs(docEditor.getCursorPosition() - 223) < 3 # Replace "sus" with "foo" via replace button - qtbot.mouseClick(docSearch.replaceButton, Qt.LeftButton, delay=KEY_DELAY) + qtbot.mouseClick(docSearch.replaceButton, QtMouseLeft, delay=KEY_DELAY) assert docEditor.getText()[220:228] == "foocipit" # Revert last two replaces diff --git a/tests/test_gui/test_gui_docviewer.py b/tests/test_gui/test_gui_docviewer.py index 47825510..dcea6af8 100644 --- a/tests/test_gui/test_gui_docviewer.py +++ b/tests/test_gui/test_gui_docviewer.py @@ -24,14 +24,15 @@ import pytest from mocked import causeException -from PyQt5.QtGui import QMouseEvent, QTextCursor from PyQt5.QtCore import QEvent, QPoint, Qt, QUrl -from PyQt5.QtWidgets import QMenu, qApp, QAction +from PyQt5.QtGui import QMouseEvent, QTextCursor +from PyQt5.QtWidgets import QAction, QApplication, QMenu from novelwriter import CONFIG, SHARED from novelwriter.enum import nwDocAction from novelwriter.core.tohtml import ToHtml from novelwriter.gui.docviewer import GuiDocViewer +from novelwriter.types import QtMouseLeft, QtModeNone @pytest.mark.gui @@ -59,9 +60,9 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum): assert nwGUI.projView.projTree.getSelectedHandle() is None # Re-select via header click - button = Qt.MouseButton.LeftButton - modifier = Qt.KeyboardModifier.NoModifier - event = QMouseEvent(QEvent.MouseButtonPress, QPoint(), button, button, modifier) + button = QtMouseLeft + modifier = QtModeNone + event = QMouseEvent(QEvent.Type.MouseButtonPress, QPoint(), button, button, modifier) docViewer.docHeader.mousePressEvent(event) assert nwGUI.projView.projTree.getSelectedHandle() == "88243afbe5ed8" @@ -77,7 +78,7 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum): docViewer.setTextCursor(cursor) docViewer._makeSelection(QTextCursor.WordUnderCursor) - qClip = qApp.clipboard() + qClip = QApplication.clipboard() qClip.clear() # Cut @@ -146,7 +147,7 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum): docViewer.setTextCursor(cursor) docViewer._makeSelection(QTextCursor.WordUnderCursor) with monkeypatch.context() as mp: - mp.setattr(QMenu, "exec_", mockExec) + mp.setattr(QMenu, "exec", mockExec) docViewer._openContextMenu(docViewer.cursorRect().center()) assert menuOpened @@ -164,7 +165,7 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum): assert docViewer.docHandle == "88243afbe5ed8" qtbot.mouseClick(docViewer.viewport(), Qt.ForwardButton, pos=rect.center(), delay=100) assert docViewer.docHandle == "4c4f28287af27" - qtbot.mouseClick(docViewer.viewport(), Qt.LeftButton, pos=rect.center(), delay=100) + qtbot.mouseClick(docViewer.viewport(), QtMouseLeft, pos=rect.center(), delay=100) assert docViewer.docHandle == "4c4f28287af27" # Scroll bar default on empty document diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py index 8b8a1bd7..4de04a95 100644 --- a/tests/test_gui/test_gui_guimain.py +++ b/tests/test_gui/test_gui_guimain.py @@ -60,7 +60,7 @@ def testGuiMain_ProjectBlocker(nwGUI): @pytest.mark.gui def testGuiMain_Launch(qtbot, monkeypatch, nwGUI, projPath): """Test the handling of launch tasks.""" - monkeypatch.setattr(GuiWelcome, "exec_", lambda *a: None) + monkeypatch.setattr(GuiWelcome, "exec", lambda *a: None) CONFIG.lastNotes = "0x0" buildTestProject(nwGUI, projPath) @@ -511,7 +511,7 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd): assert "test" in suggest with monkeypatch.context() as mp: - mp.setattr(QMenu, "exec_", lambda *a: None) + mp.setattr(QMenu, "exec", lambda *a: None) docEditor.setCursorPosition(errPos) docEditor._openContextFromCursor() diff --git a/tests/test_gui/test_gui_i18n.py b/tests/test_gui/test_gui_i18n.py index b8bda559..941c140d 100644 --- a/tests/test_gui/test_gui_i18n.py +++ b/tests/test_gui/test_gui_i18n.py @@ -23,11 +23,9 @@ from __future__ import annotations import sys import pytest -from collections.abc import Callable - from tools import buildTestProject -from PyQt5.QtWidgets import QDialog, qApp, QMessageBox +from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox from novelwriter import CONFIG, SHARED from novelwriter.dialogs.about import GuiAbout @@ -49,18 +47,18 @@ LANG_DATA = CONFIG.listLanguages(CONFIG.LANG_NW) @pytest.mark.parametrize("language", [a for a, b in LANG_DATA]) def testGuiI18n_Localisation(qtbot, monkeypatch, language, nwGUI, projPath): """Test loading the gui with a specific language.""" - monkeypatch.setattr(QDialog, "exec_", lambda *a: None) - monkeypatch.setattr(QMessageBox, "exec_", lambda *a: None) + monkeypatch.setattr(QDialog, "exec", lambda *a: None) + monkeypatch.setattr(QMessageBox, "exec", lambda *a: None) monkeypatch.setattr(QMessageBox, "result", lambda *a: QMessageBox.Yes) # Set the test language CONFIG.guiLocale = language - CONFIG.initLocalisation(qApp) + CONFIG.initLocalisation(QApplication.instance()) # type: ignore buildTestProject(nwGUI, projPath) nwGUI.show() - def showDialog(func: Callable, dType: QDialog) -> None: + def showDialog(func, dType) -> None: func() qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(dType) is not None, timeout=1000) dialog = SHARED.findTopLevelWidget(dType) diff --git a/tests/test_gui/test_gui_mainmenu.py b/tests/test_gui/test_gui_mainmenu.py index b0a0351f..2d65c162 100644 --- a/tests/test_gui/test_gui_mainmenu.py +++ b/tests/test_gui/test_gui_mainmenu.py @@ -25,13 +25,13 @@ import pytest from tools import C, writeFile, buildTestProject from PyQt5.QtGui import QTextCursor, QTextBlock -from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QAction, QFileDialog, QMessageBox from novelwriter import CONFIG, SHARED -from novelwriter.enum import nwDocAction, nwDocInsert from novelwriter.constants import nwKeyWords, nwUnicode +from novelwriter.enum import nwDocAction, nwDocInsert from novelwriter.gui.doceditor import GuiDocEditor +from novelwriter.types import QtMouseLeft @pytest.mark.gui @@ -359,7 +359,7 @@ def testGuiMenu_ContextMenus(qtbot, nwGUI, prjLipsum): rect = nwGUI.docEditor.cursorRect() nwGUI.docEditor._openContextMenu(rect.bottomRight()) - qtbot.mouseClick(nwGUI.docEditor, Qt.LeftButton, pos=rect.topLeft()) + qtbot.mouseClick(nwGUI.docEditor, QtMouseLeft, pos=rect.topLeft()) nwGUI.docEditor._makePosSelection(QTextCursor.WordUnderCursor, rect.center()) cursor = nwGUI.docEditor.textCursor() @@ -386,7 +386,7 @@ def testGuiMenu_ContextMenus(qtbot, nwGUI, prjLipsum): rect = nwGUI.docViewer.cursorRect() nwGUI.docViewer._openContextMenu(rect.bottomRight()) - qtbot.mouseClick(nwGUI.docViewer, Qt.LeftButton, pos=rect.topLeft()) + qtbot.mouseClick(nwGUI.docViewer, QtMouseLeft, pos=rect.topLeft()) nwGUI.docViewer._makePosSelection(QTextCursor.WordUnderCursor, rect.center()) cursor = nwGUI.docViewer.textCursor() @@ -410,12 +410,12 @@ def testGuiMenu_ContextMenus(qtbot, nwGUI, prjLipsum): assert nwGUI.docViewer.docHeader.backButton.isEnabled() assert not nwGUI.docViewer.docHeader.forwardButton.isEnabled() - qtbot.mouseClick(nwGUI.docViewer.docHeader.backButton, Qt.LeftButton) + qtbot.mouseClick(nwGUI.docViewer.docHeader.backButton, QtMouseLeft) assert nwGUI.docViewer.docHandle == "4c4f28287af27" assert not nwGUI.docViewer.docHeader.backButton.isEnabled() assert nwGUI.docViewer.docHeader.forwardButton.isEnabled() - qtbot.mouseClick(nwGUI.docViewer.docHeader.forwardButton, Qt.LeftButton) + qtbot.mouseClick(nwGUI.docViewer.docHeader.forwardButton, QtMouseLeft) assert nwGUI.docViewer.docHandle == "04468803b92e1" assert nwGUI.docViewer.docHeader.backButton.isEnabled() assert not nwGUI.docViewer.docHeader.forwardButton.isEnabled() diff --git a/tests/test_gui/test_gui_noveltree.py b/tests/test_gui/test_gui_noveltree.py index 120b66be..12cab27a 100644 --- a/tests/test_gui/test_gui_noveltree.py +++ b/tests/test_gui/test_gui_noveltree.py @@ -26,14 +26,15 @@ from pathlib import Path from tools import C, buildTestProject -from PyQt5.QtGui import QFocusEvent from PyQt5.QtCore import QPoint, Qt, QEvent +from PyQt5.QtGui import QFocusEvent from PyQt5.QtWidgets import QInputDialog, QToolTip from novelwriter import CONFIG, SHARED +from novelwriter.dialogs.editlabel import GuiEditLabel from novelwriter.enum import nwWidget, nwItemType from novelwriter.gui.noveltree import GuiNovelTree, NovelTreeColumn -from novelwriter.dialogs.editlabel import GuiEditLabel +from novelwriter.types import QtMouseLeft @pytest.mark.gui @@ -112,7 +113,7 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd): # Clear selection with mouse vPort = novelTree.viewport() - qtbot.mouseClick(vPort, Qt.LeftButton, pos=vPort.rect().center(), delay=10) + qtbot.mouseClick(vPort, QtMouseLeft, pos=vPort.rect().center(), delay=10) assert not scItem.isSelected() # Double-click item @@ -224,7 +225,7 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd): scItem = novelTree.topLevelItem(2) scItem.setSelected(True) assert scItem.isSelected() - novelTree.focusOutEvent(QFocusEvent(QEvent.None_, Qt.MouseFocusReason)) + novelTree.focusOutEvent(QFocusEvent(QEvent.Type.None_, Qt.MouseFocusReason)) assert not scItem.isSelected() # Close diff --git a/tests/test_gui/test_gui_projtree.py b/tests/test_gui/test_gui_projtree.py index 4934f26c..49ce464e 100644 --- a/tests/test_gui/test_gui_projtree.py +++ b/tests/test_gui/test_gui_projtree.py @@ -23,23 +23,24 @@ from __future__ import annotations import pytest from pathlib import Path -from novelwriter.core.project import NWProject -from tools import C, buildTestProject from mocked import causeOSError +from tools import C, buildTestProject -from PyQt5.QtGui import QDragEnterEvent, QDragMoveEvent, QDropEvent, QMouseEvent from PyQt5.QtCore import QEvent, QMimeData, QPoint, QTimer, Qt +from PyQt5.QtGui import QDragEnterEvent, QDragMoveEvent, QDropEvent, QMouseEvent from PyQt5.QtWidgets import QMessageBox, QMenu, QTreeWidget, QTreeWidgetItem, QDialog from novelwriter import CONFIG, SHARED -from novelwriter.enum import nwItemLayout, nwItemType, nwItemClass, nwWidget -from novelwriter.guimain import GuiMain from novelwriter.core.item import NWItem -from novelwriter.gui.projtree import GuiProjectTree, GuiProjectView, _TreeContextMenu +from novelwriter.core.project import NWProject from novelwriter.dialogs.docmerge import GuiDocMerge from novelwriter.dialogs.docsplit import GuiDocSplit from novelwriter.dialogs.editlabel import GuiEditLabel +from novelwriter.enum import nwItemLayout, nwItemType, nwItemClass, nwWidget +from novelwriter.gui.projtree import GuiProjectTree, GuiProjectView, _TreeContextMenu +from novelwriter.guimain import GuiMain +from novelwriter.types import QtMouseLeft, QtMouseMiddle, QtModeNone @pytest.mark.gui @@ -539,8 +540,8 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd, mergeData = {} monkeypatch.setattr(GuiDocMerge, "__init__", lambda *a: None) - monkeypatch.setattr(GuiDocMerge, "exec_", lambda *a: None) - monkeypatch.setattr(GuiDocMerge, "result", lambda *a: QDialog.Accepted) + monkeypatch.setattr(GuiDocMerge, "exec", lambda *a: None) + monkeypatch.setattr(GuiDocMerge, "result", lambda *a: QDialog.DialogCode.Accepted) monkeypatch.setattr(GuiDocMerge, "getData", lambda *a: mergeData) buildTestProject(nwGUI, projPath) @@ -596,7 +597,7 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd, # User cancels merge with monkeypatch.context() as mp: - mp.setattr(GuiDocMerge, "result", lambda *a: QDialog.Rejected) + mp.setattr(GuiDocMerge, "result", lambda *a: QDialog.DialogCode.Rejected) assert projTree._mergeDocuments(hChapter1, True) is False # The merge goes through @@ -640,8 +641,8 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, projPath, mockRnd, splitText = [] monkeypatch.setattr(GuiDocSplit, "__init__", lambda *a: None) - monkeypatch.setattr(GuiDocSplit, "exec_", lambda *a: None) - monkeypatch.setattr(GuiDocSplit, "result", lambda *a: QDialog.Accepted) + monkeypatch.setattr(GuiDocSplit, "exec", lambda *a: None) + monkeypatch.setattr(GuiDocSplit, "result", lambda *a: QDialog.DialogCode.Accepted) monkeypatch.setattr(GuiDocSplit, "getData", lambda *a: (splitData, splitText)) # Create a project @@ -735,7 +736,7 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, projPath, mockRnd, # Cancelled by user with monkeypatch.context() as mp: - mp.setattr(GuiDocSplit, "result", lambda *a: QDialog.Rejected) + mp.setattr(GuiDocSplit, "result", lambda *a: QDialog.DialogCode.Rejected) assert projTree._splitDocument(hSplitDoc) is False # qtbot.stop() @@ -821,8 +822,8 @@ def testGuiProjTree_AutoScroll(qtbot, monkeypatch, nwGUI: GuiMain, projPath, moc action = Qt.DropAction.MoveAction mime = QMimeData() - mouse = Qt.MouseButton.LeftButton - modifier = Qt.KeyboardModifier.NoModifier + mouse = QtMouseLeft + modifier = QtModeNone # Scroll Down h = projTree.height() @@ -880,8 +881,8 @@ def testGuiProjTree_DragAndDrop(qtbot, monkeypatch, caplog, nwGUI: GuiMain, proj nPos = projTree.visualItemRect(projTree._getTreeItem(C.hNovelRoot)).bottomLeft() action = Qt.DropAction.MoveAction mime = QMimeData() - mouse = Qt.MouseButton.LeftButton - modifier = Qt.KeyboardModifier.NoModifier + mouse = QtMouseLeft + modifier = QtModeNone projTree.saveTreeOrder() treeOrder = SHARED.project.tree._order @@ -1082,8 +1083,8 @@ def testGuiProjTree_Other(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mockRnd) eType = QEvent.Type.MouseButtonPress pos = projTree.visualItemRect(projTree._getTreeItem(C.hChapterDoc)).center() - button = Qt.MouseButton.MiddleButton - modifier = Qt.KeyboardModifier.NoModifier + button = QtMouseMiddle + modifier = QtModeNone # Trigger the viewer event = QMouseEvent(eType, pos, button, button, modifier) @@ -1092,7 +1093,7 @@ def testGuiProjTree_Other(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mockRnd) # Trigger the left click clear pos = QPoint(5000, 5000) - button = Qt.MouseButton.LeftButton + button = QtMouseLeft event = QMouseEvent(eType, pos, button, button, modifier) projTree.setSelectedHandle(C.hChapterDoc) projTree.mousePressEvent(event) @@ -1162,7 +1163,7 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd): # Pop the menu with monkeypatch.context() as mp: - mp.setattr(QMenu, "exec_", lambda *a: None) + mp.setattr(QMenu, "exec", lambda *a: None) projTree.clearSelection() # No item under menu diff --git a/tests/test_gui/test_gui_theme.py b/tests/test_gui/test_gui_theme.py index 84ade0f8..ad2d7040 100644 --- a/tests/test_gui/test_gui_theme.py +++ b/tests/test_gui/test_gui_theme.py @@ -106,22 +106,22 @@ def testGuiTheme_Main(qtbot, nwGUI, tstPaths): assert mainTheme._parseColour(parser, "Palette", "colour6").getRgb() == (0, 127, 255, 255) # The palette should load with the parsed values - mainTheme._setPalette(parser, "Palette", "colour1", QPalette.Window) - assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (100, 150, 200, 255) - mainTheme._setPalette(parser, "Palette", "colour2", QPalette.Window) - assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (100, 150, 200, 250) - mainTheme._setPalette(parser, "Palette", "colour3", QPalette.Window) - assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (100, 150, 200, 250) - mainTheme._setPalette(parser, "Palette", "colour4", QPalette.Window) - assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (250, 250, 0, 255) - mainTheme._setPalette(parser, "Palette", "colour5", QPalette.Window) - assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (0, 0, 0, 0) - mainTheme._setPalette(parser, "Palette", "colour6", QPalette.Window) - assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (0, 127, 255, 255) + mainTheme._setPalette(parser, "Palette", "colour1", QPalette.ColorRole.Window) + assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (100, 150, 200, 255) + mainTheme._setPalette(parser, "Palette", "colour2", QPalette.ColorRole.Window) + assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (100, 150, 200, 250) + mainTheme._setPalette(parser, "Palette", "colour3", QPalette.ColorRole.Window) + assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (100, 150, 200, 250) + mainTheme._setPalette(parser, "Palette", "colour4", QPalette.ColorRole.Window) + assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (250, 250, 0, 255) + mainTheme._setPalette(parser, "Palette", "colour5", QPalette.ColorRole.Window) + assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (0, 0, 0, 0) + mainTheme._setPalette(parser, "Palette", "colour6", QPalette.ColorRole.Window) + assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (0, 127, 255, 255) # Non-existing value should return default colour - mainTheme._setPalette(parser, "Palette", "stuff", QPalette.Window) - assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (0, 0, 0, 255) + mainTheme._setPalette(parser, "Palette", "stuff", QPalette.ColorRole.Window) + assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (0, 0, 0, 255) # qtbot.stop() @@ -168,15 +168,15 @@ def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI): # ================== # Set a mock colour for the window background - mainTheme._guiPalette.color(QPalette.Window).setRgb(0, 0, 0, 0) + mainTheme._guiPalette.color(QPalette.ColorRole.Window).setRgb(0, 0, 0, 0) # Load the default theme CONFIG.guiTheme = "default" assert mainTheme.loadTheme() is True # This should load a standard palette - wCol = QApplication.style().standardPalette().color(QPalette.Window).getRgb() - assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == wCol + wCol = QApplication.style().standardPalette().color(QPalette.ColorRole.Window).getRgb() + assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == wCol # Load Default Light Theme # ======================== @@ -185,10 +185,14 @@ def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI): assert mainTheme.loadTheme() is True # Check a few values - assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (239, 239, 239, 255) - assert mainTheme._guiPalette.color(QPalette.WindowText).getRgb() == (0, 0, 0, 255) - assert mainTheme._guiPalette.color(QPalette.Base).getRgb() == (255, 255, 255, 255) - assert mainTheme._guiPalette.color(QPalette.AlternateBase).getRgb() == (239, 239, 239, 255) + assert mainTheme._guiPalette.color( + QPalette.ColorRole.Window).getRgb() == (239, 239, 239, 255) + assert mainTheme._guiPalette.color( + QPalette.ColorRole.WindowText).getRgb() == (0, 0, 0, 255) + assert mainTheme._guiPalette.color( + QPalette.ColorRole.Base).getRgb() == (255, 255, 255, 255) + assert mainTheme._guiPalette.color( + QPalette.ColorRole.AlternateBase).getRgb() == (239, 239, 239, 255) # Load Default Dark Theme # ======================= @@ -197,10 +201,14 @@ def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI): assert mainTheme.loadTheme() is True # Check a few values - assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (54, 54, 54, 255) - assert mainTheme._guiPalette.color(QPalette.WindowText).getRgb() == (204, 204, 204, 255) - assert mainTheme._guiPalette.color(QPalette.Base).getRgb() == (62, 62, 62, 255) - assert mainTheme._guiPalette.color(QPalette.AlternateBase).getRgb() == (78, 78, 78, 255) + assert mainTheme._guiPalette.color( + QPalette.ColorRole.Window).getRgb() == (54, 54, 54, 255) + assert mainTheme._guiPalette.color( + QPalette.ColorRole.WindowText).getRgb() == (204, 204, 204, 255) + assert mainTheme._guiPalette.color( + QPalette.ColorRole.Base).getRgb() == (62, 62, 62, 255) + assert mainTheme._guiPalette.color( + QPalette.ColorRole.AlternateBase).getRgb() == (78, 78, 78, 255) # qtbot.stop() diff --git a/tests/test_tools/test_tools_lipsum.py b/tests/test_tools/test_tools_lipsum.py index cc4f8b18..b2ecc445 100644 --- a/tests/test_tools/test_tools_lipsum.py +++ b/tests/test_tools/test_tools_lipsum.py @@ -60,7 +60,7 @@ def testToolLipsum_Main(qtbot, monkeypatch, nwGUI, projPath, mockRnd): assert nwGUI.openDocument(C.hSceneDoc) is True nwGUI.docEditor.setCursorLine(3) with monkeypatch.context() as mp: - mp.setattr(GuiLipsum, "exec_", lambda *a: None) + mp.setattr(GuiLipsum, "exec", lambda *a: None) mp.setattr(GuiLipsum, "lipsumText", "FooBar") nwGUI.mainMenu.aLipsumText.activate(QAction.Trigger) assert nwGUI.docEditor.getText() == "### New Scene\n\nFooBar" diff --git a/tests/test_tools/test_tools_manusbuild.py b/tests/test_tools/test_tools_manusbuild.py index 4ff2c7bd..6497cb3c 100644 --- a/tests/test_tools/test_tools_manusbuild.py +++ b/tests/test_tools/test_tools_manusbuild.py @@ -27,15 +27,16 @@ from pytestqt.qtbot import QtBot from tools import buildTestProject -from PyQt5.QtGui import QDesktopServices from PyQt5.QtCore import QUrl -from PyQt5.QtWidgets import QDialogButtonBox, QFileDialog, QListWidgetItem, QMessageBox +from PyQt5.QtGui import QDesktopServices +from PyQt5.QtWidgets import QFileDialog, QListWidgetItem, QMessageBox +from novelwriter.constants import nwLabels +from novelwriter.core.buildsettings import BuildSettings from novelwriter.enum import nwBuildFmt from novelwriter.guimain import GuiMain -from novelwriter.constants import nwLabels from novelwriter.tools.manusbuild import GuiManuscriptBuild -from novelwriter.core.buildsettings import BuildSettings +from novelwriter.types import QtDialogClose @pytest.mark.gui @@ -94,7 +95,7 @@ def testManuscriptBuild_Main( assert (fncPath / "TestBuild").with_suffix(nwLabels.BUILD_EXT[fmt]).exists() lastFmt = fmt - manus._dialogButtonClicked(manus.dlgButtons.button(QDialogButtonBox.Close)) + manus._dialogButtonClicked(manus.dlgButtons.button(QtDialogClose)) manus.deleteLater() assert build.lastBuildName == "TestBuild" @@ -149,7 +150,7 @@ def testManuscriptBuild_Main( assert lastUrl.startswith("file://") # Finish - manus._dialogButtonClicked(manus.dlgButtons.button(QDialogButtonBox.Close)) + manus._dialogButtonClicked(manus.dlgButtons.button(QtDialogClose)) # qtbot.stop() # END Test testManuscriptBuild_Main diff --git a/tests/test_tools/test_tools_manuscript.py b/tests/test_tools/test_tools_manuscript.py index 374bafa0..0d2e04ca 100644 --- a/tests/test_tools/test_tools_manuscript.py +++ b/tests/test_tools/test_tools_manuscript.py @@ -31,7 +31,7 @@ from tools import C, buildTestProject from PyQt5.QtCore import pyqtSlot from PyQt5.QtPrintSupport import QPrintPreviewDialog -from PyQt5.QtWidgets import QAction, QDialogButtonBox, QListWidgetItem +from PyQt5.QtWidgets import QAction, QListWidgetItem from novelwriter import CONFIG, SHARED from novelwriter.constants import nwHeadFmt @@ -40,7 +40,7 @@ from novelwriter.guimain import GuiMain from novelwriter.tools.manusbuild import GuiManuscriptBuild from novelwriter.tools.manuscript import GuiManuscript from novelwriter.tools.manussettings import GuiBuildSettings -from novelwriter.types import QtAlignAbsolute, QtAlignJustify +from novelwriter.types import QtAlignAbsolute, QtAlignJustify, QtDialogApply, QtDialogSave @pytest.mark.gui @@ -118,7 +118,7 @@ def testManuscript_Builds(qtbot: QtBot, nwGUI: GuiMain, projPath: Path): with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000): bSettings.newSettingsReady.connect(_testNewSettingsReady) - bSettings.buttonBox.button(QDialogButtonBox.Save).click() + bSettings.buttonBox.button(QtDialogSave).click() assert isinstance(build, BuildSettings) assert build.name == "Test Build" @@ -135,7 +135,7 @@ def testManuscript_Builds(qtbot: QtBot, nwGUI: GuiMain, projPath: Path): with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000): bSettings.newSettingsReady.connect(_testNewSettingsReady) - bSettings.buttonBox.button(QDialogButtonBox.Apply).click() # Should leave the dialog open + bSettings.buttonBox.button(QtDialogApply).click() # Should leave the dialog open assert isinstance(build, BuildSettings) assert build.name == "Test Build" @@ -278,7 +278,7 @@ def testManuscript_Features(monkeypatch, qtbot, nwGUI, projPath, mockRnd): build._changed = True manus.buildList.clearSelection() with monkeypatch.context() as mp: - mp.setattr("novelwriter.tools.manusbuild.GuiManuscriptBuild.exec_", lambda *a: None) + mp.setattr("novelwriter.tools.manusbuild.GuiManuscriptBuild.exec", lambda *a: None) manus.buildList.setCurrentRow(0) manus.btnBuild.click() @@ -313,7 +313,7 @@ def testManuscript_Print(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath: Pa assert manus.docPreview.toPlainText().strip() != "" with monkeypatch.context() as mp: - mp.setattr(QPrintPreviewDialog, "exec_", lambda *a: None) + mp.setattr(QPrintPreviewDialog, "exec", lambda *a: None) manus.btnPrint.click() for obj in manus.children(): if isinstance(obj, QPrintPreviewDialog): diff --git a/tests/test_tools/test_tools_manussettings.py b/tests/test_tools/test_tools_manussettings.py index 5f2ece6d..179df303 100644 --- a/tests/test_tools/test_tools_manussettings.py +++ b/tests/test_tools/test_tools_manussettings.py @@ -29,7 +29,7 @@ from tools import C, buildTestProject from PyQt5.QtGui import QFont from PyQt5.QtCore import pyqtSlot -from PyQt5.QtWidgets import QDialogButtonBox, QFontDialog +from PyQt5.QtWidgets import QFontDialog from novelwriter import CONFIG, SHARED from novelwriter.guimain import GuiMain @@ -38,6 +38,7 @@ from novelwriter.core.buildsettings import BuildSettings, FilterMode from novelwriter.tools.manussettings import ( GuiBuildSettings, _OutputTab, _FormatTab, _ContentTab, _HeadingsTab, _FilterTab ) +from novelwriter.types import QtDialogApply, QtDialogClose, QtDialogSave @pytest.mark.gui @@ -80,7 +81,7 @@ def testBuildSettings_Init(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockRnd # Capture Apply button with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000): bSettings.newSettingsReady.connect(_testNewSettingsReady) - bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Apply)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogApply)) assert triggered @@ -89,7 +90,7 @@ def testBuildSettings_Init(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockRnd with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000): bSettings.newSettingsReady.connect(_testNewSettingsReady) - bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Save)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogSave)) assert triggered @@ -106,7 +107,7 @@ def testBuildSettings_Init(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockRnd assert triggered # Finish - bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Close)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) # qtbot.stop() # END Test testBuildSettings_Init @@ -312,7 +313,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR ] # Finish - bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Close)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) # qtbot.stop() # END Test testBuildSettings_Filter @@ -484,7 +485,7 @@ def testBuildSettings_Headings(qtbot: QtBot, nwGUI: GuiMain): assert build.getBool("headings.hideSection") is True # Finish - bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Close)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) # qtbot.stop() # END Test testBuildSettings_Headings @@ -546,7 +547,7 @@ def testBuildSettings_Content(qtbot: QtBot, nwGUI: GuiMain): assert build.getBool("text.addNoteHeadings") is True # Finish - bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Close)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) # qtbot.stop() # END Test testBuildSettings_Content @@ -648,7 +649,7 @@ def testBuildSettings_Format(monkeypatch, qtbot: QtBot, nwGUI: GuiMain): assert fmtTab.textSize.value() == 10 # Finish - bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Close)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) # qtbot.stop() # END Test testBuildSettings_Format @@ -707,7 +708,7 @@ def testBuildSettings_Output(qtbot: QtBot, nwGUI: GuiMain): assert outTab.odtPageHeader.text() == nwHeadFmt.ODT_AUTO # Finish - bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Close)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) # qtbot.stop() # END Test testBuildSettings_Output diff --git a/tests/test_tools/test_tools_welcome.py b/tests/test_tools/test_tools_welcome.py index 29900674..71bf14de 100644 --- a/tests/test_tools/test_tools_welcome.py +++ b/tests/test_tools/test_tools_welcome.py @@ -26,13 +26,14 @@ from pathlib import Path from datetime import datetime from pytestqt.qtbot import QtBot -from PyQt5.QtCore import QPoint, Qt +from PyQt5.QtCore import QPoint from PyQt5.QtWidgets import QAction, QFileDialog, QMenu from novelwriter import CONFIG, SHARED from novelwriter.enum import nwItemClass from novelwriter.constants import nwFiles from novelwriter.tools.welcome import GuiWelcome +from novelwriter.types import QtMouseLeft @pytest.mark.gui @@ -70,7 +71,7 @@ def testToolWelcome_Main(qtbot: QtBot, monkeypatch, nwGUI, fncPath): @pytest.mark.gui def testToolWelcome_Open(qtbot: QtBot, monkeypatch, nwGUI, fncPath): """Test the open tab in the Welcome window.""" - monkeypatch.setattr(QMenu, "exec_", lambda *a: None) + monkeypatch.setattr(QMenu, "exec", lambda *a: None) monkeypatch.setattr(QMenu, "deleteLater", lambda *a: None) CONFIG.recentProjects.update("/stuff/project_one", "Project One", 12345, 1690000000) @@ -100,19 +101,19 @@ def testToolWelcome_Open(qtbot: QtBot, monkeypatch, nwGUI, fncPath): # Single click item assert tabOpen.selectedPath.text() == "Path: /stuff/project_two" - qtbot.mouseClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10) + qtbot.mouseClick(vPort, QtMouseLeft, pos=posTwo, delay=10) assert tabOpen.selectedPath.text() == "Path: /stuff/project_one" # Double click item - qtbot.mouseClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10) + qtbot.mouseClick(vPort, QtMouseLeft, pos=posTwo, delay=10) with monkeypatch.context() as mp: mp.setattr(welcome, "close", lambda *a: None) with qtbot.waitSignal(welcome.openProjectRequest, timeout=5000) as signal: - qtbot.mouseDClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10) + qtbot.mouseDClick(vPort, QtMouseLeft, pos=posTwo, delay=10) assert signal.args and signal.args[0] == Path("/stuff/project_one") # Press open button - qtbot.mouseClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10) + qtbot.mouseClick(vPort, QtMouseLeft, pos=posTwo, delay=10) with monkeypatch.context() as mp: mp.setattr(welcome, "close", lambda *a: None) with qtbot.waitSignal(welcome.openProjectRequest, timeout=5000) as signal: @@ -128,7 +129,7 @@ def testToolWelcome_Open(qtbot: QtBot, monkeypatch, nwGUI, fncPath): return obj return None - qtbot.mouseClick(vPort, Qt.MouseButton.LeftButton, pos=posOne, delay=10) + qtbot.mouseClick(vPort, QtMouseLeft, pos=posOne, delay=10) ctxMenu = getMenuForPos(posOne) assert isinstance(ctxMenu, QMenu) assert ctxMenu.actions()[0].text() == "Open Project" diff --git a/tests/test_tools/test_tools_writingstats.py b/tests/test_tools/test_tools_writingstats.py index 0524174a..ef76dbaf 100644 --- a/tests/test_tools/test_tools_writingstats.py +++ b/tests/test_tools/test_tools_writingstats.py @@ -25,15 +25,15 @@ import pytest from pathlib import Path -from tools import buildTestProject from mocked import causeOSError +from tools import buildTestProject -from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QAction, QFileDialog from novelwriter import SHARED from novelwriter.constants import nwFiles from novelwriter.tools.writingstats import GuiWritingStats +from novelwriter.types import QtMouseLeft @pytest.mark.gui @@ -97,11 +97,11 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, projPath, tstPaths): monkeypatch.setattr(QFileDialog, "getSaveFileName", lambda *a, **k: ("", "")) assert not sessLog._saveData(sessLog.FMT_CSV) assert not sessLog._saveData(sessLog.FMT_JSON) - assert not sessLog._saveData(None) + assert not sessLog._saveData(None) # type: ignore # Make the save succeed monkeypatch.setattr(QFileDialog, "getSaveFileName", lambda ss, tt, pp, options: (pp, "")) - sessLog.listBox.sortByColumn(sessLog.C_TIME, 0) + sessLog.listBox.sortByColumn(sessLog.C_TIME, 0) # type: ignore assert sessLog.novelWords.text() == "{:n}".format(600) assert sessLog.notesWords.text() == "{:n}".format(275) @@ -156,7 +156,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, projPath, tstPaths): # ============ # No Novel Files - qtbot.mouseClick(sessLog.incNovel, Qt.LeftButton) + qtbot.mouseClick(sessLog.incNovel, QtMouseLeft) assert sessLog._saveData(sessLog.FMT_JSON) jsonStats = tstPaths.tmpDir / "sessionStats.json" @@ -201,8 +201,8 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, projPath, tstPaths): ] # No Note Files - qtbot.mouseClick(sessLog.incNovel, Qt.LeftButton) - qtbot.mouseClick(sessLog.incNotes, Qt.LeftButton) + qtbot.mouseClick(sessLog.incNovel, QtMouseLeft) + qtbot.mouseClick(sessLog.incNotes, QtMouseLeft) assert sessLog._saveData(sessLog.FMT_JSON) jsonStats = tstPaths.tmpDir / "sessionStats.json" @@ -247,8 +247,8 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, projPath, tstPaths): ] # No Negative Entries - qtbot.mouseClick(sessLog.incNotes, Qt.LeftButton) - qtbot.mouseClick(sessLog.hideNegative, Qt.LeftButton) + qtbot.mouseClick(sessLog.incNotes, QtMouseLeft) + qtbot.mouseClick(sessLog.hideNegative, QtMouseLeft) assert sessLog._saveData(sessLog.FMT_JSON) # qtbot.stop() @@ -279,8 +279,8 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, projPath, tstPaths): ] # Un-hide Zero Entries - qtbot.mouseClick(sessLog.hideNegative, Qt.LeftButton) - qtbot.mouseClick(sessLog.hideZeros, Qt.LeftButton) + qtbot.mouseClick(sessLog.hideNegative, QtMouseLeft) + qtbot.mouseClick(sessLog.hideZeros, QtMouseLeft) assert sessLog._saveData(sessLog.FMT_JSON) jsonStats = tstPaths.tmpDir / "sessionStats.json" @@ -333,7 +333,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, projPath, tstPaths): ] # Group by Day - qtbot.mouseClick(sessLog.groupByDay, Qt.LeftButton) + qtbot.mouseClick(sessLog.groupByDay, QtMouseLeft) assert sessLog._saveData(sessLog.FMT_JSON) jsonStats = tstPaths.tmpDir / "sessionStats.json"