Clean up code in preparation for Qt6 (#1792)

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