Clean up code in preparation for Qt6 (#1792)
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
@@ -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))
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)))
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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:
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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" \u203a <a href='{foUrl}'>{foUrl}</a>",
|
f" \u203a <a href='{foUrl}'>{foUrl}</a>",
|
||||||
f" \u203a <a href='{loUrl}'>{loUrl}</a>",
|
f" \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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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}")
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
@@ -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}"])
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user