Merge branch 'main' into release_2.2.1

This commit is contained in:
Veronica Berglyd Olsen
2024-01-27 15:44:16 +01:00
3 changed files with 28 additions and 17 deletions
+14 -14
View File
@@ -46,9 +46,9 @@ from novelwriter.constants import nwConst, nwUnicode
logger = logging.getLogger(__name__)
# =============================================================================================== #
##
# Checker Functions
# =============================================================================================== #
##
def checkStringNone(value: Any, default: str | None) -> str | None:
"""Check if a variable is a string or a None."""
@@ -131,9 +131,9 @@ def checkPath(value: Any, default: Path) -> Path:
return default
# =============================================================================================== #
##
# Validator Functions
# =============================================================================================== #
##
def isHandle(value: Any) -> bool:
"""Check if a string is a valid novelWriter handle.
@@ -204,9 +204,9 @@ def checkIntTuple(value: int, valid: tuple | list | set, default: int) -> int:
return default
# =============================================================================================== #
##
# Formatting Functions
# =============================================================================================== #
##
def formatInt(value: int) -> str:
"""Formats an integer with k, M, G etc."""
@@ -250,9 +250,9 @@ def formatTime(t: int) -> str:
return "ERROR"
# =============================================================================================== #
##
# String Functions
# =============================================================================================== #
##
def simplified(text: str) -> str:
"""Take a string and strip leading and trailing whitespaces, and
@@ -371,9 +371,9 @@ def numberToRoman(value: int, toLower: bool = False) -> str:
return roman.lower() if toLower else roman
# =============================================================================================== #
##
# Encoder Functions
# =============================================================================================== #
##
def jsonEncode(data: dict | list | tuple, n: int = 0, nmax: int = 0) -> str:
"""Encode a dictionary, list or tuple as a json object or array, and
@@ -463,9 +463,9 @@ def xmlIndent(tree: ET.Element | ET.ElementTree) -> None:
return
# =============================================================================================== #
##
# File and File System Functions
# =============================================================================================== #
##
def readTextFile(path: str | Path) -> str:
"""Read the content of a text file in a robust manner."""
@@ -507,9 +507,9 @@ def openExternalPath(path: Path) -> bool:
return False
# =============================================================================================== #
##
# Classes
# =============================================================================================== #
##
class NWConfigParser(ConfigParser):
"""Common: Adapted Config Parser
+4 -2
View File
@@ -899,7 +899,8 @@ class GuiMain(QMainWindow):
def showBuildManuscriptDialog(self) -> None:
"""Open the build manuscript dialog."""
if SHARED.hasProject:
dialog = GuiManuscript(self)
if (dialog := SHARED.findTopLevelWidget(GuiManuscript)) is None:
dialog = GuiManuscript(self)
dialog.setModal(False)
dialog.show()
dialog.raise_()
@@ -920,7 +921,8 @@ class GuiMain(QMainWindow):
def showWritingStatsDialog(self) -> None:
"""Open the session stats dialog."""
if SHARED.hasProject:
dialog = GuiWritingStats(self)
if (dialog := SHARED.findTopLevelWidget(GuiWritingStats)) is None:
dialog = GuiWritingStats(self)
dialog.setModal(False)
dialog.show()
dialog.raise_()
+10 -1
View File
@@ -27,7 +27,7 @@ from __future__ import annotations
import logging
from time import time
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, TypeVar
from pathlib import Path
from PyQt5.QtCore import QObject, QRunnable, QThreadPool, pyqtSignal
@@ -42,6 +42,8 @@ if TYPE_CHECKING: # pragma: no cover
logger = logging.getLogger(__name__)
NWWidget = TypeVar("NWWidget", bound=QWidget)
class SharedData(QObject):
@@ -215,6 +217,13 @@ class SharedData(QObject):
QThreadPool.globalInstance().start(runnable, priority=priority)
return
def findTopLevelWidget(self, kind: type[NWWidget]) -> NWWidget | None:
"""Find a top level widget."""
for widget in self.mainGui.children():
if isinstance(widget, kind):
return widget
return None
##
# Signal Proxy
##