Fix linting errors in the main code
This commit is contained in:
+2
-2
@@ -7,8 +7,8 @@ import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
import PyQt6.QtCore # noqa: F401
|
||||
import PyQt6.QtGui # noqa: F401
|
||||
import PyQt6.QtCore
|
||||
import PyQt6.QtGui
|
||||
import PyQt6.QtWidgets # noqa: F401
|
||||
except Exception:
|
||||
print("ERROR: Failed to load dependency PyQt6")
|
||||
|
||||
@@ -36,7 +36,7 @@ from novelwriter.config import Config
|
||||
from novelwriter.error import exceptionHandler
|
||||
from novelwriter.shared import SharedData
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.guimain import GuiMain
|
||||
|
||||
# Package Meta
|
||||
@@ -148,7 +148,7 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
inOpts, inRemain = getopt.getopt(sysArgs, shortOpt, longOpt)
|
||||
except getopt.GetoptError as exc:
|
||||
print(helpMsg)
|
||||
print(f"ERROR: {str(exc)}")
|
||||
print(f"ERROR: {exc!s}")
|
||||
sys.exit(2)
|
||||
|
||||
if len(inRemain) > 0:
|
||||
|
||||
+11
-9
@@ -29,11 +29,10 @@ import unicodedata
|
||||
import uuid
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from collections.abc import Callable
|
||||
from configparser import ConfigParser
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Literal, TypeGuard, TypeVar
|
||||
from typing import TYPE_CHECKING, Any, Literal, TypeGuard, TypeVar
|
||||
from urllib.parse import urljoin
|
||||
from urllib.request import pathname2url
|
||||
|
||||
@@ -45,6 +44,9 @@ from novelwriter.constants import nwConst, nwLabels, nwUnicode, trConst
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Callable
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_Type = TypeVar("_Type")
|
||||
@@ -347,7 +349,7 @@ def fuzzyTime(seconds: int) -> str:
|
||||
elif seconds < 3300: # 55 minutes
|
||||
return QCoreApplication.translate(
|
||||
"Common", "{0} minutes ago"
|
||||
).format(int(round(seconds/60)))
|
||||
).format(round(seconds/60))
|
||||
elif seconds < 5400: # 90 minutes
|
||||
return QCoreApplication.translate(
|
||||
"Common", "an hour ago"
|
||||
@@ -355,7 +357,7 @@ def fuzzyTime(seconds: int) -> str:
|
||||
elif seconds < 84600: # 23.5 hours
|
||||
return QCoreApplication.translate(
|
||||
"Common", "{0} hours ago"
|
||||
).format(int(round(seconds/3600)))
|
||||
).format(round(seconds/3600))
|
||||
elif seconds < 129600: # 1.5 days
|
||||
return QCoreApplication.translate(
|
||||
"Common", "a day ago"
|
||||
@@ -363,7 +365,7 @@ def fuzzyTime(seconds: int) -> str:
|
||||
elif seconds < 561600: # 6.5 days
|
||||
return QCoreApplication.translate(
|
||||
"Common", "{0} days ago"
|
||||
).format(int(round(seconds/86400)))
|
||||
).format(round(seconds/86400))
|
||||
elif seconds < 907200: # 10.5 days
|
||||
return QCoreApplication.translate(
|
||||
"Common", "a week ago"
|
||||
@@ -371,7 +373,7 @@ def fuzzyTime(seconds: int) -> str:
|
||||
elif seconds < 2419200: # 28 days
|
||||
return QCoreApplication.translate(
|
||||
"Common", "{0} weeks ago"
|
||||
).format(int(round(seconds/604800)))
|
||||
).format(round(seconds/604800))
|
||||
elif seconds < 3888000: # 45 days
|
||||
return QCoreApplication.translate(
|
||||
"Common", "a month ago"
|
||||
@@ -379,7 +381,7 @@ def fuzzyTime(seconds: int) -> str:
|
||||
elif seconds < 29808000: # 345 days
|
||||
return QCoreApplication.translate(
|
||||
"Common", "{0} months ago"
|
||||
).format(int(round(seconds/2592000)))
|
||||
).format(round(seconds/2592000))
|
||||
elif seconds < 47336400: # 1.5 years
|
||||
return QCoreApplication.translate(
|
||||
"Common", "a year ago"
|
||||
@@ -387,7 +389,7 @@ def fuzzyTime(seconds: int) -> str:
|
||||
else:
|
||||
return QCoreApplication.translate(
|
||||
"Common", "{0} years ago"
|
||||
).format(int(round(seconds/31557600)))
|
||||
).format(round(seconds/31557600))
|
||||
|
||||
|
||||
def numberToRoman(value: int, toLower: bool = False) -> str:
|
||||
@@ -423,7 +425,7 @@ def describeFont(font: QFont) -> str:
|
||||
info = QFontInfo(font)
|
||||
family = info.family()
|
||||
styles = [v for v in info.styleName().split() if v not in family]
|
||||
return " ".join([f"{info.pointSize()} pt", family] + styles)
|
||||
return " ".join([f"{info.pointSize()} pt", family, *styles])
|
||||
return "Error"
|
||||
|
||||
|
||||
|
||||
+30
-27
@@ -29,10 +29,9 @@ import json
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, Final
|
||||
|
||||
from PyQt6.QtCore import (
|
||||
PYQT_VERSION, PYQT_VERSION_STR, QT_VERSION, QT_VERSION_STR, QLibraryInfo,
|
||||
@@ -48,7 +47,9 @@ from novelwriter.common import (
|
||||
from novelwriter.constants import nwFiles, nwUnicode
|
||||
from novelwriter.error import formatException, logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from datetime import datetime
|
||||
|
||||
from novelwriter.core.projectdata import NWProjectData
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -62,29 +63,27 @@ DEF_TREECOL = "theme"
|
||||
class Config:
|
||||
|
||||
__slots__ = (
|
||||
"_confPath", "_dataPath", "_homePath", "_backPath", "_appPath", "_appRoot", "_hasError",
|
||||
"_errData", "_nwLangPath", "_qtLangPath", "_qLocale", "_dLocale", "_dShortDate",
|
||||
"_dShortDateTime", "_qtTrans", "_manuals", "_recentProjects", "_recentPaths",
|
||||
"_backupPath",
|
||||
|
||||
"appName", "appHandle", "guiLocale", "guiTheme", "guiSyntax", "guiFont", "hideVScroll",
|
||||
"hideHScroll", "lastNotes", "nativeFont", "useCharCount", "iconTheme", "iconColTree",
|
||||
"iconColDocs", "mainWinSize", "welcomeWinSize", "prefsWinSize", "mainPanePos",
|
||||
"viewPanePos", "outlinePanePos", "autoSaveProj", "autoSaveDoc", "emphLabels",
|
||||
"backupOnClose", "askBeforeBackup", "askBeforeExit", "textFont", "textWidth", "textMargin",
|
||||
"tabWidth", "cursorWidth", "focusWidth", "hideFocusFooter", "showFullPath", "autoSelect",
|
||||
"doJustify", "showTabsNSpaces", "showLineEndings", "showMultiSpaces", "doReplace",
|
||||
"doReplaceSQuote", "doReplaceDQuote", "doReplaceDash", "doReplaceDots", "autoScroll",
|
||||
"autoScrollPos", "scrollPastEnd", "dialogStyle", "allowOpenDial", "dialogLine",
|
||||
"narratorBreak", "narratorDialog", "altDialogOpen", "altDialogClose", "highlightEmph",
|
||||
"stopWhenIdle", "userIdleTime", "incNotesWCount", "fmtApostrophe", "fmtSQuoteOpen",
|
||||
"fmtSQuoteClose", "fmtDQuoteOpen", "fmtDQuoteClose", "fmtPadBefore", "fmtPadAfter",
|
||||
"fmtPadThin", "spellLanguage", "showViewerPanel", "showEditToolBar", "showSessionTime",
|
||||
"viewComments", "viewSynopsis", "searchCase", "searchWord", "searchRegEx", "searchLoop",
|
||||
"searchNextFile", "searchMatchCap", "searchProjCase", "searchProjWord", "searchProjRegEx",
|
||||
"verQtString", "verQtValue", "verPyQtString", "verPyQtValue", "verPyString", "osType",
|
||||
"osLinux", "osWindows", "osDarwin", "osUnknown", "hostName", "kernelVer", "isDebug",
|
||||
"memInfo", "hasEnchant",
|
||||
"_appPath", "_appRoot", "_backPath", "_backupPath", "_confPath", "_dLocale", "_dShortDate",
|
||||
"_dShortDateTime", "_dataPath", "_errData", "_hasError", "_homePath", "_manuals",
|
||||
"_nwLangPath", "_qLocale", "_qtLangPath", "_qtTrans", "_recentPaths", "_recentProjects",
|
||||
"allowOpenDial", "altDialogClose", "altDialogOpen", "appHandle", "appName",
|
||||
"askBeforeBackup", "askBeforeExit", "autoSaveDoc", "autoSaveProj", "autoScroll",
|
||||
"autoScrollPos", "autoSelect", "backupOnClose", "cursorWidth", "dialogLine", "dialogStyle",
|
||||
"doJustify", "doReplace", "doReplaceDQuote", "doReplaceDash", "doReplaceDots",
|
||||
"doReplaceSQuote", "emphLabels", "fmtApostrophe", "fmtDQuoteClose", "fmtDQuoteOpen",
|
||||
"fmtPadAfter", "fmtPadBefore", "fmtPadThin", "fmtSQuoteClose", "fmtSQuoteOpen",
|
||||
"focusWidth", "guiFont", "guiLocale", "guiSyntax", "guiTheme", "hasEnchant",
|
||||
"hideFocusFooter", "hideHScroll", "hideVScroll", "highlightEmph", "hostName",
|
||||
"iconColDocs", "iconColTree", "iconTheme", "incNotesWCount", "isDebug", "kernelVer",
|
||||
"lastNotes", "mainPanePos", "mainWinSize", "memInfo", "narratorBreak", "narratorDialog",
|
||||
"nativeFont", "osDarwin", "osLinux", "osType", "osUnknown", "osWindows", "outlinePanePos",
|
||||
"prefsWinSize", "scrollPastEnd", "searchCase", "searchLoop", "searchMatchCap",
|
||||
"searchNextFile", "searchProjCase", "searchProjRegEx", "searchProjWord", "searchRegEx",
|
||||
"searchWord", "showEditToolBar", "showFullPath", "showLineEndings", "showMultiSpaces",
|
||||
"showSessionTime", "showTabsNSpaces", "showViewerPanel", "spellLanguage", "stopWhenIdle",
|
||||
"tabWidth", "textFont", "textMargin", "textWidth", "useCharCount", "userIdleTime",
|
||||
"verPyQtString", "verPyQtValue", "verPyString", "verQtString", "verQtValue",
|
||||
"viewComments", "viewPanePos", "viewSynopsis", "welcomeWinSize",
|
||||
)
|
||||
|
||||
LANG_NW = 1
|
||||
@@ -306,6 +305,10 @@ class Config:
|
||||
def pdfDocs(self) -> Path | None:
|
||||
return self._manuals.get(f"manual_{self.locale.name()}", self._manuals.get("manual"))
|
||||
|
||||
@property
|
||||
def nwLangPath(self) -> Path:
|
||||
return self._nwLangPath
|
||||
|
||||
@property
|
||||
def locale(self) -> QLocale:
|
||||
return self._dLocale
|
||||
@@ -918,7 +921,7 @@ class RecentProjects:
|
||||
|
||||
class RecentPaths:
|
||||
|
||||
KEYS = ["default", "project", "import", "outline", "stats"]
|
||||
KEYS: Final[list[str]] = ["default", "project", "import", "outline", "stats"]
|
||||
|
||||
def __init__(self, config: Config) -> None:
|
||||
self._conf = config
|
||||
|
||||
+37
-35
@@ -23,6 +23,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Final
|
||||
|
||||
from PyQt6.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
|
||||
|
||||
from novelwriter.enum import (
|
||||
@@ -99,7 +101,7 @@ class nwShortcode:
|
||||
FOOTNOTE_B = "[footnote:"
|
||||
FIELD_B = "[field:"
|
||||
|
||||
COMMENT_STYLES = {
|
||||
COMMENT_STYLES: Final[dict[nwComment, str]] = {
|
||||
nwComment.FOOTNOTE: "[footnote:{0}]",
|
||||
nwComment.COMMENT: "[comment:{0}]",
|
||||
}
|
||||
@@ -110,13 +112,13 @@ class nwShortcode:
|
||||
class nwStyles:
|
||||
|
||||
H_VALID = ("H0", "H1", "H2", "H3", "H4")
|
||||
H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
|
||||
H_SIZES = {0: 2.50, 1: 2.00, 2: 1.75, 3: 1.50, 4: 1.25}
|
||||
H_LEVEL: Final[dict[str, int]] = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
|
||||
H_SIZES: Final[dict[int, float]] = {0: 2.50, 1: 2.00, 2: 1.75, 3: 1.50, 4: 1.25}
|
||||
|
||||
T_NORMAL = 1.0
|
||||
T_SMALL = 0.8
|
||||
|
||||
T_LABEL = {
|
||||
T_LABEL: Final[dict[str, str]] = {
|
||||
"H0": QT_TRANSLATE_NOOP("Constant", "Title"),
|
||||
"H1": QT_TRANSLATE_NOOP("Constant", "Heading 1 (Partition)"),
|
||||
"H2": QT_TRANSLATE_NOOP("Constant", "Heading 2 (Chapter)"),
|
||||
@@ -125,7 +127,7 @@ class nwStyles:
|
||||
"TT": QT_TRANSLATE_NOOP("Constant", "Text Paragraph"),
|
||||
"SP": QT_TRANSLATE_NOOP("Constant", "Scene Separator"),
|
||||
}
|
||||
T_MARGIN = {
|
||||
T_MARGIN: Final[dict[str, tuple[float, float]]] = {
|
||||
"H0": (1.50, 0.60), # Title margins (top, bottom)
|
||||
"H1": (1.50, 0.60), # Heading 1 margins (top, bottom)
|
||||
"H2": (1.50, 0.60), # Heading 2 margins (top, bottom)
|
||||
@@ -174,20 +176,20 @@ class nwKeyWords:
|
||||
MENTION_KEY = "@mention"
|
||||
|
||||
# Note: The order here affects the order of menu entries
|
||||
ALL_KEYS = [
|
||||
ALL_KEYS: Final[list[str]] = [
|
||||
TAG_KEY, POV_KEY, FOCUS_KEY, CHAR_KEY, PLOT_KEY, TIME_KEY, WORLD_KEY,
|
||||
OBJECT_KEY, ENTITY_KEY, CUSTOM_KEY, STORY_KEY, MENTION_KEY,
|
||||
]
|
||||
CAN_CREATE = [
|
||||
CAN_CREATE: Final[list[str]] = [
|
||||
POV_KEY, FOCUS_KEY, CHAR_KEY, PLOT_KEY, TIME_KEY, WORLD_KEY,
|
||||
OBJECT_KEY, ENTITY_KEY, CUSTOM_KEY,
|
||||
]
|
||||
|
||||
# Set of Valid Keys
|
||||
VALID_KEYS = set(ALL_KEYS)
|
||||
VALID_KEYS: Final[set[str]] = set(ALL_KEYS)
|
||||
|
||||
# Map from Keys to Item Class
|
||||
KEY_CLASS = {
|
||||
KEY_CLASS: Final[dict[str, nwItemClass]] = {
|
||||
POV_KEY: nwItemClass.CHARACTER,
|
||||
FOCUS_KEY: nwItemClass.CHARACTER,
|
||||
CHAR_KEY: nwItemClass.CHARACTER,
|
||||
@@ -203,7 +205,7 @@ class nwKeyWords:
|
||||
|
||||
class nwLists:
|
||||
|
||||
USER_CLASSES = [
|
||||
USER_CLASSES: Final[list[nwItemClass]] = [
|
||||
nwItemClass.CHARACTER,
|
||||
nwItemClass.PLOT,
|
||||
nwItemClass.WORLD,
|
||||
@@ -229,7 +231,7 @@ class nwStats:
|
||||
WORDS_TITLE = "titleWords"
|
||||
|
||||
# Note: The order here affects the order of menu entries
|
||||
ALL_FIELDS = [
|
||||
ALL_FIELDS: Final[list[str]] = [
|
||||
WORDS, WORDS_TEXT, WORDS_TITLE,
|
||||
CHARS, CHARS_TEXT, CHARS_TITLE,
|
||||
WCHARS_ALL, WCHARS_TEXT, WCHARS_TITLE,
|
||||
@@ -239,7 +241,7 @@ class nwStats:
|
||||
|
||||
class nwLabels:
|
||||
|
||||
CLASS_NAME = {
|
||||
CLASS_NAME: Final[dict[nwItemClass, str]] = {
|
||||
nwItemClass.NO_CLASS: QT_TRANSLATE_NOOP("Constant", "None"),
|
||||
nwItemClass.NOVEL: QT_TRANSLATE_NOOP("Constant", "Novel"),
|
||||
nwItemClass.PLOT: QT_TRANSLATE_NOOP("Constant", "Plot"),
|
||||
@@ -253,7 +255,7 @@ class nwLabels:
|
||||
nwItemClass.TEMPLATE: QT_TRANSLATE_NOOP("Constant", "Templates"),
|
||||
nwItemClass.TRASH: QT_TRANSLATE_NOOP("Constant", "Trash"),
|
||||
}
|
||||
CLASS_ICON = {
|
||||
CLASS_ICON: Final[dict[nwItemClass, str]] = {
|
||||
nwItemClass.NO_CLASS: "cls_none",
|
||||
nwItemClass.NOVEL: "cls_novel",
|
||||
nwItemClass.PLOT: "cls_plot",
|
||||
@@ -267,12 +269,12 @@ class nwLabels:
|
||||
nwItemClass.TEMPLATE: "cls_template",
|
||||
nwItemClass.TRASH: "cls_trash",
|
||||
}
|
||||
LAYOUT_NAME = {
|
||||
LAYOUT_NAME: Final[dict[nwItemLayout, str]] = {
|
||||
nwItemLayout.NO_LAYOUT: QT_TRANSLATE_NOOP("Constant", "None"),
|
||||
nwItemLayout.DOCUMENT: QT_TRANSLATE_NOOP("Constant", "Novel Document"),
|
||||
nwItemLayout.NOTE: QT_TRANSLATE_NOOP("Constant", "Project Note"),
|
||||
}
|
||||
ITEM_DESCRIPTION = {
|
||||
ITEM_DESCRIPTION: Final[dict[str, str]] = {
|
||||
"none": QT_TRANSLATE_NOOP("Constant", "None"),
|
||||
"root": QT_TRANSLATE_NOOP("Constant", "Root Folder"),
|
||||
"folder": QT_TRANSLATE_NOOP("Constant", "Folder"),
|
||||
@@ -283,11 +285,11 @@ class nwLabels:
|
||||
"doc_h4": QT_TRANSLATE_NOOP("Constant", "Novel Section"),
|
||||
"note": QT_TRANSLATE_NOOP("Constant", "Project Note"),
|
||||
}
|
||||
ACTIVE_NAME = {
|
||||
ACTIVE_NAME: Final[dict[str, str]] = {
|
||||
"checked": QT_TRANSLATE_NOOP("Constant", "Active"),
|
||||
"unchecked": QT_TRANSLATE_NOOP("Constant", "Inactive"),
|
||||
}
|
||||
KEY_NAME = {
|
||||
KEY_NAME: Final[dict[str, str]] = {
|
||||
nwKeyWords.TAG_KEY: QT_TRANSLATE_NOOP("Constant", "Tag"),
|
||||
nwKeyWords.POV_KEY: QT_TRANSLATE_NOOP("Constant", "Point of View"),
|
||||
nwKeyWords.FOCUS_KEY: QT_TRANSLATE_NOOP("Constant", "Focus"),
|
||||
@@ -301,7 +303,7 @@ class nwLabels:
|
||||
nwKeyWords.STORY_KEY: QT_TRANSLATE_NOOP("Constant", "Story"),
|
||||
nwKeyWords.MENTION_KEY: QT_TRANSLATE_NOOP("Constant", "Mentions"),
|
||||
}
|
||||
KEY_SHORTCUT = {
|
||||
KEY_SHORTCUT: Final[dict[str, str]] = {
|
||||
nwKeyWords.TAG_KEY: "Ctrl+K, G",
|
||||
nwKeyWords.POV_KEY: "Ctrl+K, V",
|
||||
nwKeyWords.FOCUS_KEY: "Ctrl+K, F",
|
||||
@@ -315,7 +317,7 @@ class nwLabels:
|
||||
nwKeyWords.STORY_KEY: "Ctrl+K, N",
|
||||
nwKeyWords.MENTION_KEY: "Ctrl+K, M",
|
||||
}
|
||||
OUTLINE_COLS = {
|
||||
OUTLINE_COLS: Final[dict[nwOutline, str]] = {
|
||||
nwOutline.TITLE: QT_TRANSLATE_NOOP("Constant", "Title"),
|
||||
nwOutline.LEVEL: QT_TRANSLATE_NOOP("Constant", "Level"),
|
||||
nwOutline.LABEL: QT_TRANSLATE_NOOP("Constant", "Document"),
|
||||
@@ -337,7 +339,7 @@ class nwLabels:
|
||||
nwOutline.MENTION: KEY_NAME[nwKeyWords.MENTION_KEY],
|
||||
nwOutline.SYNOP: QT_TRANSLATE_NOOP("Constant", "Synopsis"),
|
||||
}
|
||||
STATS_NAME = {
|
||||
STATS_NAME: Final[dict[str, str]] = {
|
||||
nwStats.CHARS: QT_TRANSLATE_NOOP("Stats", "Characters"),
|
||||
nwStats.CHARS_TEXT: QT_TRANSLATE_NOOP("Stats", "Characters in Text"),
|
||||
nwStats.CHARS_TITLE: QT_TRANSLATE_NOOP("Stats", "Characters in Headings"),
|
||||
@@ -350,7 +352,7 @@ class nwLabels:
|
||||
nwStats.WORDS_TEXT: QT_TRANSLATE_NOOP("Stats", "Words in Text"),
|
||||
nwStats.WORDS_TITLE: QT_TRANSLATE_NOOP("Stats", "Words in Headings"),
|
||||
}
|
||||
BUILD_FMT = {
|
||||
BUILD_FMT: Final[dict[nwBuildFmt, str]] = {
|
||||
nwBuildFmt.ODT: QT_TRANSLATE_NOOP("Constant", "Open Document (.odt)"),
|
||||
nwBuildFmt.FODT: QT_TRANSLATE_NOOP("Constant", "Flat Open Document (.fodt)"),
|
||||
nwBuildFmt.DOCX: QT_TRANSLATE_NOOP("Constant", "Microsoft Word Document (.docx)"),
|
||||
@@ -362,7 +364,7 @@ class nwLabels:
|
||||
nwBuildFmt.J_HTML: QT_TRANSLATE_NOOP("Constant", "JSON + HTML 5 (.json)"),
|
||||
nwBuildFmt.J_NWD: QT_TRANSLATE_NOOP("Constant", "JSON + novelWriter Markup (.json)"),
|
||||
}
|
||||
BUILD_EXT = {
|
||||
BUILD_EXT: Final[dict[nwBuildFmt, str]] = {
|
||||
nwBuildFmt.ODT: ".odt",
|
||||
nwBuildFmt.FODT: ".fodt",
|
||||
nwBuildFmt.DOCX: ".docx",
|
||||
@@ -374,7 +376,7 @@ class nwLabels:
|
||||
nwBuildFmt.J_HTML: ".json",
|
||||
nwBuildFmt.J_NWD: ".json",
|
||||
}
|
||||
SHAPES_PLAIN = {
|
||||
SHAPES_PLAIN: Final[dict[nwStatusShape, str]] = {
|
||||
nwStatusShape.SQUARE: QT_TRANSLATE_NOOP("Constant", "Square"),
|
||||
nwStatusShape.TRIANGLE: QT_TRANSLATE_NOOP("Constant", "Triangle"),
|
||||
nwStatusShape.NABLA: QT_TRANSLATE_NOOP("Constant", "Nabla"),
|
||||
@@ -384,42 +386,42 @@ class nwLabels:
|
||||
nwStatusShape.STAR: QT_TRANSLATE_NOOP("Constant", "Star"),
|
||||
nwStatusShape.PACMAN: QT_TRANSLATE_NOOP("Constant", "Pacman"),
|
||||
}
|
||||
SHAPES_CIRCLE = {
|
||||
SHAPES_CIRCLE: Final[dict[nwStatusShape, str]] = {
|
||||
nwStatusShape.CIRCLE_Q: QT_TRANSLATE_NOOP("Constant", "1/4 Circle"),
|
||||
nwStatusShape.CIRCLE_H: QT_TRANSLATE_NOOP("Constant", "Half Circle"),
|
||||
nwStatusShape.CIRCLE_T: QT_TRANSLATE_NOOP("Constant", "3/4 Circle"),
|
||||
nwStatusShape.CIRCLE: QT_TRANSLATE_NOOP("Constant", "Full Circle"),
|
||||
}
|
||||
SHAPES_BARS = {
|
||||
SHAPES_BARS: Final[dict[nwStatusShape, str]] = {
|
||||
nwStatusShape.BARS_1: QT_TRANSLATE_NOOP("Constant", "1 Bar"),
|
||||
nwStatusShape.BARS_2: QT_TRANSLATE_NOOP("Constant", "2 Bars"),
|
||||
nwStatusShape.BARS_3: QT_TRANSLATE_NOOP("Constant", "3 Bars"),
|
||||
nwStatusShape.BARS_4: QT_TRANSLATE_NOOP("Constant", "4 Bars"),
|
||||
}
|
||||
SHAPES_BLOCKS = {
|
||||
SHAPES_BLOCKS: Final[dict[nwStatusShape, str]] = {
|
||||
nwStatusShape.BLOCK_1: QT_TRANSLATE_NOOP("Constant", "1 Block"),
|
||||
nwStatusShape.BLOCK_2: QT_TRANSLATE_NOOP("Constant", "2 Blocks"),
|
||||
nwStatusShape.BLOCK_3: QT_TRANSLATE_NOOP("Constant", "3 Blocks"),
|
||||
nwStatusShape.BLOCK_4: QT_TRANSLATE_NOOP("Constant", "4 Blocks"),
|
||||
}
|
||||
FILE_FILTERS = {
|
||||
FILE_FILTERS: Final[dict[str, str]] = {
|
||||
"*.txt": QT_TRANSLATE_NOOP("Constant", "Text files"),
|
||||
"*.md": QT_TRANSLATE_NOOP("Constant", "Markdown files"),
|
||||
"*.nwd": QT_TRANSLATE_NOOP("Constant", "novelWriter files"),
|
||||
"*.csv": QT_TRANSLATE_NOOP("Constant", "CSV files"),
|
||||
"*": QT_TRANSLATE_NOOP("Constant", "All files"),
|
||||
}
|
||||
UNIT_NAME = {
|
||||
UNIT_NAME: Final[dict[str, str]] = {
|
||||
"mm": QT_TRANSLATE_NOOP("Constant", "Millimetres"),
|
||||
"cm": QT_TRANSLATE_NOOP("Constant", "Centimetres"),
|
||||
"in": QT_TRANSLATE_NOOP("Constant", "Inches"),
|
||||
}
|
||||
UNIT_SCALE = {
|
||||
UNIT_SCALE: Final[dict[str, float]] = {
|
||||
"mm": 1.0,
|
||||
"cm": 10.0,
|
||||
"in": 25.4,
|
||||
}
|
||||
PAPER_NAME = {
|
||||
PAPER_NAME: Final[dict[str, str]] = {
|
||||
"A4": QT_TRANSLATE_NOOP("Constant", "A4"),
|
||||
"A5": QT_TRANSLATE_NOOP("Constant", "A5"),
|
||||
"A6": QT_TRANSLATE_NOOP("Constant", "A6"),
|
||||
@@ -427,7 +429,7 @@ class nwLabels:
|
||||
"Letter": QT_TRANSLATE_NOOP("Constant", "US Letter"),
|
||||
"Custom": QT_TRANSLATE_NOOP("Constant", "Custom"),
|
||||
}
|
||||
PAPER_SIZE = {
|
||||
PAPER_SIZE: Final[dict[str, tuple[float, float]]] = {
|
||||
"A4": (210.0, 297.0),
|
||||
"A5": (148.0, 210.0),
|
||||
"A6": (105.0, 148.0),
|
||||
@@ -435,7 +437,7 @@ class nwLabels:
|
||||
"Letter": (215.9, 279.4),
|
||||
"Custom": (-1.0, -1.0),
|
||||
}
|
||||
THEME_COLORS = {
|
||||
THEME_COLORS: Final[dict[str, str]] = {
|
||||
"theme": QT_TRANSLATE_NOOP("Constant", "Theme Colours"),
|
||||
"default": QT_TRANSLATE_NOOP("Constant", "Foreground Colour"),
|
||||
"faded": QT_TRANSLATE_NOOP("Constant", "Faded Colour"),
|
||||
@@ -462,7 +464,7 @@ class nwHeadFmt:
|
||||
CHAR_POV = "{Char:POV}"
|
||||
CHAR_FOCUS = "{Char:Focus}"
|
||||
|
||||
PAGE_HEADERS = [
|
||||
PAGE_HEADERS: Final[list[str]] = [
|
||||
TITLE, CH_NUM, CH_WORD, CH_ROMU, CH_ROML, SC_NUM, SC_ABS,
|
||||
CHAR_POV, CHAR_FOCUS
|
||||
]
|
||||
@@ -478,7 +480,7 @@ class nwQuotes:
|
||||
"""Allowed quotation marks.
|
||||
Source: https://en.wikipedia.org/wiki/Quotation_mark
|
||||
"""
|
||||
SYMBOLS = {
|
||||
SYMBOLS: Final[dict[str, str]] = {
|
||||
"\u0027": QT_TRANSLATE_NOOP("Constant", "Straight single quotation mark"),
|
||||
"\u0022": QT_TRANSLATE_NOOP("Constant", "Straight double quotation mark"),
|
||||
|
||||
@@ -645,7 +647,7 @@ class nwUnicode:
|
||||
|
||||
class nwHtmlUnicode:
|
||||
|
||||
U_TO_H = {
|
||||
U_TO_H: Final[dict[str, str]] = {
|
||||
# Quotes
|
||||
nwUnicode.U_QUOT: nwUnicode.H_QUOT,
|
||||
nwUnicode.U_APOS: nwUnicode.H_APOS,
|
||||
|
||||
@@ -28,9 +28,9 @@ import json
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
from collections.abc import Iterable
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
|
||||
|
||||
@@ -41,6 +41,9 @@ from novelwriter.core.project import NWProject
|
||||
from novelwriter.enum import nwBuildFmt
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterable
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
T_BuildValue = str | int | float | bool
|
||||
@@ -227,9 +230,9 @@ class BuildSettings:
|
||||
@classmethod
|
||||
def fromDict(cls, data: dict) -> BuildSettings:
|
||||
"""Create a build settings object from a dict."""
|
||||
cls = BuildSettings()
|
||||
cls.unpack(data)
|
||||
return cls
|
||||
new = cls()
|
||||
new.unpack(data)
|
||||
return new
|
||||
|
||||
##
|
||||
# Properties
|
||||
@@ -514,11 +517,11 @@ class BuildSettings:
|
||||
@classmethod
|
||||
def duplicate(cls, source: BuildSettings) -> BuildSettings:
|
||||
"""Make a copy of another build."""
|
||||
cls = BuildSettings()
|
||||
cls.unpack(source.pack())
|
||||
cls._uuid = str(uuid.uuid4())
|
||||
cls._name = f"{source.name} 2"
|
||||
return cls
|
||||
new = cls()
|
||||
new.unpack(source.pack())
|
||||
new._uuid = str(uuid.uuid4())
|
||||
new._name = f"{source.name} 2"
|
||||
return new
|
||||
|
||||
|
||||
class BuildCollection:
|
||||
|
||||
@@ -30,9 +30,9 @@ import logging
|
||||
import re
|
||||
import shutil
|
||||
|
||||
from collections.abc import Iterable
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
from zipfile import ZipFile, is_zipfile
|
||||
|
||||
from PyQt6.QtCore import QCoreApplication
|
||||
@@ -40,10 +40,14 @@ from PyQt6.QtCore import QCoreApplication
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.common import isHandle, minmax, simplified
|
||||
from novelwriter.constants import nwConst, nwFiles, nwItemClass, nwStats
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.storage import NWStorageCreate
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterable
|
||||
|
||||
from novelwriter.core.item import NWItem
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -284,7 +288,7 @@ class DocDuplicator:
|
||||
class DocSearch:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._regEx = re.compile("")
|
||||
self._regEx = re.compile(r"")
|
||||
self._opts = re.UNICODE | re.IGNORECASE
|
||||
self._words = False
|
||||
self._escape = True
|
||||
@@ -381,7 +385,7 @@ class ProjectBuilder:
|
||||
path = data.get("path", None) or None
|
||||
if isinstance(path, str | Path):
|
||||
self._path = Path(path).resolve()
|
||||
if data.get("sample", False):
|
||||
if data.get("sample"):
|
||||
return self._extractSampleProject(self._path)
|
||||
elif data.get("template"):
|
||||
return self._copyProject(self._path, data)
|
||||
|
||||
@@ -25,26 +25,30 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from collections.abc import Iterable
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtGui import QFont
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.constants import nwLabels
|
||||
from novelwriter.core.buildsettings import BuildSettings
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.enum import nwBuildFmt
|
||||
from novelwriter.error import formatException, logException
|
||||
from novelwriter.formats.todocx import ToDocX
|
||||
from novelwriter.formats.tohtml import ToHtml
|
||||
from novelwriter.formats.tokenizer import Tokenizer
|
||||
from novelwriter.formats.tomarkdown import ToMarkdown
|
||||
from novelwriter.formats.toodt import ToOdt
|
||||
from novelwriter.formats.toqdoc import ToQTextDocument
|
||||
from novelwriter.formats.toraw import ToRaw
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterable
|
||||
from pathlib import Path
|
||||
|
||||
from novelwriter.core.buildsettings import BuildSettings
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.formats.tokenizer import Tokenizer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -56,8 +60,8 @@ class NWBuildDocument:
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_project", "_build", "_queue", "_error", "_cache", "_count",
|
||||
"_outline",
|
||||
"_build", "_cache", "_count", "_error", "_outline", "_project",
|
||||
"_queue",
|
||||
)
|
||||
|
||||
def __init__(self, project: NWProject, build: BuildSettings) -> None:
|
||||
|
||||
@@ -31,11 +31,11 @@ from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from novelwriter.common import formatTimeStamp, isHandle
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout
|
||||
from novelwriter.error import formatException, logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -29,7 +29,6 @@ import json
|
||||
import logging
|
||||
import random
|
||||
|
||||
from collections.abc import ItemsView, Iterable
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
@@ -44,7 +43,9 @@ from novelwriter.error import logException
|
||||
from novelwriter.text.comments import processComment
|
||||
from novelwriter.text.counting import standardCounter
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import ItemsView, Iterable
|
||||
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
@@ -906,7 +907,7 @@ class ItemIndex:
|
||||
IndexHeading object for each heading of the text.
|
||||
"""
|
||||
|
||||
__slots__ = ("_project", "_tags", "_items")
|
||||
__slots__ = ("_items", "_project", "_tags")
|
||||
|
||||
def __init__(self, project: NWProject, tagsIndex: TagsIndex) -> None:
|
||||
self._project = project
|
||||
|
||||
@@ -28,14 +28,15 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from collections.abc import ItemsView, Sequence
|
||||
from typing import TYPE_CHECKING, Literal
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.common import checkInt, isListInstance, isTitleTag
|
||||
from novelwriter.constants import nwKeyWords, nwStyles
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import ItemsView, Sequence
|
||||
|
||||
from novelwriter.core.index import TagsIndex
|
||||
from novelwriter.core.item import NWItem
|
||||
|
||||
@@ -57,7 +58,7 @@ class IndexNode:
|
||||
must be reset each time the item is re-indexed.
|
||||
"""
|
||||
|
||||
__slots__ = ("_tags", "_handle", "_item", "_headings", "_notes", "_count")
|
||||
__slots__ = ("_count", "_handle", "_headings", "_item", "_notes", "_tags")
|
||||
|
||||
def __init__(self, tagsIndex: TagsIndex, tHandle: str, nwItem: NWItem) -> None:
|
||||
self._tags = tagsIndex
|
||||
@@ -205,8 +206,8 @@ class IndexHeading:
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_tags", "_key", "_line", "_level", "_title",
|
||||
"_counts", "_tag", "_refs", "_comments",
|
||||
"_comments", "_counts", "_key", "_level", "_line", "_refs", "_tag",
|
||||
"_tags", "_title",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
|
||||
+26
-26
@@ -27,8 +27,6 @@ import logging
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from PyQt6.QtGui import QFont, QIcon
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.common import (
|
||||
checkInt, isHandle, isItemClass, isItemLayout, isItemType, simplified,
|
||||
@@ -37,7 +35,9 @@ from novelwriter.common import (
|
||||
from novelwriter.constants import nwLabels, nwStyles, trConst
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from PyQt6.QtGui import QFont, QIcon
|
||||
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -53,10 +53,10 @@ class NWItem:
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_project", "_name", "_handle", "_parent", "_root", "_order",
|
||||
"_type", "_class", "_layout", "_status", "_import", "_active",
|
||||
"_expanded", "_heading", "_charCount", "_wordCount",
|
||||
"_paraCount", "_cursorPos", "_initCount",
|
||||
"_active", "_charCount", "_class", "_cursorPos", "_expanded",
|
||||
"_handle", "_heading", "_import", "_initCount", "_layout", "_name",
|
||||
"_order", "_paraCount", "_parent", "_project", "_root", "_status",
|
||||
"_type", "_wordCount",
|
||||
)
|
||||
|
||||
def __init__(self, project: NWProject, handle: str) -> None:
|
||||
@@ -264,25 +264,25 @@ class NWItem:
|
||||
@classmethod
|
||||
def duplicate(cls, source: NWItem, handle: str) -> NWItem:
|
||||
"""Make a copy of an item."""
|
||||
cls = NWItem(source._project, handle)
|
||||
cls._name = source._name
|
||||
cls._parent = source._parent
|
||||
cls._root = source._root
|
||||
cls._order = source._order
|
||||
cls._type = source._type
|
||||
cls._class = source._class
|
||||
cls._layout = source._layout
|
||||
cls._status = source._status
|
||||
cls._import = source._import
|
||||
cls._active = source._active
|
||||
cls._expanded = source._expanded
|
||||
cls._heading = source._heading
|
||||
cls._charCount = source._charCount
|
||||
cls._wordCount = source._wordCount
|
||||
cls._paraCount = source._paraCount
|
||||
cls._cursorPos = source._cursorPos
|
||||
cls._initCount = source._initCount
|
||||
return cls
|
||||
new = cls(source._project, handle)
|
||||
new._name = source._name
|
||||
new._parent = source._parent
|
||||
new._root = source._root
|
||||
new._order = source._order
|
||||
new._type = source._type
|
||||
new._class = source._class
|
||||
new._layout = source._layout
|
||||
new._status = source._status
|
||||
new._import = source._import
|
||||
new._active = source._active
|
||||
new._expanded = source._expanded
|
||||
new._heading = source._heading
|
||||
new._charCount = source._charCount
|
||||
new._wordCount = source._wordCount
|
||||
new._paraCount = source._paraCount
|
||||
new._cursorPos = source._cursorPos
|
||||
new._initCount = source._initCount
|
||||
return new
|
||||
|
||||
##
|
||||
# Action Methods
|
||||
|
||||
@@ -37,7 +37,7 @@ from novelwriter.core.item import NWItem
|
||||
from novelwriter.enum import nwItemClass
|
||||
from novelwriter.types import QtAlignRight
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.core.tree import NWTree
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -89,7 +89,7 @@ class ProjectNode:
|
||||
C_ACTIVE = 2
|
||||
C_STATUS = 3
|
||||
|
||||
__slots__ = ("_item", "_children", "_parent", "_row", "_cache", "_flags", "_count")
|
||||
__slots__ = ("_cache", "_children", "_count", "_flags", "_item", "_parent", "_row")
|
||||
|
||||
def __init__(self, item: NWItem) -> None:
|
||||
self._item = item
|
||||
@@ -162,7 +162,7 @@ class ProjectNode:
|
||||
|
||||
def updateCount(self, propagate: bool = True) -> None:
|
||||
"""Update counts, and propagate upwards in the tree."""
|
||||
self._count = self._item.wordCount + sum(c._count for c in self._children)
|
||||
self._count = self._item.wordCount + sum(c._count for c in self._children) # noqa: SLF001
|
||||
self._cache[C_COUNT_TEXT] = f"{self._count:n}"
|
||||
if propagate and (parent := self._parent):
|
||||
parent.updateCount()
|
||||
@@ -257,13 +257,13 @@ class ProjectNode:
|
||||
"""Recursively add all nodes to a list."""
|
||||
for node in self._children:
|
||||
children.append(node)
|
||||
node._recursiveAppendChildren(children)
|
||||
node._recursiveAppendChildren(children) # noqa: SLF001
|
||||
return
|
||||
|
||||
def _refreshChildrenPos(self) -> None:
|
||||
"""Update the row value on all children."""
|
||||
for n, child in enumerate(self._children):
|
||||
child._row = n
|
||||
child._row = n # noqa: SLF001
|
||||
child.item.setOrder(n)
|
||||
return
|
||||
|
||||
@@ -290,12 +290,12 @@ class ProjectModel(QAbstractItemModel):
|
||||
methods needed primarily by the project tree GUI component.
|
||||
"""
|
||||
|
||||
__slots__ = ("_tree", "_root")
|
||||
__slots__ = ("_root", "_tree")
|
||||
|
||||
def __init__(self, tree: NWTree) -> None:
|
||||
super().__init__()
|
||||
self._tree = tree
|
||||
self._root = ProjectNode(NWItem(tree._project, INV_ROOT))
|
||||
self._root = ProjectNode(NWItem(tree.project, INV_ROOT))
|
||||
self._root.item.setName("Invisible Root")
|
||||
logger.debug("Ready: ProjectModel")
|
||||
return
|
||||
@@ -391,10 +391,10 @@ class ProjectModel(QAbstractItemModel):
|
||||
) -> bool:
|
||||
"""Process mime data drop."""
|
||||
if self.canDropMimeData(data, action, row, column, parent):
|
||||
items = []
|
||||
for handle in decodeMimeHandles(data):
|
||||
if (index := self.indexFromHandle(handle)).isValid():
|
||||
items.append(index)
|
||||
items = [
|
||||
index for handle in decodeMimeHandles(data)
|
||||
if (index := self.indexFromHandle(handle)).isValid()
|
||||
]
|
||||
self.multiMove(items, parent, row)
|
||||
return True
|
||||
return False
|
||||
@@ -490,7 +490,7 @@ class ProjectModel(QAbstractItemModel):
|
||||
if temp := self.removeChild(index.parent(), index.row()):
|
||||
self.insertChild(temp, target, pos)
|
||||
for child in reversed(node.allChildren()):
|
||||
node._updateRelationships(child)
|
||||
node._updateRelationships(child) # noqa: SLF001
|
||||
child.item.notifyToRefresh()
|
||||
node.item.notifyToRefresh()
|
||||
return
|
||||
@@ -501,16 +501,15 @@ class ProjectModel(QAbstractItemModel):
|
||||
|
||||
def clear(self) -> None:
|
||||
"""Clear the project model."""
|
||||
self._root._children.clear()
|
||||
self._root.children.clear()
|
||||
return
|
||||
|
||||
def allExpanded(self) -> list[QModelIndex]:
|
||||
"""Return a list of all expanded items."""
|
||||
expanded = []
|
||||
for node in self._root.allChildren():
|
||||
if node._item.isExpanded:
|
||||
expanded.append(self.createIndex(node.row(), 0, node))
|
||||
return expanded
|
||||
return [
|
||||
self.createIndex(node.row(), 0, node) for node in self._root.allChildren()
|
||||
if node.item.isExpanded
|
||||
]
|
||||
|
||||
def trashSelection(self, indices: list[QModelIndex]) -> bool:
|
||||
"""Check if a selection of indices are all in trash or not."""
|
||||
|
||||
@@ -25,15 +25,19 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import QAbstractTableModel, QModelIndex, Qt
|
||||
from PyQt6.QtGui import QIcon, QPixmap
|
||||
|
||||
from novelwriter import SHARED
|
||||
from novelwriter.constants import nwKeyWords, nwLabels, nwStyles, trConst
|
||||
from novelwriter.core.indexdata import IndexHeading, IndexNode
|
||||
from novelwriter.enum import nwNovelExtra
|
||||
from novelwriter.types import QtAlignRight
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.core.indexdata import IndexHeading, IndexNode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
C_FACTOR = 0x0100
|
||||
@@ -50,7 +54,7 @@ T_NodeData = str | QIcon | QPixmap | Qt.AlignmentFlag | None
|
||||
|
||||
class NovelModel(QAbstractTableModel):
|
||||
|
||||
__slots__ = ("_rows", "_more", "_columns", "_extraKey", "_extraLabel")
|
||||
__slots__ = ("_columns", "_extraKey", "_extraLabel", "_more", "_rows")
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
@@ -35,7 +35,7 @@ from novelwriter.common import checkBool, checkFloat, checkInt, checkString, jso
|
||||
from novelwriter.constants import nwFiles
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -30,6 +30,7 @@ from enum import Enum
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import QCoreApplication
|
||||
|
||||
@@ -44,12 +45,14 @@ from novelwriter.core.options import OptionState
|
||||
from novelwriter.core.projectdata import NWProjectData
|
||||
from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLReadState
|
||||
from novelwriter.core.sessions import NWSessionLog
|
||||
from novelwriter.core.status import T_StatusKind, T_UpdateEntry
|
||||
from novelwriter.core.storage import NWStorage, NWStorageOpen
|
||||
from novelwriter.core.tree import NWTree
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.core.status import T_StatusKind, T_UpdateEntry
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -64,8 +67,8 @@ class NWProjectState(Enum):
|
||||
class NWProject:
|
||||
|
||||
__slots__ = (
|
||||
"_options", "_storage", "_data", "_tree", "_index", "_session",
|
||||
"_langData", "_changed", "_valid", "_state", "tr",
|
||||
"_changed", "_data", "_index", "_langData", "_options", "_session",
|
||||
"_state", "_storage", "_tree", "_valid", "tr",
|
||||
)
|
||||
|
||||
def __init__(self) -> None:
|
||||
@@ -557,13 +560,13 @@ class NWProject:
|
||||
|
||||
def _loadProjectLocalisation(self) -> bool:
|
||||
"""Load the language data for the current project language."""
|
||||
if self._data.language is None or CONFIG._nwLangPath is None:
|
||||
if self._data.language is None or CONFIG.nwLangPath is None:
|
||||
self._langData = {}
|
||||
return False
|
||||
|
||||
langFile = Path(CONFIG._nwLangPath) / f"project_{self._data.language}.json"
|
||||
langFile = Path(CONFIG.nwLangPath) / f"project_{self._data.language}.json"
|
||||
if not langFile.is_file():
|
||||
langFile = Path(CONFIG._nwLangPath) / "project_en_GB.json"
|
||||
langFile = Path(CONFIG.nwLangPath) / "project_en_GB.json"
|
||||
|
||||
try:
|
||||
with open(langFile, mode="r", encoding="utf-8") as inFile:
|
||||
|
||||
@@ -34,7 +34,7 @@ from novelwriter.common import (
|
||||
)
|
||||
from novelwriter.core.status import NWStatus
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -39,7 +39,7 @@ from novelwriter.common import (
|
||||
hexToInt, simplified, xmlIndent, yesNo
|
||||
)
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.core.projectdata import NWProjectData
|
||||
from novelwriter.core.status import NWStatus
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
|
||||
from collections.abc import Iterable
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
@@ -35,7 +34,9 @@ from novelwriter.common import formatTimeStamp
|
||||
from novelwriter.constants import nwFiles
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterable
|
||||
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -27,7 +27,6 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
|
||||
from collections.abc import Iterator
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
@@ -36,7 +35,9 @@ from PyQt6.QtCore import QLocale
|
||||
from novelwriter.constants import nwFiles
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterator
|
||||
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -28,8 +28,7 @@ import dataclasses
|
||||
import logging
|
||||
import random
|
||||
|
||||
from collections.abc import Iterable
|
||||
from typing import Literal, TypeGuard
|
||||
from typing import TYPE_CHECKING, Literal, TypeGuard
|
||||
|
||||
from PyQt6.QtCore import QPointF, Qt
|
||||
from PyQt6.QtGui import QColor, QIcon, QPainter, QPainterPath, QPixmap, QPolygonF
|
||||
@@ -39,6 +38,9 @@ from novelwriter.common import simplified
|
||||
from novelwriter.enum import nwStatusShape
|
||||
from novelwriter.types import QtPaintAntiAlias, QtTransparent
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterable
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -54,10 +56,10 @@ class StatusEntry:
|
||||
@classmethod
|
||||
def duplicate(cls, source: StatusEntry) -> StatusEntry:
|
||||
"""Create a deep copy of the source object."""
|
||||
cls = dataclasses.replace(source)
|
||||
cls.color = QColor(source.color)
|
||||
cls.icon = QIcon(source.icon)
|
||||
return cls
|
||||
status = dataclasses.replace(source)
|
||||
status.color = QColor(source.color)
|
||||
status.icon = QIcon(source.icon)
|
||||
return status
|
||||
|
||||
|
||||
NO_ENTRY = StatusEntry("", QColor(0, 0, 0), nwStatusShape.SQUARE, QIcon(), 0)
|
||||
@@ -71,7 +73,7 @@ class NWStatus:
|
||||
STATUS = "s"
|
||||
IMPORT = "i"
|
||||
|
||||
__slots__ = ("_store", "_default", "_prefix", "_height")
|
||||
__slots__ = ("_default", "_height", "_prefix", "_store")
|
||||
|
||||
def __init__(self, prefix: T_StatusKind) -> None:
|
||||
self._store: dict[str, StatusEntry] = {}
|
||||
|
||||
@@ -40,7 +40,7 @@ from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter
|
||||
from novelwriter.core.spellcheck import UserDictionary
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -27,7 +27,6 @@ from __future__ import annotations
|
||||
import logging
|
||||
import random
|
||||
|
||||
from collections.abc import Iterable, Iterator
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Literal, overload
|
||||
|
||||
@@ -40,7 +39,9 @@ from novelwriter.core.itemmodel import ProjectModel, ProjectNode
|
||||
from novelwriter.enum import nwChange, nwItemClass, nwItemLayout, nwItemType
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterable, Iterator
|
||||
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -60,7 +61,7 @@ class NWTree:
|
||||
also used for file names.
|
||||
"""
|
||||
|
||||
__slots__ = ("_project", "_model", "_items", "_nodes", "_trash", "_ready")
|
||||
__slots__ = ("_items", "_model", "_nodes", "_project", "_ready", "_trash")
|
||||
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
self._project = project
|
||||
@@ -107,6 +108,11 @@ class NWTree:
|
||||
# Properties
|
||||
##
|
||||
|
||||
@property
|
||||
def project(self) -> NWProject:
|
||||
"""Return the parent project."""
|
||||
return self._project
|
||||
|
||||
@property
|
||||
def trash(self) -> ProjectNode | None:
|
||||
"""Return trash node, if it exists."""
|
||||
@@ -396,7 +402,7 @@ class NWTree:
|
||||
|
||||
def checkType(self, tHandle: str, itemType: nwItemType) -> bool:
|
||||
"""Check if item exists and is of the specified item type."""
|
||||
if tItem := self.__getitem__(tHandle):
|
||||
if tItem := self[tHandle]:
|
||||
return tItem.itemType == itemType
|
||||
return False
|
||||
|
||||
@@ -414,8 +420,7 @@ class NWTree:
|
||||
node = parent
|
||||
else:
|
||||
return path
|
||||
else:
|
||||
logger.error("Max project tree depth reached")
|
||||
logger.error("Max project tree depth reached")
|
||||
return path
|
||||
|
||||
def subTree(self, tHandle: str) -> list[str]:
|
||||
|
||||
@@ -25,7 +25,8 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from PyQt6.QtGui import QCloseEvent
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtWidgets import (
|
||||
QDialogButtonBox, QHBoxLayout, QLabel, QTextBrowser, QVBoxLayout, QWidget
|
||||
)
|
||||
@@ -37,6 +38,9 @@ from novelwriter.extensions.modified import NDialog
|
||||
from novelwriter.extensions.versioninfo import VersionInfoWidget
|
||||
from novelwriter.types import QtAlignRightTop, QtDialogClose, QtHexArgb
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from PyQt6.QtGui import QCloseEvent
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
@@ -131,11 +131,11 @@ class GuiDocMerge(NDialog):
|
||||
@classmethod
|
||||
def getData(cls, parent: QWidget, handle: str, items: list[str]) -> tuple[dict, bool]:
|
||||
"""Pop the dialog and return the result."""
|
||||
cls = GuiDocMerge(parent, handle, items)
|
||||
cls.exec()
|
||||
data = cls.data()
|
||||
accepted = cls.result() == QtAccepted
|
||||
cls.softDelete()
|
||||
dialog = cls(parent, handle, items)
|
||||
dialog.exec()
|
||||
data = dialog.data()
|
||||
accepted = dialog.result() == QtAccepted
|
||||
dialog.softDelete()
|
||||
return data, accepted
|
||||
|
||||
##
|
||||
|
||||
@@ -178,11 +178,11 @@ class GuiDocSplit(NDialog):
|
||||
@classmethod
|
||||
def getData(cls, parent: QWidget, handle: str) -> tuple[dict, list[str], bool]:
|
||||
"""Pop the dialog and return the result."""
|
||||
cls = GuiDocSplit(parent, handle)
|
||||
cls.exec()
|
||||
data, text = cls.data()
|
||||
accepted = cls.result() == QtAccepted
|
||||
cls.softDelete()
|
||||
dialog = cls(parent, handle)
|
||||
dialog.exec()
|
||||
data, text = dialog.data()
|
||||
accepted = dialog.result() == QtAccepted
|
||||
dialog.softDelete()
|
||||
return data, text, accepted
|
||||
|
||||
##
|
||||
|
||||
@@ -82,9 +82,9 @@ class GuiEditLabel(NDialog):
|
||||
@classmethod
|
||||
def getLabel(cls, parent: QWidget, text: str) -> tuple[str, bool]:
|
||||
"""Pop the dialog and return the result."""
|
||||
cls = GuiEditLabel(parent, text=text)
|
||||
cls.exec()
|
||||
label = cls.itemLabel
|
||||
accepted = cls.result() == QtAccepted
|
||||
cls.softDelete()
|
||||
dialog = cls(parent, text=text)
|
||||
dialog.exec()
|
||||
label = dialog.itemLabel
|
||||
accepted = dialog.result() == QtAccepted
|
||||
dialog.softDelete()
|
||||
return label, accepted
|
||||
|
||||
@@ -432,7 +432,7 @@ class GuiPreferences(NDialog):
|
||||
self.textWidth.setSingleStep(10)
|
||||
self.textWidth.setValue(CONFIG.textWidth)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Maximum text width in \"Normal Mode\""), self.textWidth,
|
||||
self.tr('Maximum text width in "Normal Mode"'), self.textWidth,
|
||||
self.tr("Set to 0 to disable this feature."), unit=self.tr("px")
|
||||
)
|
||||
|
||||
@@ -443,7 +443,7 @@ class GuiPreferences(NDialog):
|
||||
self.focusWidth.setSingleStep(10)
|
||||
self.focusWidth.setValue(CONFIG.focusWidth)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Maximum text width in \"Focus Mode\""), self.focusWidth,
|
||||
self.tr('Maximum text width in "Focus Mode"'), self.focusWidth,
|
||||
self.tr("The maximum width cannot be disabled."), unit=self.tr("px")
|
||||
)
|
||||
|
||||
@@ -451,7 +451,7 @@ class GuiPreferences(NDialog):
|
||||
self.hideFocusFooter = NSwitch(self)
|
||||
self.hideFocusFooter.setChecked(CONFIG.hideFocusFooter)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Hide document footer in \"Focus Mode\""), self.hideFocusFooter,
|
||||
self.tr('Hide document footer in "Focus Mode"'), self.hideFocusFooter,
|
||||
self.tr("Hide the information bar in the document editor.")
|
||||
)
|
||||
|
||||
|
||||
@@ -122,11 +122,11 @@ class GuiQuoteSelect(NDialog):
|
||||
@classmethod
|
||||
def getQuote(cls, parent: QWidget, current: str = "") -> tuple[str, bool]:
|
||||
"""Pop the dialog and return the result."""
|
||||
cls = GuiQuoteSelect(parent, current=current)
|
||||
cls.exec()
|
||||
quote = cls._selected
|
||||
accepted = cls.result() == QtAccepted
|
||||
cls.softDelete()
|
||||
dialog = cls(parent, current=current)
|
||||
dialog.exec()
|
||||
quote = dialog._selected
|
||||
accepted = dialog.result() == QtAccepted
|
||||
dialog.softDelete()
|
||||
return quote, accepted
|
||||
|
||||
##
|
||||
|
||||
@@ -26,9 +26,9 @@ from __future__ import annotations
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt6.QtGui import QCloseEvent
|
||||
from PyQt6.QtWidgets import (
|
||||
QAbstractItemView, QApplication, QDialogButtonBox, QFileDialog,
|
||||
QHBoxLayout, QLineEdit, QListWidget, QVBoxLayout, QWidget
|
||||
@@ -41,6 +41,9 @@ from novelwriter.extensions.configlayout import NColorLabel
|
||||
from novelwriter.extensions.modified import NDialog, NIconToolButton
|
||||
from novelwriter.types import QtDialogClose, QtDialogSave
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from PyQt6.QtGui import QCloseEvent
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -242,8 +245,7 @@ class GuiWordList(NDialog):
|
||||
|
||||
def _listWords(self) -> list[str]:
|
||||
"""List all words in the list box."""
|
||||
result = []
|
||||
for i in range(self.listBox.count()):
|
||||
if (item := self.listBox.item(i)) and (word := item.text().strip()):
|
||||
result.append(word)
|
||||
return result
|
||||
return [
|
||||
word for i in range(self.listBox.count())
|
||||
if (item := self.listBox.item(i)) and (word := item.text().strip())
|
||||
]
|
||||
|
||||
@@ -36,7 +36,7 @@ from PyQt6.QtWidgets import (
|
||||
QPlainTextEdit, QStyle, QWidget
|
||||
)
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from types import TracebackType
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -46,7 +46,7 @@ def logException() -> None:
|
||||
"""Log the content of an exception message."""
|
||||
exType, exValue, _ = sys.exc_info()
|
||||
if exType is not None:
|
||||
logger.error(f"{exType.__name__}: {str(exValue)}", stacklevel=2)
|
||||
logger.error(f"{exType.__name__}: {exValue!s}", stacklevel=2)
|
||||
return
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ def formatException(exc: BaseException) -> str:
|
||||
"""Format an exception as a string the same way the default
|
||||
exception handler does.
|
||||
"""
|
||||
return f"{type(exc).__name__}: {str(exc)}"
|
||||
return f"{type(exc).__name__}: {exc!s}"
|
||||
|
||||
|
||||
class NWErrorMessage(QDialog):
|
||||
@@ -151,7 +151,7 @@ class NWErrorMessage(QDialog):
|
||||
f"Python: {sys.version.split()[0]} ({sys.hexversion:#x})\n"
|
||||
f"Qt: {QT_VERSION_STR}, PyQt: {PYQT_VERSION_STR}\n"
|
||||
f"enchant: {enchantVersion}\n\n"
|
||||
f"{exType.__name__}:\n{str(exValue)}\n\n"
|
||||
f"{exType.__name__}:\n{exValue!s}\n\n"
|
||||
f"Traceback:\n{txtTrace}\n"
|
||||
)
|
||||
except Exception:
|
||||
|
||||
@@ -24,9 +24,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import QEvent, QObject
|
||||
from PyQt6.QtGui import QStatusTipEvent, QWheelEvent
|
||||
from PyQt6.QtWidgets import QWidget
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from PyQt6.QtWidgets import QWidget
|
||||
|
||||
|
||||
class WheelEventFilter(QObject):
|
||||
@@ -40,7 +44,7 @@ class WheelEventFilter(QObject):
|
||||
Reference: https://stackoverflow.com/a/17739995/5825851
|
||||
"""
|
||||
|
||||
__slots__ = ("_parent", "_locked")
|
||||
__slots__ = ("_locked", "_parent")
|
||||
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
@@ -27,11 +27,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import QModelIndex, QSize, Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt6.QtGui import QMouseEvent, QWheelEvent
|
||||
from PyQt6.QtWidgets import (
|
||||
QApplication, QComboBox, QDialog, QDoubleSpinBox, QLabel, QSpinBox,
|
||||
QToolButton, QTreeView, QWidget
|
||||
@@ -40,7 +38,11 @@ from PyQt6.QtWidgets import (
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.types import QtMouseLeft, QtMouseMiddle
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from enum import Enum
|
||||
|
||||
from PyQt6.QtGui import QMouseEvent, QWheelEvent
|
||||
|
||||
from novelwriter.guimain import GuiMain
|
||||
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ class NPagedSideBar(QToolBar):
|
||||
|
||||
class _PagedToolButton(QToolButton):
|
||||
|
||||
__slots__ = ("_bH", "_tM", "_aH")
|
||||
__slots__ = ("_aH", "_bH", "_tM")
|
||||
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
@@ -44,8 +44,8 @@ class NProgressCircle(QProgressBar):
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_text", "_point", "_dRect", "_cRect", "_dPen", "_dBrush",
|
||||
"_cPen", "_bPen", "_tColor"
|
||||
"_bPen", "_cPen", "_cRect", "_dBrush", "_dPen", "_dRect", "_point",
|
||||
"_tColor", "_text",
|
||||
)
|
||||
|
||||
def __init__(self, parent: QWidget, size: int, point: int) -> None:
|
||||
|
||||
@@ -35,7 +35,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class StatusLED(QAbstractButton):
|
||||
|
||||
__slots__ = ("_neutral", "_postitve", "_negative", "_color", "_state")
|
||||
__slots__ = ("_color", "_negative", "_neutral", "_postitve", "_state")
|
||||
|
||||
def __init__(self, sW: int, sH: int, parent: QWidget | None = None) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
@@ -33,7 +33,7 @@ from novelwriter.types import QtMouseLeft, QtNoPen, QtPaintAntiAlias, QtSizeFixe
|
||||
|
||||
class NSwitch(QAbstractButton):
|
||||
|
||||
__slots__ = ("_xW", "_xH", "_xR", "_rH", "_rR", "_offset")
|
||||
__slots__ = ("_offset", "_rH", "_rR", "_xH", "_xR", "_xW")
|
||||
|
||||
def __init__(self, parent: QWidget, height: int = 0) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
@@ -23,8 +23,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import pyqtSignal
|
||||
from PyQt6.QtGui import QIcon
|
||||
from PyQt6.QtWidgets import QGridLayout, QLabel, QScrollArea, QWidget
|
||||
|
||||
from novelwriter.extensions.switch import NSwitch
|
||||
@@ -33,6 +34,9 @@ from novelwriter.types import (
|
||||
QtSizeMinimumExpanding
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from PyQt6.QtGui import QIcon
|
||||
|
||||
|
||||
class NSwitchBox(QScrollArea):
|
||||
"""Extension: Switch Box Widget
|
||||
|
||||
@@ -29,21 +29,25 @@ import re
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import NamedTuple
|
||||
from typing import TYPE_CHECKING, NamedTuple
|
||||
from zipfile import ZIP_DEFLATED, ZipFile
|
||||
|
||||
from PyQt6.QtCore import QMargins, QSize
|
||||
from PyQt6.QtGui import QColor
|
||||
|
||||
from novelwriter import __version__
|
||||
from novelwriter.common import firstFloat, xmlElement, xmlSubElem
|
||||
from novelwriter.constants import nwHeadFmt, nwStyles
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt
|
||||
from novelwriter.formats.tokenizer import Tokenizer
|
||||
from novelwriter.types import QtHexRgb
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt6.QtGui import QColor
|
||||
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# RegEx
|
||||
@@ -1052,9 +1056,9 @@ class ToDocX(Tokenizer):
|
||||
class DocXParagraph:
|
||||
|
||||
__slots__ = (
|
||||
"_content", "_style", "_textAlign",
|
||||
"_topMargin", "_bottomMargin", "_leftMargin", "_rightMargin",
|
||||
"_indentFirst", "_breakBefore", "_breakAfter", "_footnoteRef",
|
||||
"_bottomMargin", "_breakAfter", "_breakBefore", "_content",
|
||||
"_footnoteRef", "_indentFirst", "_leftMargin", "_rightMargin",
|
||||
"_style", "_textAlign", "_topMargin",
|
||||
)
|
||||
|
||||
def __init__(self) -> None:
|
||||
|
||||
@@ -26,16 +26,20 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from novelwriter.common import formatTimeStamp
|
||||
from novelwriter.constants import nwHtmlUnicode, nwStyles
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt, stripEscape
|
||||
from novelwriter.formats.tokenizer import Tokenizer
|
||||
from novelwriter.types import FONT_STYLE, FONT_WEIGHTS, QtHexRgb
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Each opener tag, with the id of its corresponding closer and tag format
|
||||
@@ -311,10 +315,8 @@ class ToHtml(Tokenizer):
|
||||
|
||||
def replaceTabs(self, nSpaces: int = 8, spaceChar: str = " ") -> None:
|
||||
"""Replace tabs with spaces in the html."""
|
||||
pages = []
|
||||
tabSpace = spaceChar*nSpaces
|
||||
for aLine in self._pages:
|
||||
pages.append(aLine.replace("\t", tabSpace))
|
||||
pages = [aLine.replace("\t", tabSpace) for aLine in self._pages]
|
||||
self._pages = pages
|
||||
return
|
||||
|
||||
|
||||
@@ -28,8 +28,7 @@ import logging
|
||||
import re
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from pathlib import Path
|
||||
from typing import NamedTuple
|
||||
from typing import TYPE_CHECKING, NamedTuple
|
||||
|
||||
from PyQt6.QtCore import QLocale
|
||||
from PyQt6.QtGui import QColor, QFont
|
||||
@@ -40,7 +39,6 @@ from novelwriter.constants import (
|
||||
nwHeadFmt, nwKeyWords, nwLabels, nwShortcode, nwStats, nwStyles, nwUnicode,
|
||||
trConst
|
||||
)
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.enum import nwComment, nwItemLayout
|
||||
from novelwriter.formats.shared import (
|
||||
BlockFmt, BlockTyp, T_Block, T_Formats, T_Note, TextDocumentTheme, TextFmt
|
||||
@@ -48,6 +46,11 @@ from novelwriter.formats.shared import (
|
||||
from novelwriter.text.comments import processComment
|
||||
from novelwriter.text.patterns import REGEX_PATTERNS, DialogParser
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -72,7 +75,7 @@ HEADINGS = [
|
||||
BlockTyp.TITLE, BlockTyp.PART, BlockTyp.HEAD1,
|
||||
BlockTyp.HEAD2, BlockTyp.HEAD3, BlockTyp.HEAD4,
|
||||
]
|
||||
SKIP_INDENT = HEADINGS + [BlockTyp.SEP, BlockTyp.SKIP]
|
||||
SKIP_INDENT = [*HEADINGS, BlockTyp.SEP, BlockTyp.SKIP]
|
||||
B_EMPTY: T_Block = (BlockTyp.EMPTY, "", "", [], BlockFmt.NONE)
|
||||
|
||||
|
||||
@@ -651,7 +654,7 @@ class Tokenizer(ABC):
|
||||
tText = aLine[2:].strip()
|
||||
tType = BlockTyp.HEAD1 if isPlain else BlockTyp.TITLE
|
||||
sHide = self._hidePart if isPlain else False
|
||||
if not (isPlain or isNovel and sHide):
|
||||
if not (isPlain or (isNovel and sHide)):
|
||||
tStyle |= self._titleStyle
|
||||
if isNovel:
|
||||
tType = BlockTyp.PART if isPlain else BlockTyp.TITLE
|
||||
@@ -1124,12 +1127,10 @@ class Tokenizer(ABC):
|
||||
temp.append((res.end(0), 0, TextFmt.HRF_E, ""))
|
||||
|
||||
# Match Shortcodes
|
||||
for res in REGEX_PATTERNS.shortcodePlain.finditer(text):
|
||||
temp.append((
|
||||
res.start(1), res.end(1),
|
||||
self._shortCodeFmt.get(res.group(1).lower(), 0),
|
||||
"",
|
||||
))
|
||||
temp.extend(
|
||||
(res.start(1), res.end(1), self._shortCodeFmt.get(res.group(1).lower(), 0), "")
|
||||
for res in REGEX_PATTERNS.shortcodePlain.finditer(text)
|
||||
)
|
||||
|
||||
# Match Shortcode w/Values
|
||||
tHandle = self._handle or ""
|
||||
|
||||
@@ -25,13 +25,17 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from novelwriter.constants import nwUnicode
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt
|
||||
from novelwriter.formats.tokenizer import Tokenizer
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
@@ -29,10 +29,9 @@ from __future__ import annotations
|
||||
import logging
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from collections.abc import Sequence
|
||||
from datetime import datetime
|
||||
from hashlib import sha256
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Final
|
||||
from zipfile import ZIP_DEFLATED, ZipFile
|
||||
|
||||
from PyQt6.QtGui import QColor, QFont
|
||||
@@ -40,11 +39,16 @@ from PyQt6.QtGui import QColor, QFont
|
||||
from novelwriter import __version__
|
||||
from novelwriter.common import xmlElement, xmlIndent, xmlSubElem
|
||||
from novelwriter.constants import nwHeadFmt, nwStyles
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.formats.shared import BlockFmt, BlockTyp, TextFmt, stripEscape
|
||||
from novelwriter.formats.tokenizer import Tokenizer
|
||||
from novelwriter.types import FONT_STYLE, QtHexRgb
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Sequence
|
||||
from pathlib import Path
|
||||
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Main XML NameSpaces
|
||||
@@ -1000,11 +1004,11 @@ class ODTParagraphStyle:
|
||||
exporter. Only the used settings are exposed here to keep the class
|
||||
minimal and fast.
|
||||
"""
|
||||
VALID_ALIGN = ["start", "center", "end", "justify", "inside", "outside", "left", "right"]
|
||||
VALID_BREAK = ["auto", "column", "page", "even-page", "odd-page", "inherit"]
|
||||
VALID_LEVEL = ["1", "2", "3", "4"]
|
||||
VALID_CLASS = ["text", "chapter", "extra"]
|
||||
VALID_WEIGHT = ["normal", "bold"] + FONT_WEIGHT_NUM
|
||||
VALID_ALIGN: Final[list[str]] = ["start", "center", "end", "justify", "left", "right"]
|
||||
VALID_BREAK: Final[list[str]] = ["auto", "page", "even-page", "odd-page", "inherit"]
|
||||
VALID_LEVEL: Final[list[str]] = ["1", "2", "3", "4"]
|
||||
VALID_CLASS: Final[list[str]] = ["text", "chapter", "extra"]
|
||||
VALID_WEIGHT: Final[list[str]] = ["normal", "bold", *FONT_WEIGHT_NUM]
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
|
||||
@@ -1207,9 +1211,9 @@ class ODTParagraphStyle:
|
||||
def getID(self) -> str:
|
||||
"""Generate a unique ID from the settings."""
|
||||
return sha256((
|
||||
f"Paragraph:Main:{str(self._mAttr)}:"
|
||||
f"Paragraph:Para:{str(self._pAttr)}:"
|
||||
f"Paragraph:Text:{str(self._tAttr)}:"
|
||||
f"Paragraph:Main:{self._mAttr!s}:"
|
||||
f"Paragraph:Para:{self._pAttr!s}:"
|
||||
f"Paragraph:Text:{self._tAttr!s}:"
|
||||
).encode()).hexdigest()
|
||||
|
||||
def packXML(self, xParent: ET.Element) -> None:
|
||||
@@ -1237,13 +1241,13 @@ class ODTTextStyle:
|
||||
Only the used settings are exposed here to keep the class minimal
|
||||
and fast.
|
||||
"""
|
||||
VALID_WEIGHT = ["normal", "bold"] + FONT_WEIGHT_NUM
|
||||
VALID_STYLE = ["normal", "italic", "oblique"]
|
||||
VALID_POS = ["super", "sub"]
|
||||
VALID_LSTYLE = ["none", "solid"]
|
||||
VALID_LTYPE = ["single", "double"]
|
||||
VALID_LWIDTH = ["auto"]
|
||||
VALID_LCOL = ["font-color"]
|
||||
VALID_WEIGHT: Final[list[str]] = ["normal", "bold", *FONT_WEIGHT_NUM]
|
||||
VALID_STYLE: Final[list[str]] = ["normal", "italic", "oblique"]
|
||||
VALID_POS: Final[list[str]] = ["super", "sub"]
|
||||
VALID_LSTYLE: Final[list[str]] = ["none", "solid"]
|
||||
VALID_LTYPE: Final[list[str]] = ["single", "double"]
|
||||
VALID_LWIDTH: Final[list[str]] = ["auto"]
|
||||
VALID_LCOL: Final[list[str]] = ["font-color"]
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
self._name = name
|
||||
|
||||
@@ -25,7 +25,7 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import QMarginsF, QSizeF
|
||||
from PyQt6.QtGui import (
|
||||
@@ -36,7 +36,6 @@ from PyQt6.QtPrintSupport import QPrinter
|
||||
|
||||
from novelwriter import __version__
|
||||
from novelwriter.constants import nwStyles, nwUnicode
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt
|
||||
from novelwriter.formats.tokenizer import HEADINGS, Tokenizer
|
||||
from novelwriter.types import (
|
||||
@@ -45,6 +44,11 @@ from novelwriter.types import (
|
||||
QtPropLineHeight, QtTransparent, QtVAlignNormal, QtVAlignSub, QtVAlignSuper
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
T_TextStyle = tuple[QTextBlockFormat, QTextCharFormat]
|
||||
|
||||
@@ -26,13 +26,17 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from novelwriter.common import formatTimeStamp
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.formats.tokenizer import Tokenizer
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
@@ -97,10 +97,10 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
"""Gui Widget: Main Document Editor"""
|
||||
|
||||
__slots__ = (
|
||||
"_nwDocument", "_nwItem", "_docChanged", "_docHandle", "_vpMargin",
|
||||
"_lastEdit", "_lastActive", "_lastFind", "_doReplace", "_autoReplace",
|
||||
"_completer", "_qDocument", "_keyContext", "_followTag1", "_followTag2",
|
||||
"_timerDoc", "_wCounterDoc", "_timerSel", "_wCounterSel",
|
||||
"_autoReplace", "_completer", "_doReplace", "_docChanged", "_docHandle", "_followTag1",
|
||||
"_followTag2", "_keyContext", "_lastActive", "_lastEdit", "_lastFind", "_nwDocument",
|
||||
"_nwItem", "_qDocument", "_timerDoc", "_timerSel", "_vpMargin", "_wCounterDoc",
|
||||
"_wCounterSel",
|
||||
)
|
||||
|
||||
MOVE_KEYS = (
|
||||
@@ -760,7 +760,7 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
elif action == nwDocAction.REPL_SNG:
|
||||
self._replaceQuotes("'", CONFIG.fmtSQuoteOpen, CONFIG.fmtSQuoteClose)
|
||||
elif action == nwDocAction.REPL_DBL:
|
||||
self._replaceQuotes("\"", CONFIG.fmtDQuoteOpen, CONFIG.fmtDQuoteClose)
|
||||
self._replaceQuotes('"', CONFIG.fmtDQuoteOpen, CONFIG.fmtDQuoteClose)
|
||||
elif action == nwDocAction.RM_BREAKS:
|
||||
self._removeInParLineBreaks()
|
||||
elif action == nwDocAction.ALIGN_L:
|
||||
@@ -2003,7 +2003,7 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
sPos = cPos - i - 1
|
||||
cOne = str(self._qDocument.characterAt(sPos))
|
||||
cTwo = str(self._qDocument.characterAt(sPos - 1))
|
||||
if not (cOne.isalnum() or cOne in apos and cTwo.isalnum()):
|
||||
if not (cOne.isalnum() or (cOne in apos and cTwo.isalnum())):
|
||||
sPos += 1
|
||||
break
|
||||
|
||||
@@ -2013,7 +2013,7 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
ePos = cPos + i
|
||||
cOne = str(self._qDocument.characterAt(ePos))
|
||||
cTwo = str(self._qDocument.characterAt(ePos + 1))
|
||||
if not (cOne.isalnum() or cOne in apos and cTwo.isalnum()):
|
||||
if not (cOne.isalnum() or (cOne in apos and cTwo.isalnum())):
|
||||
break
|
||||
|
||||
if ePos - sPos <= 0:
|
||||
@@ -2193,9 +2193,9 @@ class BackgroundWordCounterSignals(QObject):
|
||||
class TextAutoReplace:
|
||||
|
||||
__slots__ = (
|
||||
"_quoteSO", "_quoteSC", "_quoteDO", "_quoteDC",
|
||||
"_replaceSQuote", "_replaceDQuote", "_replaceDash", "_replaceDots",
|
||||
"_padChar", "_padBefore", "_padAfter", "_doPadBefore", "_doPadAfter",
|
||||
"_doPadAfter", "_doPadBefore", "_padAfter", "_padBefore", "_padChar",
|
||||
"_quoteDC", "_quoteDO", "_quoteSC", "_quoteSO", "_replaceDQuote",
|
||||
"_replaceDash", "_replaceDots", "_replaceSQuote",
|
||||
)
|
||||
|
||||
def __init__(self) -> None:
|
||||
|
||||
@@ -58,8 +58,8 @@ BLOCK_TITLE = 4
|
||||
class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
|
||||
__slots__ = (
|
||||
"_tHandle", "_isNovel", "_isInactive", "_spellCheck", "_spellErr",
|
||||
"_hStyles", "_minRules", "_txtRules", "_cmnRules", "_dialogParser",
|
||||
"_cmnRules", "_dialogParser", "_hStyles", "_isInactive", "_isNovel",
|
||||
"_minRules", "_spellCheck", "_spellErr", "_tHandle", "_txtRules",
|
||||
)
|
||||
|
||||
def __init__(self, document: QTextDocument) -> None:
|
||||
@@ -466,7 +466,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
|
||||
class TextBlockData(QTextBlockUserData):
|
||||
|
||||
__slots__ = ("_text", "_offset", "_metaData", "_spellErrors")
|
||||
__slots__ = ("_metaData", "_offset", "_spellErrors", "_text")
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
@@ -26,6 +26,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import QModelIndex, Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt6.QtWidgets import (
|
||||
@@ -36,12 +37,14 @@ from PyQt6.QtWidgets import (
|
||||
from novelwriter import SHARED
|
||||
from novelwriter.common import checkInt, qtAddAction
|
||||
from novelwriter.constants import nwLabels, nwLists, nwStyles, trConst
|
||||
from novelwriter.core.indexdata import IndexHeading, IndexNode
|
||||
from novelwriter.enum import nwChange, nwDocMode, nwItemClass
|
||||
from novelwriter.extensions.modified import NIconToolButton
|
||||
from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON
|
||||
from novelwriter.types import QtDecoration, QtHeaderFixed, QtHeaderToContents, QtUserRole
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.core.indexdata import IndexHeading, IndexNode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from collections.abc import Iterable
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import QObject, pyqtSlot
|
||||
from PyQt6.QtGui import QTextBlock, QTextCursor, QTextDocument
|
||||
@@ -35,6 +35,9 @@ from PyQt6.QtWidgets import QApplication, QPlainTextDocumentLayout
|
||||
from novelwriter import SHARED
|
||||
from novelwriter.gui.dochighlight import GuiDocHighlighter, TextBlockData
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterable
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ class GuiItemDetails(QWidget):
|
||||
return
|
||||
|
||||
self._handle = tHandle
|
||||
iPx = int(round(0.9*SHARED.theme.baseIconHeight))
|
||||
iPx = round(0.9*SHARED.theme.baseIconHeight)
|
||||
|
||||
# Label
|
||||
# =====
|
||||
|
||||
@@ -41,7 +41,7 @@ from novelwriter.constants import (
|
||||
from novelwriter.enum import nwDocAction, nwDocInsert, nwFocus, nwView
|
||||
from novelwriter.extensions.eventfilters import StatusTipFilter
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.guimain import GuiMain
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -471,7 +471,7 @@ class GuiMainMenu(QMenuBar):
|
||||
|
||||
# Insert > Double Prime
|
||||
self.aInsDPrime = qtAddAction(self.mInsPunct, self.tr("Double Prime"))
|
||||
self.aInsDPrime.setShortcut("Ctrl+K, Ctrl+\"")
|
||||
self.aInsDPrime.setShortcut('Ctrl+K, Ctrl+"')
|
||||
self.aInsDPrime.triggered.connect(
|
||||
lambda: self.requestDocInsertText.emit(nwUnicode.U_DPRIME)
|
||||
)
|
||||
@@ -680,7 +680,7 @@ class GuiMainMenu(QMenuBar):
|
||||
|
||||
# Format > Double Quotes
|
||||
self.aFmtDQuote = qtAddAction(self.fmtMenu, self.tr("Wrap Double Quotes"))
|
||||
self.aFmtDQuote.setShortcut("Ctrl+\"")
|
||||
self.aFmtDQuote.setShortcut('Ctrl+"')
|
||||
self.aFmtDQuote.triggered.connect(
|
||||
lambda: self.requestDocAction.emit(nwDocAction.D_QUOTE)
|
||||
)
|
||||
|
||||
@@ -32,6 +32,7 @@ import logging
|
||||
|
||||
from enum import Enum
|
||||
from time import time
|
||||
from typing import Final
|
||||
|
||||
from PyQt6.QtCore import QT_TRANSLATE_NOOP, Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt6.QtGui import QAction, QIcon
|
||||
@@ -319,7 +320,7 @@ class GuiOutlineToolBar(QToolBar):
|
||||
|
||||
class GuiOutlineTree(QTreeWidget):
|
||||
|
||||
DEF_WIDTH = {
|
||||
DEF_WIDTH: Final[dict[nwOutline, int]] = {
|
||||
nwOutline.TITLE: 200,
|
||||
nwOutline.LEVEL: 40,
|
||||
nwOutline.LABEL: 150,
|
||||
@@ -342,7 +343,7 @@ class GuiOutlineTree(QTreeWidget):
|
||||
nwOutline.SYNOP: 200,
|
||||
}
|
||||
|
||||
DEF_HIDDEN = {
|
||||
DEF_HIDDEN: Final[dict[nwOutline, bool]] = {
|
||||
nwOutline.TITLE: False,
|
||||
nwOutline.LEVEL: True,
|
||||
nwOutline.LABEL: False,
|
||||
@@ -498,7 +499,7 @@ class GuiOutlineTree(QTreeWidget):
|
||||
tree.
|
||||
"""
|
||||
# If it's the first time, we always build
|
||||
if self._firstView or self._firstView and overRide:
|
||||
if self._firstView or (self._firstView and overRide):
|
||||
self._loadHeaderState()
|
||||
self._populateTree(rootHandle)
|
||||
self._firstView = False
|
||||
@@ -558,7 +559,7 @@ class GuiOutlineTree(QTreeWidget):
|
||||
logger.info("Writing CSV file: %s", path)
|
||||
cols = [col for col in self._treeOrder if not self._colHidden[col]]
|
||||
order = [self._colIdx[col] for col in cols]
|
||||
with open(path, mode="w", newline="") as csvFile:
|
||||
with open(path, mode="w", newline="", encoding="utf-8") as csvFile:
|
||||
writer = csv.writer(csvFile, dialect="excel", quoting=csv.QUOTE_ALL)
|
||||
writer.writerow([trConst(nwLabels.OUTLINE_COLS[col]) for col in cols])
|
||||
for i in range(self.topLevelItemCount()):
|
||||
@@ -795,7 +796,7 @@ class GuiOutlineHeaderMenu(QMenu):
|
||||
|
||||
class GuiOutlineDetails(QScrollArea):
|
||||
|
||||
LVL_MAP = {
|
||||
LVL_MAP: Final[dict[str, str]] = {
|
||||
"H1": QT_TRANSLATE_NOOP("GuiOutlineDetails", "Title"),
|
||||
"H2": QT_TRANSLATE_NOOP("GuiOutlineDetails", "Chapter"),
|
||||
"H3": QT_TRANSLATE_NOOP("GuiOutlineDetails", "Scene"),
|
||||
|
||||
@@ -1099,7 +1099,7 @@ class _UpdatableMenu(QMenu):
|
||||
|
||||
class _TreeContextMenu(QMenu):
|
||||
|
||||
__slots__ = ("_tree", "_view", "_node", "_item", "_model", "_handle", "_indices", "_children")
|
||||
__slots__ = ("_children", "_handle", "_indices", "_item", "_model", "_node", "_tree", "_view")
|
||||
|
||||
def __init__(
|
||||
self, projTree: GuiProjectTree, model: ProjectModel,
|
||||
@@ -1327,7 +1327,7 @@ class _TreeContextMenu(QMenu):
|
||||
"""Add move to Trash action."""
|
||||
if (
|
||||
self._model.trashSelection(self._indices)
|
||||
or len(self._indices) == 1 and self._item.isRootType()
|
||||
or (len(self._indices) == 1 and self._item.isRootType())
|
||||
):
|
||||
text = self.tr("Delete Permanently")
|
||||
else:
|
||||
|
||||
@@ -26,6 +26,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt6.QtGui import QAction, QCursor, QKeyEvent, QPalette
|
||||
@@ -37,12 +38,14 @@ from PyQt6.QtWidgets import (
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.common import checkInt, qtAddAction
|
||||
from novelwriter.core.coretools import DocSearch
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.types import (
|
||||
QtAlignMiddle, QtAlignRight, QtHeaderStretch, QtHeaderToContents,
|
||||
QtHexArgb, QtUserRole
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.core.item import NWItem
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ from novelwriter.extensions.eventfilters import StatusTipFilter
|
||||
from novelwriter.extensions.modified import NIconToolButton
|
||||
from novelwriter.gui.theme import STYLES_BIG_TOOLBUTTON
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.guimain import GuiMain
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
+20
-22
@@ -27,7 +27,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
|
||||
from math import ceil
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Final
|
||||
|
||||
from PyQt6.QtCore import QSize, Qt
|
||||
from PyQt6.QtGui import (
|
||||
@@ -44,6 +44,9 @@ from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.types import QtBlack, QtHexArgb, QtPaintAntiAlias, QtTransparent
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
STYLES_FLAT_TABS = "flatTabWidget"
|
||||
@@ -93,18 +96,13 @@ class GuiTheme:
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
# Attributes
|
||||
"iconCache", "themeMeta", "isDarkTheme", "helpText", "fadedText", "errorText",
|
||||
"syntaxMeta", "syntaxTheme", "guiFont", "guiFontB", "guiFontBU", "guiFontSmall",
|
||||
"fontPointSize", "fontPixelSize", "baseIconHeight", "baseButtonHeight", "textNHeight",
|
||||
"textNWidth", "baseIconSize", "buttonIconSize", "guiFontFixed",
|
||||
|
||||
# Functions
|
||||
"getIcon", "getPixmap", "getItemIcon", "getIconColor", "getToggleIcon", "getDecoration",
|
||||
"getHeaderDecoration", "getHeaderDecorationNarrow",
|
||||
|
||||
# Internal
|
||||
"_guiPalette", "_themeList", "_syntaxList", "_availThemes", "_availSyntax", "_styleSheets",
|
||||
"_availSyntax", "_availThemes", "_guiPalette", "_styleSheets", "_syntaxList", "_themeList",
|
||||
"baseButtonHeight", "baseIconHeight", "baseIconSize", "buttonIconSize", "errorText",
|
||||
"fadedText", "fontPixelSize", "fontPointSize", "getDecoration", "getHeaderDecoration",
|
||||
"getHeaderDecorationNarrow", "getIcon", "getIconColor", "getItemIcon", "getPixmap",
|
||||
"getToggleIcon", "guiFont", "guiFontB", "guiFontBU", "guiFontFixed", "guiFontSmall",
|
||||
"helpText", "iconCache", "isDarkTheme", "syntaxMeta", "syntaxTheme", "textNHeight",
|
||||
"textNWidth", "themeMeta",
|
||||
)
|
||||
|
||||
def __init__(self) -> None:
|
||||
@@ -164,9 +162,9 @@ class GuiTheme:
|
||||
fHeight = qMetric.height()
|
||||
fAscent = qMetric.ascent()
|
||||
self.fontPointSize = self.guiFont.pointSizeF()
|
||||
self.fontPixelSize = int(round(fHeight))
|
||||
self.baseIconHeight = int(round(fAscent))
|
||||
self.baseButtonHeight = int(round(1.35*fAscent))
|
||||
self.fontPixelSize = round(fHeight)
|
||||
self.baseIconHeight = round(fAscent)
|
||||
self.baseButtonHeight = round(1.35*fAscent)
|
||||
self.textNHeight = qMetric.boundingRect("N").height()
|
||||
self.textNWidth = qMetric.boundingRect("N").width()
|
||||
|
||||
@@ -202,7 +200,7 @@ class GuiTheme:
|
||||
qMetrics = QFontMetrics(font)
|
||||
else:
|
||||
qMetrics = QFontMetrics(self.guiFont)
|
||||
return int(ceil(qMetrics.boundingRect(text).width()))
|
||||
return ceil(qMetrics.boundingRect(text).width())
|
||||
|
||||
##
|
||||
# Theme Methods
|
||||
@@ -567,16 +565,16 @@ class GuiIcons:
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"mainTheme", "themeMeta", "_svgData", "_svgColors", "_qColors",
|
||||
"_qIcons", "_headerDec", "_headerDecNarrow", "_availThemes",
|
||||
"_themeList", "_noIcon",
|
||||
"_availThemes", "_headerDec", "_headerDecNarrow", "_noIcon",
|
||||
"_qColors", "_qIcons", "_svgColors", "_svgData", "_themeList",
|
||||
"mainTheme", "themeMeta",
|
||||
)
|
||||
|
||||
TOGGLE_ICON_KEYS: dict[str, tuple[str, str]] = {
|
||||
TOGGLE_ICON_KEYS: Final[dict[str, tuple[str, str]]] = {
|
||||
"bullet": ("bullet-on", "bullet-off"),
|
||||
"unfold": ("unfold-show", "unfold-hide"),
|
||||
}
|
||||
IMAGE_MAP: dict[str, tuple[str, str]] = {
|
||||
IMAGE_MAP: Final[dict[str, tuple[str, str]]] = {
|
||||
"welcome": ("welcome-light.jpg", "welcome-dark.jpg"),
|
||||
"nw-text": ("novelwriter-text-light.svg", "novelwriter-text-dark.svg"),
|
||||
}
|
||||
|
||||
@@ -1009,7 +1009,7 @@ class GuiMain(QMainWindow):
|
||||
fN = self.novelView.treeHasFocus()
|
||||
|
||||
self._changeView(nwView.EDITOR)
|
||||
if (vM and (vP and fP or vN and not fN)) or (not vM and vN):
|
||||
if (vM and ((vP and fP) or (vN and not fN))) or (not vM and vN):
|
||||
self._changeView(nwView.NOVEL)
|
||||
self.novelView.setTreeFocus()
|
||||
else:
|
||||
|
||||
@@ -40,7 +40,7 @@ from novelwriter.constants import nwFiles
|
||||
from novelwriter.core.spellcheck import NWSpellEnchant
|
||||
from novelwriter.enum import nwChange, nwItemClass
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.status import T_StatusKind
|
||||
from novelwriter.gui.theme import GuiTheme
|
||||
@@ -54,8 +54,8 @@ NWWidget = TypeVar("NWWidget", bound=QWidget)
|
||||
class SharedData(QObject):
|
||||
|
||||
__slots__ = (
|
||||
"_gui", "_theme", "_project", "_spelling", "_lockedBy", "_lastAlert",
|
||||
"_idleTime", "_idleRefTime",
|
||||
"_gui", "_idleRefTime", "_idleTime", "_lastAlert", "_lockedBy",
|
||||
"_project", "_spelling", "_theme",
|
||||
)
|
||||
|
||||
focusModeChanged = pyqtSignal(bool)
|
||||
@@ -480,7 +480,7 @@ class _GuiAlert(QMessageBox):
|
||||
def setException(self, exception: Exception) -> None:
|
||||
"""Add exception details."""
|
||||
info = self.informativeText()
|
||||
text = f"<b>{type(exception).__name__}</b>: {str(exception)}"
|
||||
text = f"<b>{type(exception).__name__}</b>: {exception!s}"
|
||||
self.setInformativeText(f"{info}<br>{text}" if info else text)
|
||||
return
|
||||
|
||||
|
||||
@@ -128,8 +128,8 @@ REGEX_PATTERNS = RegExPatterns()
|
||||
class DialogParser:
|
||||
|
||||
__slots__ = (
|
||||
"_quotes", "_dialog", "_alternate", "_enabled",
|
||||
"_narrator", "_breakD", "_breakQ", "_mode",
|
||||
"_alternate", "_breakD", "_breakQ", "_dialog", "_enabled", "_mode",
|
||||
"_narrator", "_quotes",
|
||||
)
|
||||
|
||||
def __init__(self) -> None:
|
||||
|
||||
@@ -124,10 +124,10 @@ class GuiLipsum(NDialog):
|
||||
@classmethod
|
||||
def getLipsum(cls, parent: QWidget) -> str:
|
||||
"""Pop the dialog and return the lipsum text."""
|
||||
cls = GuiLipsum(parent)
|
||||
cls.exec()
|
||||
text = cls.lipsumText
|
||||
cls.softDelete()
|
||||
dialog = cls(parent)
|
||||
dialog.exec()
|
||||
text = dialog.lipsumText
|
||||
dialog.softDelete()
|
||||
return text
|
||||
|
||||
##
|
||||
|
||||
@@ -26,9 +26,9 @@ from __future__ import annotations
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import QTimer, pyqtSlot
|
||||
from PyQt6.QtGui import QCloseEvent
|
||||
from PyQt6.QtWidgets import (
|
||||
QAbstractButton, QAbstractItemView, QDialogButtonBox, QFileDialog,
|
||||
QGridLayout, QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem,
|
||||
@@ -38,7 +38,6 @@ from PyQt6.QtWidgets import (
|
||||
from novelwriter import SHARED
|
||||
from novelwriter.common import makeFileNameSafe, openExternalPath
|
||||
from novelwriter.constants import nwLabels
|
||||
from novelwriter.core.buildsettings import BuildSettings
|
||||
from novelwriter.core.docbuild import NWBuildDocument
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.enum import nwBuildFmt
|
||||
@@ -46,6 +45,11 @@ from novelwriter.extensions.modified import NDialog, NIconToolButton
|
||||
from novelwriter.extensions.progressbars import NProgressSimple
|
||||
from novelwriter.types import QtAlignCenter, QtDialogClose, QtRoleAction, QtRoleReject, QtUserRole
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from PyQt6.QtGui import QCloseEvent
|
||||
|
||||
from novelwriter.core.buildsettings import BuildSettings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ from novelwriter.types import (
|
||||
QtUserRole
|
||||
)
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.guimain import GuiMain
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -427,10 +427,10 @@ class GuiManuscript(NToolDialog):
|
||||
|
||||
def _saveSettings(self) -> None:
|
||||
"""Save the user GUI settings."""
|
||||
buildOrder = []
|
||||
for i in range(self.buildList.count()):
|
||||
if item := self.buildList.item(i):
|
||||
buildOrder.append(item.data(self.D_KEY))
|
||||
buildOrder = [
|
||||
item.data(self.D_KEY) for i in range(self.buildList.count())
|
||||
if (item := self.buildList.item(i))
|
||||
]
|
||||
|
||||
current = self.buildList.currentItem()
|
||||
lastBuild = current.data(self.D_KEY) if isinstance(current, QListWidgetItem) else ""
|
||||
@@ -744,7 +744,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
document.setDocumentMargin(CONFIG.textMargin)
|
||||
|
||||
self.setPlaceholderText(self.tr(
|
||||
"Press the \"Preview\" button to generate ..."
|
||||
'Press the "Preview" button to generate ...'
|
||||
))
|
||||
|
||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
|
||||
|
||||
@@ -55,7 +55,7 @@ from novelwriter.types import (
|
||||
QtUserRole
|
||||
)
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.guimain import GuiMain
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -26,8 +26,9 @@ from __future__ import annotations
|
||||
import logging
|
||||
import math
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import pyqtSlot
|
||||
from PyQt6.QtGui import QCloseEvent
|
||||
from PyQt6.QtWidgets import (
|
||||
QAbstractItemView, QDialogButtonBox, QFormLayout, QGridLayout, QHBoxLayout,
|
||||
QLabel, QSpinBox, QStackedWidget, QTreeWidget, QTreeWidgetItem,
|
||||
@@ -44,6 +45,9 @@ from novelwriter.extensions.pagedsidebar import NPagedSideBar
|
||||
from novelwriter.extensions.switch import NSwitch
|
||||
from novelwriter.types import QtAlignRight, QtDecoration, QtDialogClose
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from PyQt6.QtGui import QCloseEvent
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
@@ -385,7 +385,7 @@ class _OpenProjectPage(QWidget):
|
||||
|
||||
class _ProjectListItem(QStyledItemDelegate):
|
||||
|
||||
__slots__ = ("_pPx", "_hPx", "_tFont", "_dFont", "_dPen", "_icon")
|
||||
__slots__ = ("_dFont", "_dPen", "_hPx", "_icon", "_pPx", "_tFont")
|
||||
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
@@ -47,7 +47,7 @@ from novelwriter.types import (
|
||||
QtDialogClose, QtRoleAction
|
||||
)
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
from novelwriter.guimain import GuiMain
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -124,7 +124,7 @@ class GuiWritingStats(NToolDialog):
|
||||
self.listBox.setSortingEnabled(True)
|
||||
|
||||
# Word Bar
|
||||
self.barHeight = int(round(0.5*SHARED.theme.fontPixelSize))
|
||||
self.barHeight = round(0.5*SHARED.theme.fontPixelSize)
|
||||
self.barImage = QPixmap(self.barHeight, self.barHeight)
|
||||
self.barImage.fill(self.palette().highlight().color())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user