Merge branch 'main' into primary_count
This commit is contained in:
@@ -25,15 +25,15 @@ text = 86, 88, 105
|
|||||||
link = 9, 161, 237
|
link = 9, 161, 237
|
||||||
headertext = 45, 174, 88
|
headertext = 45, 174, 88
|
||||||
headertag = 45, 174, 88, 160
|
headertag = 45, 174, 88, 160
|
||||||
emphasis = 19, 187, 183
|
emphasis = 247, 103, 187
|
||||||
dialog = 207, 156, 0
|
dialog = 9, 161, 237
|
||||||
altdialog = 207, 156, 0
|
altdialog = 207, 156, 0
|
||||||
note = 120, 187, 185
|
note = 120, 187, 185
|
||||||
hidden = 145, 148, 162
|
hidden = 145, 148, 162
|
||||||
shortcode = 247, 103, 187
|
shortcode = 247, 103, 187
|
||||||
keyword = 9, 161, 237
|
keyword = 9, 161, 237
|
||||||
tag = 45, 174, 88
|
tag = 45, 174, 88
|
||||||
value = 9, 161, 237
|
value = 207, 156, 0
|
||||||
optional = 207, 156, 0
|
optional = 207, 156, 0
|
||||||
spellcheckline = 255, 92, 87
|
spellcheckline = 255, 92, 87
|
||||||
errorline = 45, 174, 88
|
errorline = 45, 174, 88
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
[Main]
|
||||||
|
name = Snazzy Light
|
||||||
|
author = Veronica Berglyd Olsen (adaptation)
|
||||||
|
credit = Florian Reuschel (color theme)
|
||||||
|
url = https://github.com/loilo/vscode-snazzy-light
|
||||||
|
license = MIT License
|
||||||
|
licenseurl = https://github.com/loilo/vscode-snazzy-light/blob/master/LICENSE
|
||||||
|
|
||||||
|
[Icons]
|
||||||
|
default = 86, 88, 105
|
||||||
|
faded = 84, 85, 84
|
||||||
|
red = 255, 92, 87
|
||||||
|
orange = 245, 185, 0
|
||||||
|
yellow = 207, 156, 0
|
||||||
|
green = 45, 174, 88
|
||||||
|
aqua = 19, 187, 183
|
||||||
|
blue = 9, 161, 237
|
||||||
|
purple = 247, 103, 187
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
root = 9, 161, 237
|
||||||
|
folder = 207, 156, 0
|
||||||
|
file = 84, 85, 84
|
||||||
|
title = 45, 174, 88
|
||||||
|
chapter = 255, 92, 87
|
||||||
|
scene = 9, 161, 237
|
||||||
|
note = 207, 156, 0
|
||||||
|
|
||||||
|
[Palette]
|
||||||
|
window = 243, 244, 245
|
||||||
|
windowtext = 86, 88, 105
|
||||||
|
base = 250, 251, 252
|
||||||
|
alternatebase = 234, 234, 235
|
||||||
|
text = 86, 88, 105
|
||||||
|
tooltipbase = 245, 233, 194
|
||||||
|
tooltiptext = 86, 88, 105
|
||||||
|
button = 250, 251, 252
|
||||||
|
buttontext = 86, 88, 105
|
||||||
|
brighttext = 255, 255, 255
|
||||||
|
highlight = 9, 161, 237
|
||||||
|
highlightedtext = 255, 255, 255
|
||||||
|
link = 9, 161, 237
|
||||||
|
linkvisited = 9, 161, 237
|
||||||
|
|
||||||
|
[GUI]
|
||||||
|
helptext = 9, 161, 237
|
||||||
|
fadedtext = 84, 85, 84
|
||||||
|
errortext = 255, 92, 87
|
||||||
+10
-1
@@ -40,7 +40,7 @@ from PyQt6.QtCore import QCoreApplication, QMimeData, QUrl
|
|||||||
from PyQt6.QtGui import QAction, QDesktopServices, QFont, QFontDatabase, QFontInfo
|
from PyQt6.QtGui import QAction, QDesktopServices, QFont, QFontDatabase, QFontInfo
|
||||||
from PyQt6.QtWidgets import QMenu, QMenuBar, QWidget
|
from PyQt6.QtWidgets import QMenu, QMenuBar, QWidget
|
||||||
|
|
||||||
from novelwriter.constants import nwConst, nwLabels, nwUnicode, trConst
|
from novelwriter.constants import nwConst, nwLabels, nwQuotes, nwUnicode, trConst
|
||||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
||||||
from novelwriter.error import logException
|
from novelwriter.error import logException
|
||||||
|
|
||||||
@@ -298,6 +298,15 @@ def uniqueCompact(text: str) -> str:
|
|||||||
return "".join(sorted(set(compact(text))))
|
return "".join(sorted(set(compact(text))))
|
||||||
|
|
||||||
|
|
||||||
|
def processDialogSymbols(symbols: str) -> str:
|
||||||
|
"""Process dialogue line symbols."""
|
||||||
|
result = ""
|
||||||
|
for c in uniqueCompact(symbols):
|
||||||
|
if c in nwQuotes.ALLOWED:
|
||||||
|
result += c
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def elide(text: str, length: int) -> str:
|
def elide(text: str, length: int) -> str:
|
||||||
"""Elide a piece of text to a maximum length."""
|
"""Elide a piece of text to a maximum length."""
|
||||||
if len(text) > (cut := max(4, length)):
|
if len(text) > (cut := max(4, length)):
|
||||||
|
|||||||
+41
-19
@@ -34,17 +34,17 @@ from time import time
|
|||||||
from typing import TYPE_CHECKING, Final
|
from typing import TYPE_CHECKING, Final
|
||||||
|
|
||||||
from PyQt6.QtCore import (
|
from PyQt6.QtCore import (
|
||||||
PYQT_VERSION, PYQT_VERSION_STR, QT_VERSION, QT_VERSION_STR, QLibraryInfo,
|
PYQT_VERSION, PYQT_VERSION_STR, QT_VERSION, QT_VERSION_STR, QDate,
|
||||||
QLocale, QStandardPaths, QSysInfo, QTranslator
|
QDateTime, QLibraryInfo, QLocale, QStandardPaths, QSysInfo, QTranslator
|
||||||
)
|
)
|
||||||
from PyQt6.QtGui import QFont, QFontDatabase, QFontMetrics
|
from PyQt6.QtGui import QFont, QFontDatabase, QFontMetrics
|
||||||
from PyQt6.QtWidgets import QApplication
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
|
||||||
from novelwriter.common import (
|
from novelwriter.common import (
|
||||||
NWConfigParser, checkInt, checkPath, describeFont, fontMatcher,
|
NWConfigParser, checkInt, checkPath, describeFont, fontMatcher,
|
||||||
formatTimeStamp
|
formatTimeStamp, processDialogSymbols, simplified
|
||||||
)
|
)
|
||||||
from novelwriter.constants import nwFiles, nwHtmlUnicode, nwUnicode
|
from novelwriter.constants import nwFiles, nwHtmlUnicode, nwQuotes, nwUnicode
|
||||||
from novelwriter.error import formatException, logException
|
from novelwriter.error import formatException, logException
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -65,16 +65,16 @@ class Config:
|
|||||||
|
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
"_appPath", "_appRoot", "_backPath", "_backupPath", "_confPath", "_dLocale", "_dShortDate",
|
"_appPath", "_appRoot", "_backPath", "_backupPath", "_confPath", "_dLocale", "_dShortDate",
|
||||||
"_dShortDateTime", "_dataPath", "_errData", "_hasError", "_homePath", "_manuals",
|
"_dShortDateTime", "_dataPath", "_errData", "_hasError", "_homePath", "_lastAuthor",
|
||||||
"_nwLangPath", "_qLocale", "_qtLangPath", "_qtTrans", "_recentPaths", "_recentProjects",
|
"_manuals", "_nwLangPath", "_qLocale", "_qtLangPath", "_qtTrans", "_recentPaths",
|
||||||
"_splash", "allowOpenDial", "altDialogClose", "altDialogOpen", "appHandle", "appName",
|
"_recentProjects", "_splash", "allowOpenDial", "altDialogClose", "altDialogOpen",
|
||||||
"askBeforeBackup", "askBeforeExit", "autoSaveDoc", "autoSaveProj", "autoScroll",
|
"appHandle", "appName", "askBeforeBackup", "askBeforeExit", "autoSaveDoc", "autoSaveProj",
|
||||||
"autoScrollPos", "autoSelect", "backupOnClose", "cursorWidth", "dialogLine", "dialogStyle",
|
"autoScroll", "autoScrollPos", "autoSelect", "backupOnClose", "cursorWidth", "dialogLine",
|
||||||
"doJustify", "doReplace", "doReplaceDQuote", "doReplaceDash", "doReplaceDots",
|
"dialogStyle", "doJustify", "doReplace", "doReplaceDQuote", "doReplaceDash",
|
||||||
"doReplaceSQuote", "emphLabels", "fmtApostrophe", "fmtDQuoteClose", "fmtDQuoteOpen",
|
"doReplaceDots", "doReplaceSQuote", "emphLabels", "fmtApostrophe", "fmtDQuoteClose",
|
||||||
"fmtPadAfter", "fmtPadBefore", "fmtPadThin", "fmtSQuoteClose", "fmtSQuoteOpen",
|
"fmtDQuoteOpen", "fmtPadAfter", "fmtPadBefore", "fmtPadThin", "fmtSQuoteClose",
|
||||||
"focusWidth", "guiFont", "guiLocale", "guiSyntax", "guiTheme", "hasEnchant",
|
"fmtSQuoteOpen", "focusWidth", "guiFont", "guiLocale", "guiSyntax", "guiTheme",
|
||||||
"hideFocusFooter", "hideHScroll", "hideVScroll", "highlightEmph", "hostName",
|
"hasEnchant", "hideFocusFooter", "hideHScroll", "hideVScroll", "highlightEmph", "hostName",
|
||||||
"iconColDocs", "iconColTree", "iconTheme", "incNotesWCount", "isDebug", "kernelVer",
|
"iconColDocs", "iconColTree", "iconTheme", "incNotesWCount", "isDebug", "kernelVer",
|
||||||
"lastNotes", "mainPanePos", "mainWinSize", "memInfo", "narratorBreak", "narratorDialog",
|
"lastNotes", "mainPanePos", "mainWinSize", "memInfo", "narratorBreak", "narratorDialog",
|
||||||
"nativeFont", "osDarwin", "osLinux", "osType", "osUnknown", "osWindows", "outlinePanePos",
|
"nativeFont", "osDarwin", "osLinux", "osType", "osUnknown", "osWindows", "outlinePanePos",
|
||||||
@@ -149,6 +149,7 @@ class Config:
|
|||||||
|
|
||||||
self._recentProjects = RecentProjects(self)
|
self._recentProjects = RecentProjects(self)
|
||||||
self._recentPaths = RecentPaths(self)
|
self._recentPaths = RecentPaths(self)
|
||||||
|
self._lastAuthor = ""
|
||||||
|
|
||||||
# General GUI Settings
|
# General GUI Settings
|
||||||
self.guiLocale = self._qLocale.name()
|
self.guiLocale = self._qLocale.name()
|
||||||
@@ -321,6 +322,11 @@ class Config:
|
|||||||
def recentProjects(self) -> RecentProjects:
|
def recentProjects(self) -> RecentProjects:
|
||||||
return self._recentProjects
|
return self._recentProjects
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lastAuthor(self) -> str:
|
||||||
|
"""Return the last author name used."""
|
||||||
|
return simplified(self._lastAuthor)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Getters
|
# Getters
|
||||||
##
|
##
|
||||||
@@ -336,6 +342,11 @@ class Config:
|
|||||||
# Setters
|
# Setters
|
||||||
##
|
##
|
||||||
|
|
||||||
|
def setLastAuthor(self, value: str) -> None:
|
||||||
|
"""Set tle last used author name."""
|
||||||
|
self._lastAuthor = simplified(value)
|
||||||
|
return
|
||||||
|
|
||||||
def setMainWinSize(self, width: int, height: int) -> None:
|
def setMainWinSize(self, width: int, height: int) -> None:
|
||||||
"""Set the size of the main window, but only if the change is
|
"""Set the size of the main window, but only if the change is
|
||||||
larger than 5 pixels. The OS window manager will sometimes
|
larger than 5 pixels. The OS window manager will sometimes
|
||||||
@@ -467,11 +478,16 @@ class Config:
|
|||||||
|
|
||||||
def localDate(self, value: datetime) -> str:
|
def localDate(self, value: datetime) -> str:
|
||||||
"""Return a localised date format."""
|
"""Return a localised date format."""
|
||||||
return self._dLocale.toString(value, self._dShortDate)
|
# Explicitly convert the date first, see bug #2325
|
||||||
|
return self._dLocale.toString(QDate(value.year, value.month, value.day), self._dShortDate)
|
||||||
|
|
||||||
def localDateTime(self, value: datetime) -> str:
|
def localDateTime(self, value: datetime) -> str:
|
||||||
"""Return a localised datetime format."""
|
"""Return a localised datetime format."""
|
||||||
return self._dLocale.toString(value, self._dShortDateTime)
|
# Explicitly convert the datetime first, see bug #2325
|
||||||
|
return self._dLocale.toString(
|
||||||
|
QDateTime(value.year, value.month, value.day, value.hour, value.minute, value.second),
|
||||||
|
self._dShortDateTime,
|
||||||
|
)
|
||||||
|
|
||||||
def listLanguages(self, lngSet: int) -> list[tuple[str, str]]:
|
def listLanguages(self, lngSet: int) -> list[tuple[str, str]]:
|
||||||
"""List localisation files in the i18n folder. The default GUI
|
"""List localisation files in the i18n folder. The default GUI
|
||||||
@@ -640,6 +656,7 @@ class Config:
|
|||||||
self.backupOnClose = conf.rdBool(sec, "backuponclose", self.backupOnClose)
|
self.backupOnClose = conf.rdBool(sec, "backuponclose", self.backupOnClose)
|
||||||
self.askBeforeBackup = conf.rdBool(sec, "askbeforebackup", self.askBeforeBackup)
|
self.askBeforeBackup = conf.rdBool(sec, "askbeforebackup", self.askBeforeBackup)
|
||||||
self.askBeforeExit = conf.rdBool(sec, "askbeforeexit", self.askBeforeExit)
|
self.askBeforeExit = conf.rdBool(sec, "askbeforeexit", self.askBeforeExit)
|
||||||
|
self._lastAuthor = conf.rdStr(sec, "lastauthor", self._lastAuthor)
|
||||||
|
|
||||||
# Editor
|
# Editor
|
||||||
sec = "Editor"
|
sec = "Editor"
|
||||||
@@ -675,9 +692,9 @@ class Config:
|
|||||||
self.showFullPath = conf.rdBool(sec, "showfullpath", self.showFullPath)
|
self.showFullPath = conf.rdBool(sec, "showfullpath", self.showFullPath)
|
||||||
self.dialogStyle = conf.rdInt(sec, "dialogstyle", self.dialogStyle)
|
self.dialogStyle = conf.rdInt(sec, "dialogstyle", self.dialogStyle)
|
||||||
self.allowOpenDial = conf.rdBool(sec, "allowopendial", self.allowOpenDial)
|
self.allowOpenDial = conf.rdBool(sec, "allowopendial", self.allowOpenDial)
|
||||||
self.dialogLine = conf.rdStr(sec, "dialogline", self.dialogLine)
|
dialogLine = conf.rdStr(sec, "dialogline", self.dialogLine)
|
||||||
self.narratorBreak = conf.rdStr(sec, "narratorbreak", self.narratorBreak)
|
narratorBreak = conf.rdStr(sec, "narratorbreak", self.narratorBreak)
|
||||||
self.narratorDialog = conf.rdStr(sec, "narratordialog", self.narratorDialog)
|
narratorDialog = conf.rdStr(sec, "narratordialog", self.narratorDialog)
|
||||||
self.altDialogOpen = conf.rdStr(sec, "altdialogopen", self.altDialogOpen)
|
self.altDialogOpen = conf.rdStr(sec, "altdialogopen", self.altDialogOpen)
|
||||||
self.altDialogClose = conf.rdStr(sec, "altdialogclose", self.altDialogClose)
|
self.altDialogClose = conf.rdStr(sec, "altdialogclose", self.altDialogClose)
|
||||||
self.highlightEmph = conf.rdBool(sec, "highlightemph", self.highlightEmph)
|
self.highlightEmph = conf.rdBool(sec, "highlightemph", self.highlightEmph)
|
||||||
@@ -716,6 +733,10 @@ class Config:
|
|||||||
logger.info("Using straight double quotes, so disabling auto-replace")
|
logger.info("Using straight double quotes, so disabling auto-replace")
|
||||||
self.doReplaceDQuote = False
|
self.doReplaceDQuote = False
|
||||||
|
|
||||||
|
self.dialogLine = processDialogSymbols(dialogLine)
|
||||||
|
self.narratorBreak = narratorBreak if narratorBreak in nwQuotes.DASHES else ""
|
||||||
|
self.narratorDialog = narratorDialog if narratorDialog in nwQuotes.DASHES else ""
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def saveConfig(self) -> bool:
|
def saveConfig(self) -> bool:
|
||||||
@@ -760,6 +781,7 @@ class Config:
|
|||||||
"backuponclose": str(self.backupOnClose),
|
"backuponclose": str(self.backupOnClose),
|
||||||
"askbeforebackup": str(self.askBeforeBackup),
|
"askbeforebackup": str(self.askBeforeBackup),
|
||||||
"askbeforeexit": str(self.askBeforeExit),
|
"askbeforeexit": str(self.askBeforeExit),
|
||||||
|
"lastauthor": str(self._lastAuthor),
|
||||||
}
|
}
|
||||||
|
|
||||||
conf["Editor"] = {
|
conf["Editor"] = {
|
||||||
|
|||||||
@@ -505,6 +505,19 @@ class nwQuotes:
|
|||||||
"\u300f": QT_TRANSLATE_NOOP("Constant", "Right white corner bracket"),
|
"\u300f": QT_TRANSLATE_NOOP("Constant", "Right white corner bracket"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DASHES: Final[dict[str, str]] = {
|
||||||
|
"": QT_TRANSLATE_NOOP("Constant", "None"),
|
||||||
|
"\u2013": QT_TRANSLATE_NOOP("Constant", "Short dash"),
|
||||||
|
"\u2014": QT_TRANSLATE_NOOP("Constant", "Long dash"),
|
||||||
|
"\u2015": QT_TRANSLATE_NOOP("Constant", "Horizontal bar"),
|
||||||
|
}
|
||||||
|
|
||||||
|
ALLOWED: Final[list[str]] = [
|
||||||
|
"\u0027", "\u0022", "\u2018", "\u2019", "\u201a", "\u201b", "\u201c", "\u201d", "\u201e",
|
||||||
|
"\u201f", "\u2e42", "\u2039", "\u203a", "\u00ab", "\u00bb", "\u300c", "\u300d", "\u300e",
|
||||||
|
"\u300f", "\u2013", "\u2014", "\u2015",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class nwUnicode:
|
class nwUnicode:
|
||||||
"""Supported unicode character constants and their HTML equivalents."""
|
"""Supported unicode character constants and their HTML equivalents."""
|
||||||
|
|||||||
@@ -383,10 +383,12 @@ class ProjectBuilder:
|
|||||||
"""Build or copy a project from a data dictionary."""
|
"""Build or copy a project from a data dictionary."""
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
path = data.get("path", None) or None
|
path = data.get("path", None) or None
|
||||||
|
if author := data.get("author"):
|
||||||
|
CONFIG.setLastAuthor(author)
|
||||||
if isinstance(path, str | Path):
|
if isinstance(path, str | Path):
|
||||||
self._path = Path(path).resolve()
|
self._path = Path(path).resolve()
|
||||||
if data.get("sample"):
|
if data.get("sample"):
|
||||||
return self._extractSampleProject(self._path)
|
return self._extractSampleProject(self._path, data)
|
||||||
elif data.get("template"):
|
elif data.get("template"):
|
||||||
return self._copyProject(self._path, data)
|
return self._copyProject(self._path, data)
|
||||||
else:
|
else:
|
||||||
@@ -416,20 +418,21 @@ class ProjectBuilder:
|
|||||||
|
|
||||||
self._path = project.storage.storagePath
|
self._path = project.storage.storagePath
|
||||||
|
|
||||||
lblNewProject = self.tr("New Project")
|
trName = self.tr("New Project")
|
||||||
lblTitlePage = self.tr("Title Page")
|
trAuthor = self.tr("Author Name")
|
||||||
|
trTitlePage = self.tr("Title Page")
|
||||||
|
|
||||||
# Settings
|
# Settings
|
||||||
project.data.setUuid(None)
|
project.data.setUuid(None)
|
||||||
project.data.setName(data.get("name", lblNewProject))
|
project.data.setName(data.get("name", trName))
|
||||||
project.data.setAuthor(data.get("author", ""))
|
project.data.setAuthor(data.get("author", trAuthor))
|
||||||
project.data.setLanguage(CONFIG.guiLocale)
|
project.data.setLanguage(CONFIG.guiLocale)
|
||||||
project.setDefaultStatusImport()
|
project.setDefaultStatusImport()
|
||||||
project.session.startSession()
|
project.session.startSession()
|
||||||
|
|
||||||
# Add Root Folders
|
# Add Root Folders
|
||||||
hNovelRoot = project.newRoot(nwItemClass.NOVEL)
|
hNovelRoot = project.newRoot(nwItemClass.NOVEL)
|
||||||
hTitlePage = project.newFile(lblTitlePage, hNovelRoot)
|
hTitlePage = project.newFile(trTitlePage, hNovelRoot)
|
||||||
|
|
||||||
# Generate Title Page
|
# Generate Title Page
|
||||||
aDoc = project.storage.getDocument(hTitlePage)
|
aDoc = project.storage.getDocument(hTitlePage)
|
||||||
@@ -446,25 +449,21 @@ class ProjectBuilder:
|
|||||||
"\n"
|
"\n"
|
||||||
">> {count}: [field:{field}] <<\n"
|
">> {count}: [field:{field}] <<\n"
|
||||||
).format(
|
).format(
|
||||||
author=project.data.author or "None",
|
author=project.data.author or trAuthor,
|
||||||
address=self.tr("Address"),
|
address=self.tr("Address Line"),
|
||||||
title=project.data.name or "None",
|
title=project.data.name or trName,
|
||||||
by=self.tr("By"),
|
by=self.tr("By"),
|
||||||
count=self.tr("Word Count"),
|
count=self.tr("Word Count"),
|
||||||
field=nwStats.WORDS_TEXT,
|
field=nwStats.WORDS_TEXT,
|
||||||
))
|
))
|
||||||
|
|
||||||
# Create a project structure based on selected root folders
|
|
||||||
# and a number of chapters and scenes selected in the
|
|
||||||
# wizard's custom page.
|
|
||||||
|
|
||||||
# Create chapters and scenes
|
# Create chapters and scenes
|
||||||
numChapters = data.get("chapters", 0)
|
numChapters = data.get("chapters", 0)
|
||||||
numScenes = data.get("scenes", 0)
|
numScenes = data.get("scenes", 0)
|
||||||
|
|
||||||
chSynop = self.tr("Summary of the chapter.")
|
trChSynop = self.tr("Summary of the chapter.")
|
||||||
scSynop = self.tr("Summary of the scene.")
|
trScSynop = self.tr("Summary of the scene.")
|
||||||
bfNote = self.tr("A short description.")
|
trNoteDesc = self.tr("A short description.")
|
||||||
|
|
||||||
# Create chapters
|
# Create chapters
|
||||||
if numChapters > 0:
|
if numChapters > 0:
|
||||||
@@ -472,7 +471,7 @@ class ProjectBuilder:
|
|||||||
chTitle = self.tr("Chapter {0}").format(f"{ch+1:d}")
|
chTitle = self.tr("Chapter {0}").format(f"{ch+1:d}")
|
||||||
cHandle = project.newFile(chTitle, hNovelRoot)
|
cHandle = project.newFile(chTitle, hNovelRoot)
|
||||||
aDoc = project.storage.getDocument(cHandle)
|
aDoc = project.storage.getDocument(cHandle)
|
||||||
aDoc.writeDocument(f"## {chTitle}\n\n%Synopsis: {chSynop}\n\n")
|
aDoc.writeDocument(f"## {chTitle}\n\n%Synopsis: {trChSynop}\n\n")
|
||||||
|
|
||||||
# Create chapter scenes
|
# Create chapter scenes
|
||||||
if numScenes > 0 and cHandle:
|
if numScenes > 0 and cHandle:
|
||||||
@@ -480,7 +479,7 @@ class ProjectBuilder:
|
|||||||
scTitle = self.tr("Scene {0}").format(f"{ch+1:d}.{sc+1:d}")
|
scTitle = self.tr("Scene {0}").format(f"{ch+1:d}.{sc+1:d}")
|
||||||
sHandle = project.newFile(scTitle, cHandle)
|
sHandle = project.newFile(scTitle, cHandle)
|
||||||
aDoc = project.storage.getDocument(sHandle)
|
aDoc = project.storage.getDocument(sHandle)
|
||||||
aDoc.writeDocument(f"### {scTitle}\n\n%Synopsis: {scSynop}\n\n")
|
aDoc.writeDocument(f"### {scTitle}\n\n%Synopsis: {trScSynop}\n\n")
|
||||||
|
|
||||||
# Create scenes (no chapters)
|
# Create scenes (no chapters)
|
||||||
elif numScenes > 0:
|
elif numScenes > 0:
|
||||||
@@ -488,7 +487,7 @@ class ProjectBuilder:
|
|||||||
scTitle = self.tr("Scene {0}").format(f"{sc+1:d}")
|
scTitle = self.tr("Scene {0}").format(f"{sc+1:d}")
|
||||||
sHandle = project.newFile(scTitle, hNovelRoot)
|
sHandle = project.newFile(scTitle, hNovelRoot)
|
||||||
aDoc = project.storage.getDocument(sHandle)
|
aDoc = project.storage.getDocument(sHandle)
|
||||||
aDoc.writeDocument(f"### {scTitle}\n\n%Synopsis: {scSynop}\n\n")
|
aDoc.writeDocument(f"### {scTitle}\n\n%Synopsis: {trScSynop}\n\n")
|
||||||
|
|
||||||
# Create notes folders
|
# Create notes folders
|
||||||
noteTitles = {
|
noteTitles = {
|
||||||
@@ -508,7 +507,7 @@ class ProjectBuilder:
|
|||||||
aDoc.writeDocument(
|
aDoc.writeDocument(
|
||||||
f"# {noteTitles[newRoot]}\n\n"
|
f"# {noteTitles[newRoot]}\n\n"
|
||||||
f"@tag: {ntTag}\n\n"
|
f"@tag: {ntTag}\n\n"
|
||||||
f"%Short: {bfNote}\n\n"
|
f"%Short: {trNoteDesc}\n\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Also add the archive and trash folders
|
# Also add the archive and trash folders
|
||||||
@@ -563,23 +562,11 @@ class ProjectBuilder:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# Open the copied project and update settings
|
# Open the copied project and update settings
|
||||||
project = NWProject()
|
self._resetProject(dstPath, data)
|
||||||
project.openProject(dstPath)
|
|
||||||
project.data.setUuid("") # Creates a fresh uuid
|
|
||||||
project.data.setName(data.get("name", "None"))
|
|
||||||
project.data.setAuthor(data.get("author", ""))
|
|
||||||
project.data.setSpellCheck(True)
|
|
||||||
project.data.setSpellLang(None)
|
|
||||||
project.data.setDoBackup(True)
|
|
||||||
project.data.setSaveCount(0)
|
|
||||||
project.data.setAutoCount(0)
|
|
||||||
project.data.setEditTime(0)
|
|
||||||
project.saveProject()
|
|
||||||
project.closeProject()
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _extractSampleProject(self, path: Path) -> bool:
|
def _extractSampleProject(self, path: Path, data: dict) -> bool:
|
||||||
"""Make a copy of the sample project by extracting the
|
"""Make a copy of the sample project by extracting the
|
||||||
sample.zip file to the new path.
|
sample.zip file to the new path.
|
||||||
"""
|
"""
|
||||||
@@ -593,6 +580,7 @@ class ProjectBuilder:
|
|||||||
if (sample := CONFIG.assetPath("sample.zip")).is_file():
|
if (sample := CONFIG.assetPath("sample.zip")).is_file():
|
||||||
try:
|
try:
|
||||||
shutil.unpack_archive(sample, path)
|
shutil.unpack_archive(sample, path)
|
||||||
|
self._resetProject(path, data)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
SHARED.error(self.tr("Failed to create a new example project."), exc=exc)
|
SHARED.error(self.tr("Failed to create a new example project."), exc=exc)
|
||||||
return False
|
return False
|
||||||
@@ -605,3 +593,22 @@ class ProjectBuilder:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _resetProject(self, path: Path, data: dict) -> None:
|
||||||
|
"""Open a project and reset/update its settings."""
|
||||||
|
project = NWProject()
|
||||||
|
project.openProject(path)
|
||||||
|
project.data.setUuid("") # Creates a fresh uuid
|
||||||
|
if name := data.get("name", ""):
|
||||||
|
project.data.setName(name)
|
||||||
|
if author := data.get("author", ""):
|
||||||
|
project.data.setAuthor(author)
|
||||||
|
project.data.setSpellCheck(True)
|
||||||
|
project.data.setSpellLang(None)
|
||||||
|
project.data.setDoBackup(True)
|
||||||
|
project.data.setSaveCount(0)
|
||||||
|
project.data.setAutoCount(0)
|
||||||
|
project.data.setEditTime(0)
|
||||||
|
project.saveProject()
|
||||||
|
project.closeProject()
|
||||||
|
return
|
||||||
|
|||||||
@@ -45,16 +45,18 @@ logger = logging.getLogger(__name__)
|
|||||||
INV_ROOT = "invisibleRoot"
|
INV_ROOT = "invisibleRoot"
|
||||||
C_FACTOR = 0x0100
|
C_FACTOR = 0x0100
|
||||||
|
|
||||||
C_LABEL_TEXT = 0x0000 | Qt.ItemDataRole.DisplayRole
|
C_LABEL_TEXT = 0x0000 | Qt.ItemDataRole.DisplayRole
|
||||||
C_LABEL_ICON = 0x0000 | Qt.ItemDataRole.DecorationRole
|
C_LABEL_ICON = 0x0000 | Qt.ItemDataRole.DecorationRole
|
||||||
C_LABEL_FONT = 0x0000 | Qt.ItemDataRole.FontRole
|
C_LABEL_FONT = 0x0000 | Qt.ItemDataRole.FontRole
|
||||||
C_COUNT_TEXT = 0x0100 | Qt.ItemDataRole.DisplayRole
|
C_COUNT_TEXT = 0x0100 | Qt.ItemDataRole.DisplayRole
|
||||||
C_COUNT_ICON = 0x0100 | Qt.ItemDataRole.DecorationRole
|
C_COUNT_ICON = 0x0100 | Qt.ItemDataRole.DecorationRole
|
||||||
C_COUNT_ALIGN = 0x0100 | Qt.ItemDataRole.TextAlignmentRole
|
C_COUNT_ALIGN = 0x0100 | Qt.ItemDataRole.TextAlignmentRole
|
||||||
C_ACTIVE_ICON = 0x0200 | Qt.ItemDataRole.DecorationRole
|
C_ACTIVE_ICON = 0x0200 | Qt.ItemDataRole.DecorationRole
|
||||||
C_ACTIVE_TIP = 0x0200 | Qt.ItemDataRole.ToolTipRole
|
C_ACTIVE_TIP = 0x0200 | Qt.ItemDataRole.ToolTipRole
|
||||||
C_STATUS_ICON = 0x0300 | Qt.ItemDataRole.DecorationRole
|
C_ACTIVE_ACCESS = 0x0200 | Qt.ItemDataRole.AccessibleTextRole
|
||||||
C_STATUS_TIP = 0x0300 | Qt.ItemDataRole.ToolTipRole
|
C_STATUS_ICON = 0x0300 | Qt.ItemDataRole.DecorationRole
|
||||||
|
C_STATUS_TIP = 0x0300 | Qt.ItemDataRole.ToolTipRole
|
||||||
|
C_STATUS_ACCESS = 0x0300 | Qt.ItemDataRole.AccessibleTextRole
|
||||||
|
|
||||||
NODE_FLAGS = Qt.ItemFlag.ItemIsEnabled
|
NODE_FLAGS = Qt.ItemFlag.ItemIsEnabled
|
||||||
NODE_FLAGS |= Qt.ItemFlag.ItemIsSelectable
|
NODE_FLAGS |= Qt.ItemFlag.ItemIsSelectable
|
||||||
@@ -150,13 +152,15 @@ class ProjectNode:
|
|||||||
|
|
||||||
# Active
|
# Active
|
||||||
aText, aIcon = self._item.getActiveStatus()
|
aText, aIcon = self._item.getActiveStatus()
|
||||||
self._cache[C_ACTIVE_TIP] = aText
|
|
||||||
self._cache[C_ACTIVE_ICON] = aIcon
|
self._cache[C_ACTIVE_ICON] = aIcon
|
||||||
|
self._cache[C_ACTIVE_TIP] = aText
|
||||||
|
self._cache[C_ACTIVE_ACCESS] = aText
|
||||||
|
|
||||||
# Status
|
# Status
|
||||||
sText, sIcon = self._item.getImportStatus()
|
sText, sIcon = self._item.getImportStatus()
|
||||||
self._cache[C_STATUS_TIP] = sText
|
|
||||||
self._cache[C_STATUS_ICON] = sIcon
|
self._cache[C_STATUS_ICON] = sIcon
|
||||||
|
self._cache[C_STATUS_TIP] = sText
|
||||||
|
self._cache[C_STATUS_ACCESS] = sText
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ R_TEXT = Qt.ItemDataRole.DisplayRole
|
|||||||
R_ICON = Qt.ItemDataRole.DecorationRole
|
R_ICON = Qt.ItemDataRole.DecorationRole
|
||||||
R_ALIGN = Qt.ItemDataRole.TextAlignmentRole
|
R_ALIGN = Qt.ItemDataRole.TextAlignmentRole
|
||||||
R_TIP = Qt.ItemDataRole.ToolTipRole
|
R_TIP = Qt.ItemDataRole.ToolTipRole
|
||||||
|
R_ACCESS = Qt.ItemDataRole.AccessibleTextRole
|
||||||
R_HANDLE = 0xff01
|
R_HANDLE = 0xff01
|
||||||
R_KEY = 0xff02
|
R_KEY = 0xff02
|
||||||
|
|
||||||
@@ -217,6 +218,7 @@ class NovelModel(QAbstractTableModel):
|
|||||||
text = ", ".join(refs)
|
text = ", ".join(refs)
|
||||||
data[C_FACTOR*2 | R_TEXT] = text
|
data[C_FACTOR*2 | R_TEXT] = text
|
||||||
data[C_FACTOR*2 | R_TIP] = f"<b>{self._extraLabel}:</b> {text}"
|
data[C_FACTOR*2 | R_TIP] = f"<b>{self._extraLabel}:</b> {text}"
|
||||||
|
data[C_FACTOR*2 | R_ACCESS] = f"{self._extraLabel}: {text}"
|
||||||
data[C_FACTOR*3 | R_ICON] = self._more
|
data[C_FACTOR*3 | R_ICON] = self._more
|
||||||
data[R_HANDLE] = handle
|
data[R_HANDLE] = handle
|
||||||
data[R_KEY] = key
|
data[R_KEY] = key
|
||||||
|
|||||||
@@ -483,14 +483,14 @@ class NWProject:
|
|||||||
|
|
||||||
def setDefaultStatusImport(self) -> None:
|
def setDefaultStatusImport(self) -> None:
|
||||||
"""Set the default status and importance values."""
|
"""Set the default status and importance values."""
|
||||||
self._data.itemStatus.add(None, self.tr("New"), (100, 100, 100), "SQUARE", 0)
|
self._data.itemStatus.add(None, self.tr("New"), (120, 120, 120), "STAR", 0)
|
||||||
self._data.itemStatus.add(None, self.tr("Note"), (200, 50, 0), "SQUARE", 0)
|
self._data.itemStatus.add(None, self.tr("Note"), (205, 171, 143), "TRIANGLE", 0)
|
||||||
self._data.itemStatus.add(None, self.tr("Draft"), (200, 150, 0), "SQUARE", 0)
|
self._data.itemStatus.add(None, self.tr("Draft"), (143, 240, 164), "CIRCLE_T", 0)
|
||||||
self._data.itemStatus.add(None, self.tr("Finished"), (50, 200, 0), "SQUARE", 0)
|
self._data.itemStatus.add(None, self.tr("Finished"), (249, 240, 107), "STAR", 0)
|
||||||
self._data.itemImport.add(None, self.tr("New"), (100, 100, 100), "SQUARE", 0)
|
self._data.itemImport.add(None, self.tr("New"), (120, 120, 120), "SQUARE", 0)
|
||||||
self._data.itemImport.add(None, self.tr("Minor"), (200, 50, 0), "SQUARE", 0)
|
self._data.itemImport.add(None, self.tr("Minor"), (220, 138, 221), "BLOCK_2", 0)
|
||||||
self._data.itemImport.add(None, self.tr("Major"), (200, 150, 0), "SQUARE", 0)
|
self._data.itemImport.add(None, self.tr("Major"), (220, 138, 221), "BLOCK_3", 0)
|
||||||
self._data.itemImport.add(None, self.tr("Main"), (50, 200, 0), "SQUARE", 0)
|
self._data.itemImport.add(None, self.tr("Main"), (220, 138, 221), "BLOCK_4", 0)
|
||||||
return
|
return
|
||||||
|
|
||||||
def setProjectLang(self, language: str | None) -> None:
|
def setProjectLang(self, language: str | None) -> None:
|
||||||
|
|||||||
@@ -73,8 +73,9 @@ class GuiDocMerge(NDialog):
|
|||||||
self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
|
self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
|
||||||
|
|
||||||
# Merge Options
|
# Merge Options
|
||||||
self.trashLabel = QLabel(self.tr("Move merged items to Trash"), self)
|
|
||||||
self.trashSwitch = NSwitch(self, height=iPx)
|
self.trashSwitch = NSwitch(self, height=iPx)
|
||||||
|
self.trashLabel = QLabel(self.tr("Move merged items to Trash"), self)
|
||||||
|
self.trashLabel.setBuddy(self.trashSwitch)
|
||||||
|
|
||||||
self.optBox = QGridLayout()
|
self.optBox = QGridLayout()
|
||||||
self.optBox.addWidget(self.trashLabel, 0, 0)
|
self.optBox.addWidget(self.trashLabel, 0, 0)
|
||||||
|
|||||||
@@ -90,16 +90,19 @@ class GuiDocSplit(NDialog):
|
|||||||
self.splitLevel.currentIndexChanged.connect(self._reloadList)
|
self.splitLevel.currentIndexChanged.connect(self._reloadList)
|
||||||
|
|
||||||
# Split Options
|
# Split Options
|
||||||
self.folderLabel = QLabel(self.tr("Split into a new folder"), self)
|
|
||||||
self.folderSwitch = NSwitch(self, height=iPx)
|
self.folderSwitch = NSwitch(self, height=iPx)
|
||||||
self.folderSwitch.setChecked(intoFolder)
|
self.folderSwitch.setChecked(intoFolder)
|
||||||
|
self.folderLabel = QLabel(self.tr("Split into a new folder"), self)
|
||||||
|
self.folderLabel.setBuddy(self.folderSwitch)
|
||||||
|
|
||||||
self.hierarchyLabel = QLabel(self.tr("Create document hierarchy"), self)
|
|
||||||
self.hierarchySwitch = NSwitch(self, height=iPx)
|
self.hierarchySwitch = NSwitch(self, height=iPx)
|
||||||
self.hierarchySwitch.setChecked(docHierarchy)
|
self.hierarchySwitch.setChecked(docHierarchy)
|
||||||
|
self.hierarchyLabel = QLabel(self.tr("Create document hierarchy"), self)
|
||||||
|
self.hierarchyLabel.setBuddy(self.hierarchySwitch)
|
||||||
|
|
||||||
self.trashLabel = QLabel(self.tr("Move split document to Trash"), self)
|
|
||||||
self.trashSwitch = NSwitch(self, height=iPx)
|
self.trashSwitch = NSwitch(self, height=iPx)
|
||||||
|
self.trashLabel = QLabel(self.tr("Move split document to Trash"), self)
|
||||||
|
self.trashLabel.setBuddy(self.trashSwitch)
|
||||||
|
|
||||||
self.optBox = QGridLayout()
|
self.optBox = QGridLayout()
|
||||||
self.optBox.addWidget(self.folderLabel, 0, 0)
|
self.optBox.addWidget(self.folderLabel, 0, 0)
|
||||||
|
|||||||
@@ -43,11 +43,14 @@ class GuiEditLabel(NDialog):
|
|||||||
self.setWindowTitle(self.tr("Item Label"))
|
self.setWindowTitle(self.tr("Item Label"))
|
||||||
|
|
||||||
# Item Label
|
# Item Label
|
||||||
self.labelValue = QLineEdit(self)
|
self.edtValue = QLineEdit(self)
|
||||||
self.labelValue.setMinimumWidth(220)
|
self.edtValue.setMinimumWidth(220)
|
||||||
self.labelValue.setMaxLength(200)
|
self.edtValue.setMaxLength(200)
|
||||||
self.labelValue.setText(text)
|
self.edtValue.setText(text)
|
||||||
self.labelValue.selectAll()
|
self.edtValue.selectAll()
|
||||||
|
|
||||||
|
self.lblValue = QLabel(self.tr("Label"), self)
|
||||||
|
self.lblValue.setBuddy(self.lblValue)
|
||||||
|
|
||||||
# Buttons
|
# Buttons
|
||||||
self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
|
self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
|
||||||
@@ -56,8 +59,8 @@ class GuiEditLabel(NDialog):
|
|||||||
|
|
||||||
# Assemble
|
# Assemble
|
||||||
self.innerBox = QHBoxLayout()
|
self.innerBox = QHBoxLayout()
|
||||||
self.innerBox.addWidget(QLabel(self.tr("Label"), self), 0)
|
self.innerBox.addWidget(self.lblValue, 0)
|
||||||
self.innerBox.addWidget(self.labelValue, 1)
|
self.innerBox.addWidget(self.edtValue, 1)
|
||||||
self.innerBox.setSpacing(12)
|
self.innerBox.setSpacing(12)
|
||||||
|
|
||||||
self.outerBox = QVBoxLayout()
|
self.outerBox = QVBoxLayout()
|
||||||
@@ -77,7 +80,7 @@ class GuiEditLabel(NDialog):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def itemLabel(self) -> str:
|
def itemLabel(self) -> str:
|
||||||
return self.labelValue.text()
|
return self.edtValue.text()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getLabel(cls, parent: QWidget, text: str) -> tuple[str, bool]:
|
def getLabel(cls, parent: QWidget, text: str) -> tuple[str, bool]:
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ from PyQt6.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.common import compact, describeFont, uniqueCompact
|
from novelwriter.common import compact, describeFont, processDialogSymbols, uniqueCompact
|
||||||
from novelwriter.config import DEF_GUI, DEF_ICONS, DEF_SYNTAX, DEF_TREECOL
|
from novelwriter.config import DEF_GUI, DEF_ICONS, DEF_SYNTAX, DEF_TREECOL
|
||||||
from novelwriter.constants import nwLabels, nwUnicode, trConst
|
from novelwriter.constants import nwLabels, nwQuotes, nwUnicode, trConst
|
||||||
from novelwriter.dialogs.quotes import GuiQuoteSelect
|
from novelwriter.dialogs.quotes import GuiQuoteSelect
|
||||||
from novelwriter.extensions.configlayout import NColorLabel, NScrollableForm
|
from novelwriter.extensions.configlayout import NColorLabel, NScrollableForm
|
||||||
from novelwriter.extensions.modified import (
|
from novelwriter.extensions.modified import (
|
||||||
@@ -80,6 +80,7 @@ class GuiPreferences(NDialog):
|
|||||||
# SideBar
|
# SideBar
|
||||||
self.sidebar = NPagedSideBar(self)
|
self.sidebar = NPagedSideBar(self)
|
||||||
self.sidebar.setLabelColor(SHARED.theme.helpText)
|
self.sidebar.setLabelColor(SHARED.theme.helpText)
|
||||||
|
self.sidebar.setAccessibleName(self.titleLabel.text())
|
||||||
self.sidebar.buttonClicked.connect(self._sidebarClicked)
|
self.sidebar.buttonClicked.connect(self._sidebarClicked)
|
||||||
|
|
||||||
# Form
|
# Form
|
||||||
@@ -644,21 +645,20 @@ class GuiPreferences(NDialog):
|
|||||||
self.tr("Lines starting with any of these symbols are dialogue.")
|
self.tr("Lines starting with any of these symbols are dialogue.")
|
||||||
)
|
)
|
||||||
|
|
||||||
self.narratorBreak = QLineEdit(self)
|
self.narratorBreak = NComboBox(self)
|
||||||
self.narratorBreak.setMaxLength(1)
|
self.narratorDialog = NComboBox(self)
|
||||||
self.narratorBreak.setFixedWidth(boxFixed)
|
for key, value in nwQuotes.DASHES.items():
|
||||||
self.narratorBreak.setAlignment(QtAlignCenter)
|
label = trConst(value)
|
||||||
self.narratorBreak.setText(CONFIG.narratorBreak)
|
self.narratorBreak.addItem(label, key)
|
||||||
|
self.narratorDialog.addItem(label, key)
|
||||||
|
|
||||||
|
self.narratorBreak.setCurrentData(CONFIG.narratorBreak, "")
|
||||||
|
self.narratorDialog.setCurrentData(CONFIG.narratorDialog, "")
|
||||||
|
|
||||||
self.mainForm.addRow(
|
self.mainForm.addRow(
|
||||||
self.tr("Narrator break symbol"), self.narratorBreak,
|
self.tr("Narrator break symbol"), self.narratorBreak,
|
||||||
self.tr("Symbol to indicate a narrator break in dialogue.")
|
self.tr("Symbol to indicate a narrator break in dialogue.")
|
||||||
)
|
)
|
||||||
|
|
||||||
self.narratorDialog = QLineEdit(self)
|
|
||||||
self.narratorDialog.setMaxLength(1)
|
|
||||||
self.narratorDialog.setFixedWidth(boxFixed)
|
|
||||||
self.narratorDialog.setAlignment(QtAlignCenter)
|
|
||||||
self.narratorDialog.setText(CONFIG.narratorDialog)
|
|
||||||
self.mainForm.addRow(
|
self.mainForm.addRow(
|
||||||
self.tr("Alternating dialogue/narration symbol"), self.narratorDialog,
|
self.tr("Alternating dialogue/narration symbol"), self.narratorDialog,
|
||||||
self.tr("Alternates dialogue highlighting within any paragraph.")
|
self.tr("Alternates dialogue highlighting within any paragraph.")
|
||||||
@@ -1045,9 +1045,9 @@ class GuiPreferences(NDialog):
|
|||||||
# Text Highlighting
|
# Text Highlighting
|
||||||
dialogueStyle = self.dialogStyle.currentData()
|
dialogueStyle = self.dialogStyle.currentData()
|
||||||
allowOpenDial = self.allowOpenDial.isChecked()
|
allowOpenDial = self.allowOpenDial.isChecked()
|
||||||
dialogueLine = uniqueCompact(self.dialogLine.text())
|
dialogueLine = processDialogSymbols(self.dialogLine.text())
|
||||||
narratorBreak = self.narratorBreak.text().strip()
|
narratorBreak = self.narratorBreak.currentData()
|
||||||
narratorDialog = self.narratorDialog.text().strip()
|
narratorDialog = self.narratorDialog.currentData()
|
||||||
altDialogOpen = compact(self.altDialogOpen.text())
|
altDialogOpen = compact(self.altDialogOpen.text())
|
||||||
altDialogClose = compact(self.altDialogClose.text())
|
altDialogClose = compact(self.altDialogClose.text())
|
||||||
highlightEmph = self.highlightEmph.isChecked()
|
highlightEmph = self.highlightEmph.isChecked()
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ class GuiProjectSettings(NDialog):
|
|||||||
# SideBar
|
# SideBar
|
||||||
self.sidebar = NPagedSideBar(self)
|
self.sidebar = NPagedSideBar(self)
|
||||||
self.sidebar.setLabelColor(SHARED.theme.helpText)
|
self.sidebar.setLabelColor(SHARED.theme.helpText)
|
||||||
|
self.sidebar.setAccessibleName(self.titleLabel.text())
|
||||||
self.sidebar.addButton(self.tr("Settings"), self.PAGE_SETTINGS)
|
self.sidebar.addButton(self.tr("Settings"), self.PAGE_SETTINGS)
|
||||||
self.sidebar.addButton(self.tr("Status"), self.PAGE_STATUS)
|
self.sidebar.addButton(self.tr("Status"), self.PAGE_STATUS)
|
||||||
self.sidebar.addButton(self.tr("Importance"), self.PAGE_IMPORT)
|
self.sidebar.addButton(self.tr("Importance"), self.PAGE_IMPORT)
|
||||||
@@ -349,6 +350,7 @@ class _StatusPage(NFixedPage):
|
|||||||
self.listBox.setHeaderLabels([self.tr("Label"), self.tr("Usage")])
|
self.listBox.setHeaderLabels([self.tr("Label"), self.tr("Usage")])
|
||||||
self.listBox.setColumnWidth(self.C_LABEL, wCol0)
|
self.listBox.setColumnWidth(self.C_LABEL, wCol0)
|
||||||
self.listBox.setIndentation(0)
|
self.listBox.setIndentation(0)
|
||||||
|
self.listBox.setAccessibleName(pageLabel)
|
||||||
self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||||
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||||
self.listBox.itemSelectionChanged.connect(self._onSelectionChanged)
|
self.listBox.itemSelectionChanged.connect(self._onSelectionChanged)
|
||||||
@@ -686,6 +688,7 @@ class _ReplacePage(NFixedPage):
|
|||||||
self.listBox.setHeaderLabels([self.tr("Keyword"), self.tr("Replace With")])
|
self.listBox.setHeaderLabels([self.tr("Keyword"), self.tr("Replace With")])
|
||||||
self.listBox.setColumnWidth(self.C_KEY, wCol0)
|
self.listBox.setColumnWidth(self.C_KEY, wCol0)
|
||||||
self.listBox.setIndentation(0)
|
self.listBox.setIndentation(0)
|
||||||
|
self.listBox.setAccessibleName(self.pageTitle.text())
|
||||||
self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||||
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||||
self.listBox.itemSelectionChanged.connect(self._onSelectionChanged)
|
self.listBox.itemSelectionChanged.connect(self._onSelectionChanged)
|
||||||
|
|||||||
@@ -211,7 +211,8 @@ class NScrollableForm(QScrollArea):
|
|||||||
else:
|
else:
|
||||||
qWidget = widget
|
qWidget = widget
|
||||||
|
|
||||||
qLabel = QLabel(label or "", self)
|
text = label or ""
|
||||||
|
qLabel = QLabel(text, self)
|
||||||
qLabel.setIndent(self._indent)
|
qLabel.setIndent(self._indent)
|
||||||
qLabel.setBuddy(qWidget)
|
qLabel.setBuddy(qWidget)
|
||||||
|
|
||||||
@@ -227,6 +228,7 @@ class NScrollableForm(QScrollArea):
|
|||||||
row.addLayout(labelBox, stretch[0])
|
row.addLayout(labelBox, stretch[0])
|
||||||
if editable:
|
if editable:
|
||||||
self._editable[editable] = qHelp
|
self._editable[editable] = qHelp
|
||||||
|
text = f"{text}: {helpText}"
|
||||||
else:
|
else:
|
||||||
row.addWidget(qLabel, stretch[0])
|
row.addWidget(qLabel, stretch[0])
|
||||||
|
|
||||||
@@ -235,6 +237,7 @@ class NScrollableForm(QScrollArea):
|
|||||||
box.addWidget(qWidget, 1)
|
box.addWidget(qWidget, 1)
|
||||||
box.addWidget(QLabel(unit, self), 0)
|
box.addWidget(QLabel(unit, self), 0)
|
||||||
row.addLayout(box, stretch[1])
|
row.addLayout(box, stretch[1])
|
||||||
|
text = f"{text} Unit: {unit}"
|
||||||
elif isinstance(button, QAbstractButton):
|
elif isinstance(button, QAbstractButton):
|
||||||
box = QHBoxLayout()
|
box = QHBoxLayout()
|
||||||
box.addWidget(qWidget, 1)
|
box.addWidget(qWidget, 1)
|
||||||
@@ -243,10 +246,11 @@ class NScrollableForm(QScrollArea):
|
|||||||
else:
|
else:
|
||||||
row.addWidget(qWidget, stretch[1])
|
row.addWidget(qWidget, stretch[1])
|
||||||
|
|
||||||
|
self._first = False
|
||||||
self._layout.addLayout(row)
|
self._layout.addLayout(row)
|
||||||
if label:
|
if label:
|
||||||
self._index[label.strip()] = qWidget
|
self._index[label.strip()] = qWidget
|
||||||
self._first = False
|
qLabel.setAccessibleName(text)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from PyQt6.QtCore import QPropertyAnimation, Qt, pyqtProperty # pyright: ignore
|
from PyQt6.QtCore import QPropertyAnimation, Qt, pyqtProperty, pyqtSlot # pyright: ignore
|
||||||
from PyQt6.QtGui import QEnterEvent, QMouseEvent, QPainter, QPaintEvent, QResizeEvent
|
from PyQt6.QtGui import QEnterEvent, QPainter, QPaintEvent, QResizeEvent
|
||||||
from PyQt6.QtWidgets import QAbstractButton, QWidget
|
from PyQt6.QtWidgets import QAbstractButton, QWidget
|
||||||
|
|
||||||
from novelwriter import SHARED
|
from novelwriter import SHARED
|
||||||
from novelwriter.types import QtMouseLeft, QtNoPen, QtPaintAntiAlias, QtSizeFixed
|
from novelwriter.types import QtNoPen, QtPaintAntiAlias, QtSizeFixed
|
||||||
|
|
||||||
|
|
||||||
class NSwitch(QAbstractButton):
|
class NSwitch(QAbstractButton):
|
||||||
@@ -50,6 +50,8 @@ class NSwitch(QAbstractButton):
|
|||||||
self.setFixedHeight(self._xH)
|
self.setFixedHeight(self._xH)
|
||||||
self._offset = self._xR
|
self._offset = self._xR
|
||||||
|
|
||||||
|
self.clicked.connect(self._onClick)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -94,7 +96,7 @@ class NSwitch(QAbstractButton):
|
|||||||
painter.setRenderHint(QtPaintAntiAlias, True)
|
painter.setRenderHint(QtPaintAntiAlias, True)
|
||||||
painter.setOpacity(1.0 if self.isEnabled() else 0.5)
|
painter.setOpacity(1.0 if self.isEnabled() else 0.5)
|
||||||
|
|
||||||
painter.setPen(palette.mid().color())
|
painter.setPen(palette.highlight().color() if self.hasFocus() else palette.mid().color())
|
||||||
painter.setBrush(palette.highlight() if self.isChecked() else palette.alternateBase())
|
painter.setBrush(palette.highlight() if self.isChecked() else palette.alternateBase())
|
||||||
painter.drawRoundedRect(0, 0, self._xW, self._xH, self._xR, self._xR)
|
painter.drawRoundedRect(0, 0, self._xW, self._xH, self._xR, self._xR)
|
||||||
|
|
||||||
@@ -106,19 +108,18 @@ class NSwitch(QAbstractButton):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
|
|
||||||
"""Animate the switch on mouse release."""
|
|
||||||
super().mouseReleaseEvent(event)
|
|
||||||
if event.button() == QtMouseLeft:
|
|
||||||
anim = QPropertyAnimation(self, b"offset", self)
|
|
||||||
anim.setDuration(120)
|
|
||||||
anim.setStartValue(self._offset)
|
|
||||||
anim.setEndValue((self._xW - self._xR) if self.isChecked() else self._xR)
|
|
||||||
anim.start()
|
|
||||||
return
|
|
||||||
|
|
||||||
def enterEvent(self, event: QEnterEvent) -> None:
|
def enterEvent(self, event: QEnterEvent) -> None:
|
||||||
"""Change the cursor when hovering the button."""
|
"""Change the cursor when hovering the button."""
|
||||||
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||||
super().enterEvent(event)
|
super().enterEvent(event)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@pyqtSlot(bool)
|
||||||
|
def _onClick(self, checked: bool) -> None:
|
||||||
|
"""Animate the toggle action."""
|
||||||
|
anim = QPropertyAnimation(self, b"offset", self)
|
||||||
|
anim.setDuration(120)
|
||||||
|
anim.setStartValue(self._offset)
|
||||||
|
anim.setEndValue((self._xW - self._xR) if checked else self._xR)
|
||||||
|
anim.start()
|
||||||
|
return
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ class NSwitchBox(QScrollArea):
|
|||||||
switch.toggled.connect(lambda state: self._emitSwitchSignal(identifier, state))
|
switch.toggled.connect(lambda state: self._emitSwitchSignal(identifier, state))
|
||||||
self._content.addWidget(switch, self._index, 2, QtAlignRight)
|
self._content.addWidget(switch, self._index, 2, QtAlignRight)
|
||||||
|
|
||||||
|
label.setBuddy(switch)
|
||||||
self._widgets.append(switch)
|
self._widgets.append(switch)
|
||||||
self._bumpIndex()
|
self._bumpIndex()
|
||||||
|
|
||||||
|
|||||||
@@ -299,6 +299,7 @@ class GuiNovelToolBar(QWidget):
|
|||||||
self.novelValue.setHandle(rootHandle)
|
self.novelValue.setHandle(rootHandle)
|
||||||
SHARED.project.data.setLastHandle(rootHandle, "novel")
|
SHARED.project.data.setLastHandle(rootHandle, "novel")
|
||||||
self.novelView.setCurrentNovel(rootHandle)
|
self.novelView.setCurrentNovel(rootHandle)
|
||||||
|
self.novelView.novelTree.setAccessibleName(self.novelValue.currentText())
|
||||||
return
|
return
|
||||||
|
|
||||||
def setLastColType(self, colType: nwNovelExtra, doRefresh: bool = True) -> None:
|
def setLastColType(self, colType: nwNovelExtra, doRefresh: bool = True) -> None:
|
||||||
|
|||||||
@@ -254,6 +254,7 @@ class GuiProjectToolBar(QWidget):
|
|||||||
self.viewLabel.setFont(SHARED.theme.guiFontB)
|
self.viewLabel.setFont(SHARED.theme.guiFontB)
|
||||||
self.viewLabel.setContentsMargins(0, 0, 0, 0)
|
self.viewLabel.setContentsMargins(0, 0, 0, 0)
|
||||||
self.viewLabel.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
|
self.viewLabel.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
|
||||||
|
self.projTree.setAccessibleName(self.viewLabel.text())
|
||||||
|
|
||||||
# Quick Links
|
# Quick Links
|
||||||
self.mQuick = QMenu(self)
|
self.mQuick = QMenu(self)
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ class GuiProjectSearch(QWidget):
|
|||||||
self.searchResult.setAllColumnsShowFocus(True)
|
self.searchResult.setAllColumnsShowFocus(True)
|
||||||
self.searchResult.itemDoubleClicked.connect(self._searchResultDoubleClicked)
|
self.searchResult.itemDoubleClicked.connect(self._searchResultDoubleClicked)
|
||||||
self.searchResult.itemSelectionChanged.connect(self._searchResultSelected)
|
self.searchResult.itemSelectionChanged.connect(self._searchResultSelected)
|
||||||
|
self.searchResult.setAccessibleName(self.viewLabel.text())
|
||||||
|
|
||||||
if header := self.searchResult.header():
|
if header := self.searchResult.header():
|
||||||
header.setStretchLastSection(False)
|
header.setStretchLastSection(False)
|
||||||
|
|||||||
@@ -75,8 +75,9 @@ class GuiLipsum(NDialog):
|
|||||||
self.paraCount.setMaximum(100)
|
self.paraCount.setMaximum(100)
|
||||||
self.paraCount.setValue(5)
|
self.paraCount.setValue(5)
|
||||||
|
|
||||||
self.randLabel = QLabel(self.tr("Randomise order"), self)
|
|
||||||
self.randSwitch = NSwitch(self)
|
self.randSwitch = NSwitch(self)
|
||||||
|
self.randLabel = QLabel(self.tr("Randomise order"), self)
|
||||||
|
self.randLabel.setBuddy(self.randSwitch)
|
||||||
|
|
||||||
self.formBox = QGridLayout()
|
self.formBox = QGridLayout()
|
||||||
self.formBox.addWidget(self.headLabel, 0, 0, 1, 2, QtAlignLeft)
|
self.formBox.addWidget(self.headLabel, 0, 0, 1, 2, QtAlignLeft)
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ class GuiBuildSettings(NToolDialog):
|
|||||||
# SideBar
|
# SideBar
|
||||||
self.sidebar = NPagedSideBar(self)
|
self.sidebar = NPagedSideBar(self)
|
||||||
self.sidebar.setLabelColor(SHARED.theme.helpText)
|
self.sidebar.setLabelColor(SHARED.theme.helpText)
|
||||||
|
self.sidebar.setAccessibleName(self.titleLabel.text())
|
||||||
|
|
||||||
self.sidebar.addLabel(self.tr("General"))
|
self.sidebar.addLabel(self.tr("General"))
|
||||||
self.sidebar.addButton(self.tr("Selection"), self.OPT_FILTERS)
|
self.sidebar.addButton(self.tr("Selection"), self.OPT_FILTERS)
|
||||||
@@ -564,9 +565,10 @@ class _HeadingsTab(NScrollablePage):
|
|||||||
self.fmtPart.setReadOnly(True)
|
self.fmtPart.setReadOnly(True)
|
||||||
self.btnPart = NIconToolButton(self, iSz, "edit", "green")
|
self.btnPart = NIconToolButton(self, iSz, "edit", "green")
|
||||||
self.btnPart.clicked.connect(qtLambda(self._editHeading, self.EDIT_TITLE))
|
self.btnPart.clicked.connect(qtLambda(self._editHeading, self.EDIT_TITLE))
|
||||||
|
self.swtPart = NSwitch(self, height=iPx)
|
||||||
self.hdePart = QLabel(trHide, self)
|
self.hdePart = QLabel(trHide, self)
|
||||||
self.hdePart.setIndent(6)
|
self.hdePart.setIndent(6)
|
||||||
self.swtPart = NSwitch(self, height=iPx)
|
self.hdePart.setBuddy(self.swtPart)
|
||||||
|
|
||||||
self.formatBox.addWidget(self.lblPart, 0, 0)
|
self.formatBox.addWidget(self.lblPart, 0, 0)
|
||||||
self.formatBox.addWidget(self.fmtPart, 0, 1)
|
self.formatBox.addWidget(self.fmtPart, 0, 1)
|
||||||
@@ -580,9 +582,10 @@ class _HeadingsTab(NScrollablePage):
|
|||||||
self.fmtChapter.setReadOnly(True)
|
self.fmtChapter.setReadOnly(True)
|
||||||
self.btnChapter = NIconToolButton(self, iSz, "edit", "green")
|
self.btnChapter = NIconToolButton(self, iSz, "edit", "green")
|
||||||
self.btnChapter.clicked.connect(qtLambda(self._editHeading, self.EDIT_CHAPTER))
|
self.btnChapter.clicked.connect(qtLambda(self._editHeading, self.EDIT_CHAPTER))
|
||||||
|
self.swtChapter = NSwitch(self, height=iPx)
|
||||||
self.hdeChapter = QLabel(trHide, self)
|
self.hdeChapter = QLabel(trHide, self)
|
||||||
self.hdeChapter.setIndent(6)
|
self.hdeChapter.setIndent(6)
|
||||||
self.swtChapter = NSwitch(self, height=iPx)
|
self.hdeChapter.setBuddy(self.swtChapter)
|
||||||
|
|
||||||
self.formatBox.addWidget(self.lblChapter, 1, 0)
|
self.formatBox.addWidget(self.lblChapter, 1, 0)
|
||||||
self.formatBox.addWidget(self.fmtChapter, 1, 1)
|
self.formatBox.addWidget(self.fmtChapter, 1, 1)
|
||||||
@@ -596,9 +599,10 @@ class _HeadingsTab(NScrollablePage):
|
|||||||
self.fmtUnnumbered.setReadOnly(True)
|
self.fmtUnnumbered.setReadOnly(True)
|
||||||
self.btnUnnumbered = NIconToolButton(self, iSz, "edit", "green")
|
self.btnUnnumbered = NIconToolButton(self, iSz, "edit", "green")
|
||||||
self.btnUnnumbered.clicked.connect(qtLambda(self._editHeading, self.EDIT_UNNUM))
|
self.btnUnnumbered.clicked.connect(qtLambda(self._editHeading, self.EDIT_UNNUM))
|
||||||
|
self.swtUnnumbered = NSwitch(self, height=iPx)
|
||||||
self.hdeUnnumbered = QLabel(trHide, self)
|
self.hdeUnnumbered = QLabel(trHide, self)
|
||||||
self.hdeUnnumbered.setIndent(6)
|
self.hdeUnnumbered.setIndent(6)
|
||||||
self.swtUnnumbered = NSwitch(self, height=iPx)
|
self.hdeUnnumbered.setBuddy(self.swtUnnumbered)
|
||||||
|
|
||||||
self.formatBox.addWidget(self.lblUnnumbered, 2, 0)
|
self.formatBox.addWidget(self.lblUnnumbered, 2, 0)
|
||||||
self.formatBox.addWidget(self.fmtUnnumbered, 2, 1)
|
self.formatBox.addWidget(self.fmtUnnumbered, 2, 1)
|
||||||
@@ -612,9 +616,10 @@ class _HeadingsTab(NScrollablePage):
|
|||||||
self.fmtScene.setReadOnly(True)
|
self.fmtScene.setReadOnly(True)
|
||||||
self.btnScene = NIconToolButton(self, iSz, "edit", "green")
|
self.btnScene = NIconToolButton(self, iSz, "edit", "green")
|
||||||
self.btnScene.clicked.connect(qtLambda(self._editHeading, self.EDIT_SCENE))
|
self.btnScene.clicked.connect(qtLambda(self._editHeading, self.EDIT_SCENE))
|
||||||
|
self.swtScene = NSwitch(self, height=iPx)
|
||||||
self.hdeScene = QLabel(trHide, self)
|
self.hdeScene = QLabel(trHide, self)
|
||||||
self.hdeScene.setIndent(6)
|
self.hdeScene.setIndent(6)
|
||||||
self.swtScene = NSwitch(self, height=iPx)
|
self.hdeScene.setBuddy(self.swtScene)
|
||||||
|
|
||||||
self.formatBox.addWidget(self.lblScene, 3, 0)
|
self.formatBox.addWidget(self.lblScene, 3, 0)
|
||||||
self.formatBox.addWidget(self.fmtScene, 3, 1)
|
self.formatBox.addWidget(self.fmtScene, 3, 1)
|
||||||
@@ -628,9 +633,10 @@ class _HeadingsTab(NScrollablePage):
|
|||||||
self.fmtAScene.setReadOnly(True)
|
self.fmtAScene.setReadOnly(True)
|
||||||
self.btnAScene = NIconToolButton(self, iSz, "edit", "green")
|
self.btnAScene = NIconToolButton(self, iSz, "edit", "green")
|
||||||
self.btnAScene.clicked.connect(qtLambda(self._editHeading, self.EDIT_HSCENE))
|
self.btnAScene.clicked.connect(qtLambda(self._editHeading, self.EDIT_HSCENE))
|
||||||
|
self.swtAScene = NSwitch(self, height=iPx)
|
||||||
self.hdeAScene = QLabel(trHide, self)
|
self.hdeAScene = QLabel(trHide, self)
|
||||||
self.hdeAScene.setIndent(6)
|
self.hdeAScene.setIndent(6)
|
||||||
self.swtAScene = NSwitch(self, height=iPx)
|
self.hdeAScene.setBuddy(self.swtAScene)
|
||||||
|
|
||||||
self.formatBox.addWidget(self.lblAScene, 4, 0)
|
self.formatBox.addWidget(self.lblAScene, 4, 0)
|
||||||
self.formatBox.addWidget(self.fmtAScene, 4, 1)
|
self.formatBox.addWidget(self.fmtAScene, 4, 1)
|
||||||
@@ -644,9 +650,10 @@ class _HeadingsTab(NScrollablePage):
|
|||||||
self.fmtSection.setReadOnly(True)
|
self.fmtSection.setReadOnly(True)
|
||||||
self.btnSection = NIconToolButton(self, iSz, "edit", "green")
|
self.btnSection = NIconToolButton(self, iSz, "edit", "green")
|
||||||
self.btnSection.clicked.connect(qtLambda(self._editHeading, self.EDIT_SECTION))
|
self.btnSection.clicked.connect(qtLambda(self._editHeading, self.EDIT_SECTION))
|
||||||
|
self.swtSection = NSwitch(self, height=iPx)
|
||||||
self.hdeSection = QLabel(trHide, self)
|
self.hdeSection = QLabel(trHide, self)
|
||||||
self.hdeSection.setIndent(6)
|
self.hdeSection.setIndent(6)
|
||||||
self.swtSection = NSwitch(self, height=iPx)
|
self.hdeSection.setBuddy(self.swtSection)
|
||||||
|
|
||||||
self.formatBox.addWidget(self.lblSection, 5, 0)
|
self.formatBox.addWidget(self.lblSection, 5, 0)
|
||||||
self.formatBox.addWidget(self.fmtSection, 5, 1)
|
self.formatBox.addWidget(self.fmtSection, 5, 1)
|
||||||
@@ -704,44 +711,59 @@ class _HeadingsTab(NScrollablePage):
|
|||||||
|
|
||||||
# Layout Matrix
|
# Layout Matrix
|
||||||
# =============
|
# =============
|
||||||
|
trCentre = self.tr("Centre")
|
||||||
|
trBreak = self.tr("Page Break")
|
||||||
|
|
||||||
self.layoutMatrix = QGridLayout()
|
self.layoutMatrix = QGridLayout()
|
||||||
self.layoutMatrix.setVerticalSpacing(12)
|
self.layoutMatrix.setVerticalSpacing(12)
|
||||||
self.layoutMatrix.setHorizontalSpacing(12)
|
self.layoutMatrix.setHorizontalSpacing(12)
|
||||||
|
|
||||||
self.layoutMatrix.addWidget(QLabel(self.tr("Centre"), self), 0, 1)
|
self.layoutMatrix.addWidget(QLabel(trCentre, self), 0, 1)
|
||||||
self.layoutMatrix.addWidget(QLabel(self.tr("Page Break"), self), 0, 2)
|
self.layoutMatrix.addWidget(QLabel(trBreak, self), 0, 2)
|
||||||
|
|
||||||
# Title Layout
|
# Title Layout
|
||||||
self.lblTitle = QLabel(self._build.getLabel("headings.styleTitle"), self)
|
trLabel = self._build.getLabel("headings.styleTitle")
|
||||||
|
self.lblTitle = QLabel(trLabel, self)
|
||||||
self.centerTitle = NSwitch(self, height=iPx)
|
self.centerTitle = NSwitch(self, height=iPx)
|
||||||
|
self.centerTitle.setAccessibleName(f"{trLabel}: {trCentre}")
|
||||||
self.breakTitle = NSwitch(self, height=iPx)
|
self.breakTitle = NSwitch(self, height=iPx)
|
||||||
|
self.breakTitle.setAccessibleName(f"{trLabel}: {trBreak}")
|
||||||
|
|
||||||
self.layoutMatrix.addWidget(self.lblTitle, 1, 0)
|
self.layoutMatrix.addWidget(self.lblTitle, 1, 0)
|
||||||
self.layoutMatrix.addWidget(self.centerTitle, 1, 1, QtAlignCenter)
|
self.layoutMatrix.addWidget(self.centerTitle, 1, 1, QtAlignCenter)
|
||||||
self.layoutMatrix.addWidget(self.breakTitle, 1, 2, QtAlignCenter)
|
self.layoutMatrix.addWidget(self.breakTitle, 1, 2, QtAlignCenter)
|
||||||
|
|
||||||
# Partition Layout
|
# Partition Layout
|
||||||
self.lblPart = QLabel(self._build.getLabel("headings.stylePart"), self)
|
trLabel = self._build.getLabel("headings.stylePart")
|
||||||
|
self.lblPart = QLabel(trLabel, self)
|
||||||
self.centerPart = NSwitch(self, height=iPx)
|
self.centerPart = NSwitch(self, height=iPx)
|
||||||
|
self.centerPart.setAccessibleName(f"{trLabel}: {trCentre}")
|
||||||
self.breakPart = NSwitch(self, height=iPx)
|
self.breakPart = NSwitch(self, height=iPx)
|
||||||
|
self.breakPart.setAccessibleName(f"{trLabel}: {trBreak}")
|
||||||
|
|
||||||
self.layoutMatrix.addWidget(self.lblPart, 2, 0)
|
self.layoutMatrix.addWidget(self.lblPart, 2, 0)
|
||||||
self.layoutMatrix.addWidget(self.centerPart, 2, 1, QtAlignCenter)
|
self.layoutMatrix.addWidget(self.centerPart, 2, 1, QtAlignCenter)
|
||||||
self.layoutMatrix.addWidget(self.breakPart, 2, 2, QtAlignCenter)
|
self.layoutMatrix.addWidget(self.breakPart, 2, 2, QtAlignCenter)
|
||||||
|
|
||||||
# Chapter Layout
|
# Chapter Layout
|
||||||
self.lblChapter = QLabel(self._build.getLabel("headings.styleChapter"), self)
|
trLabel = self._build.getLabel("headings.styleChapter")
|
||||||
|
self.lblChapter = QLabel(trLabel, self)
|
||||||
self.centerChapter = NSwitch(self, height=iPx)
|
self.centerChapter = NSwitch(self, height=iPx)
|
||||||
|
self.centerChapter.setAccessibleName(f"{trLabel}: {trCentre}")
|
||||||
self.breakChapter = NSwitch(self, height=iPx)
|
self.breakChapter = NSwitch(self, height=iPx)
|
||||||
|
self.breakChapter.setAccessibleName(f"{trLabel}: {trBreak}")
|
||||||
|
|
||||||
self.layoutMatrix.addWidget(self.lblChapter, 3, 0)
|
self.layoutMatrix.addWidget(self.lblChapter, 3, 0)
|
||||||
self.layoutMatrix.addWidget(self.centerChapter, 3, 1, QtAlignCenter)
|
self.layoutMatrix.addWidget(self.centerChapter, 3, 1, QtAlignCenter)
|
||||||
self.layoutMatrix.addWidget(self.breakChapter, 3, 2, QtAlignCenter)
|
self.layoutMatrix.addWidget(self.breakChapter, 3, 2, QtAlignCenter)
|
||||||
|
|
||||||
# Scene Layout
|
# Scene Layout
|
||||||
self.lblScene = QLabel(self._build.getLabel("headings.styleScene"), self)
|
trLabel = self._build.getLabel("headings.styleScene")
|
||||||
|
self.lblScene = QLabel(trLabel, self)
|
||||||
self.centerScene = NSwitch(self, height=iPx)
|
self.centerScene = NSwitch(self, height=iPx)
|
||||||
|
self.centerScene.setAccessibleName(f"{trLabel}: {trCentre}")
|
||||||
self.breakScene = NSwitch(self, height=iPx)
|
self.breakScene = NSwitch(self, height=iPx)
|
||||||
|
self.breakScene.setAccessibleName(f"{trLabel}: {trBreak}")
|
||||||
|
|
||||||
self.layoutMatrix.addWidget(self.lblScene, 4, 0)
|
self.layoutMatrix.addWidget(self.lblScene, 4, 0)
|
||||||
self.layoutMatrix.addWidget(self.centerScene, 4, 1, QtAlignCenter)
|
self.layoutMatrix.addWidget(self.centerScene, 4, 1, QtAlignCenter)
|
||||||
@@ -979,7 +1001,6 @@ class _FormattingTab(NScrollableForm):
|
|||||||
|
|
||||||
# Note Headings
|
# Note Headings
|
||||||
self.addNoteHead = NSwitch(self, height=iPx)
|
self.addNoteHead = NSwitch(self, height=iPx)
|
||||||
|
|
||||||
self.addRow(self._build.getLabel("text.addNoteHeadings"), self.addNoteHead)
|
self.addRow(self._build.getLabel("text.addNoteHeadings"), self.addNoteHead)
|
||||||
|
|
||||||
# Text Format
|
# Text Format
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ class GuiNovelDetails(NNonBlockingDialog):
|
|||||||
# SideBar
|
# SideBar
|
||||||
self.sidebar = NPagedSideBar(self)
|
self.sidebar = NPagedSideBar(self)
|
||||||
self.sidebar.setLabelColor(SHARED.theme.helpText)
|
self.sidebar.setLabelColor(SHARED.theme.helpText)
|
||||||
|
self.sidebar.setAccessibleName(self.titleLabel.text())
|
||||||
self.sidebar.addButton(self.tr("Overview"), self.PAGE_OVERVIEW)
|
self.sidebar.addButton(self.tr("Overview"), self.PAGE_OVERVIEW)
|
||||||
self.sidebar.addButton(self.tr("Contents"), self.PAGE_CONTENTS)
|
self.sidebar.addButton(self.tr("Contents"), self.PAGE_CONTENTS)
|
||||||
self.sidebar.setSelected(self.PAGE_OVERVIEW)
|
self.sidebar.setSelected(self.PAGE_OVERVIEW)
|
||||||
@@ -356,16 +357,14 @@ class _ContentsPage(NFixedPage):
|
|||||||
countFrom = options.getInt("GuiNovelDetails", "countFrom", 1)
|
countFrom = options.getInt("GuiNovelDetails", "countFrom", 1)
|
||||||
clearDouble = options.getBool("GuiNovelDetails", "clearDouble", True)
|
clearDouble = options.getBool("GuiNovelDetails", "clearDouble", True)
|
||||||
|
|
||||||
self.wpLabel = QLabel(self.tr("Words per page"), self)
|
|
||||||
|
|
||||||
self.wpValue = QSpinBox(self)
|
self.wpValue = QSpinBox(self)
|
||||||
self.wpValue.setMinimum(10)
|
self.wpValue.setMinimum(10)
|
||||||
self.wpValue.setMaximum(1000)
|
self.wpValue.setMaximum(1000)
|
||||||
self.wpValue.setSingleStep(10)
|
self.wpValue.setSingleStep(10)
|
||||||
self.wpValue.setValue(wordsPerPage)
|
self.wpValue.setValue(wordsPerPage)
|
||||||
self.wpValue.valueChanged.connect(self._populateTree)
|
self.wpValue.valueChanged.connect(self._populateTree)
|
||||||
|
self.wpLabel = QLabel(self.tr("Words per page"), self)
|
||||||
self.poLabel = QLabel(self.tr("First page offset"), self)
|
self.wpLabel.setBuddy(self.wpValue)
|
||||||
|
|
||||||
self.poValue = QSpinBox(self)
|
self.poValue = QSpinBox(self)
|
||||||
self.poValue.setMinimum(1)
|
self.poValue.setMinimum(1)
|
||||||
@@ -373,12 +372,14 @@ class _ContentsPage(NFixedPage):
|
|||||||
self.poValue.setSingleStep(1)
|
self.poValue.setSingleStep(1)
|
||||||
self.poValue.setValue(countFrom)
|
self.poValue.setValue(countFrom)
|
||||||
self.poValue.valueChanged.connect(self._populateTree)
|
self.poValue.valueChanged.connect(self._populateTree)
|
||||||
|
self.poLabel = QLabel(self.tr("First page offset"), self)
|
||||||
self.dblLabel = QLabel(self.tr("Chapters on odd pages"), self)
|
self.poLabel.setBuddy(self.poValue)
|
||||||
|
|
||||||
self.dblValue = NSwitch(self, height=iPx)
|
self.dblValue = NSwitch(self, height=iPx)
|
||||||
self.dblValue.setChecked(clearDouble)
|
self.dblValue.setChecked(clearDouble)
|
||||||
self.dblValue.clicked.connect(self._populateTree)
|
self.dblValue.clicked.connect(self._populateTree)
|
||||||
|
self.dblLabel = QLabel(self.tr("Chapters on odd pages"), self)
|
||||||
|
self.dblLabel.setBuddy(self.dblValue)
|
||||||
|
|
||||||
self.optionsBox = QGridLayout()
|
self.optionsBox = QGridLayout()
|
||||||
self.optionsBox.addWidget(self.wpLabel, 0, 0)
|
self.optionsBox.addWidget(self.wpLabel, 0, 0)
|
||||||
|
|||||||
@@ -565,6 +565,7 @@ class _NewProjectForm(QWidget):
|
|||||||
self.projAuthor = QLineEdit(self)
|
self.projAuthor = QLineEdit(self)
|
||||||
self.projAuthor.setMaxLength(200)
|
self.projAuthor.setMaxLength(200)
|
||||||
self.projAuthor.setPlaceholderText(self.tr("Optional"))
|
self.projAuthor.setPlaceholderText(self.tr("Optional"))
|
||||||
|
self.projAuthor.setText(CONFIG.lastAuthor)
|
||||||
|
|
||||||
# Project Path
|
# Project Path
|
||||||
self.projPath = QLineEdit(self)
|
self.projPath = QLineEdit(self)
|
||||||
|
|||||||
@@ -183,59 +183,82 @@ class GuiWritingStats(NToolDialog):
|
|||||||
# Filter Options
|
# Filter Options
|
||||||
iPx = SHARED.theme.baseIconHeight
|
iPx = SHARED.theme.baseIconHeight
|
||||||
|
|
||||||
self.filterBox = QGroupBox(self.tr("Filters"), self)
|
|
||||||
self.filterForm = QGridLayout(self)
|
self.filterForm = QGridLayout(self)
|
||||||
|
self.filterForm.setRowStretch(6, 1)
|
||||||
|
self.filterBox = QGroupBox(self.tr("Filters"), self)
|
||||||
self.filterBox.setLayout(self.filterForm)
|
self.filterBox.setLayout(self.filterForm)
|
||||||
|
|
||||||
self.incNovel = NSwitch(self, height=iPx)
|
# Include Novel Files
|
||||||
self.incNovel.setChecked(
|
self.swtIncNovel = NSwitch(self, height=iPx)
|
||||||
|
self.swtIncNovel.setChecked(
|
||||||
pOptions.getBool("GuiWritingStats", "incNovel", True)
|
pOptions.getBool("GuiWritingStats", "incNovel", True)
|
||||||
)
|
)
|
||||||
self.incNovel.clicked.connect(self._updateListBox)
|
self.swtIncNovel.clicked.connect(self._updateListBox)
|
||||||
|
self.lblIncNovel = QLabel(self.tr("Count novel files"), self)
|
||||||
|
self.lblIncNovel.setBuddy(self.swtIncNovel)
|
||||||
|
|
||||||
self.incNotes = NSwitch(self, height=iPx)
|
self.filterForm.addWidget(self.lblIncNovel, 0, 0)
|
||||||
self.incNotes.setChecked(
|
self.filterForm.addWidget(self.swtIncNovel, 0, 1)
|
||||||
|
|
||||||
|
# Include Note Files
|
||||||
|
self.swtIncNotes = NSwitch(self, height=iPx)
|
||||||
|
self.swtIncNotes.setChecked(
|
||||||
pOptions.getBool("GuiWritingStats", "incNotes", True)
|
pOptions.getBool("GuiWritingStats", "incNotes", True)
|
||||||
)
|
)
|
||||||
self.incNotes.clicked.connect(self._updateListBox)
|
self.swtIncNotes.clicked.connect(self._updateListBox)
|
||||||
|
self.lblIncNotes = QLabel(self.tr("Count note files"), self)
|
||||||
|
self.lblIncNotes.setBuddy(self.swtIncNotes)
|
||||||
|
|
||||||
self.hideZeros = NSwitch(self, height=iPx)
|
self.filterForm.addWidget(self.lblIncNotes, 1, 0)
|
||||||
self.hideZeros.setChecked(
|
self.filterForm.addWidget(self.swtIncNotes, 1, 1)
|
||||||
|
|
||||||
|
# Hide Zero Counts
|
||||||
|
self.swtHideZeros = NSwitch(self, height=iPx)
|
||||||
|
self.swtHideZeros.setChecked(
|
||||||
pOptions.getBool("GuiWritingStats", "hideZeros", True)
|
pOptions.getBool("GuiWritingStats", "hideZeros", True)
|
||||||
)
|
)
|
||||||
self.hideZeros.clicked.connect(self._updateListBox)
|
self.swtHideZeros.clicked.connect(self._updateListBox)
|
||||||
|
self.lblHideZeros = QLabel(self.tr("Hide zero word count"), self)
|
||||||
|
self.lblHideZeros.setBuddy(self.swtHideZeros)
|
||||||
|
|
||||||
self.hideNegative = NSwitch(self, height=iPx)
|
self.filterForm.addWidget(self.lblHideZeros, 2, 0)
|
||||||
self.hideNegative.setChecked(
|
self.filterForm.addWidget(self.swtHideZeros, 2, 1)
|
||||||
|
|
||||||
|
# Hide Negative Counts
|
||||||
|
self.swtHideNegative = NSwitch(self, height=iPx)
|
||||||
|
self.swtHideNegative.setChecked(
|
||||||
pOptions.getBool("GuiWritingStats", "hideNegative", False)
|
pOptions.getBool("GuiWritingStats", "hideNegative", False)
|
||||||
)
|
)
|
||||||
self.hideNegative.clicked.connect(self._updateListBox)
|
self.swtHideNegative.clicked.connect(self._updateListBox)
|
||||||
|
self.lblHideNegative = QLabel(self.tr("Hide negative word count"), self)
|
||||||
|
self.lblHideNegative.setBuddy(self.swtHideNegative)
|
||||||
|
|
||||||
self.groupByDay = NSwitch(self, height=iPx)
|
self.filterForm.addWidget(self.lblHideNegative, 3, 0)
|
||||||
self.groupByDay.setChecked(
|
self.filterForm.addWidget(self.swtHideNegative, 3, 1)
|
||||||
|
|
||||||
|
# Group Entries
|
||||||
|
self.swtGroupByDay = NSwitch(self, height=iPx)
|
||||||
|
self.swtGroupByDay.setChecked(
|
||||||
pOptions.getBool("GuiWritingStats", "groupByDay", False)
|
pOptions.getBool("GuiWritingStats", "groupByDay", False)
|
||||||
)
|
)
|
||||||
self.groupByDay.clicked.connect(self._updateListBox)
|
self.swtGroupByDay.clicked.connect(self._updateListBox)
|
||||||
|
self.lblGroupByDay = QLabel(self.tr("Group entries by day"), self)
|
||||||
|
self.lblGroupByDay.setBuddy(self.swtGroupByDay)
|
||||||
|
|
||||||
self.showIdleTime = NSwitch(self, height=iPx)
|
self.filterForm.addWidget(self.lblGroupByDay, 4, 0)
|
||||||
self.showIdleTime.setChecked(
|
self.filterForm.addWidget(self.swtGroupByDay, 4, 1)
|
||||||
|
|
||||||
|
# Show Idle
|
||||||
|
self.swtShowIdleTime = NSwitch(self, height=iPx)
|
||||||
|
self.swtShowIdleTime.setChecked(
|
||||||
pOptions.getBool("GuiWritingStats", "showIdleTime", False)
|
pOptions.getBool("GuiWritingStats", "showIdleTime", False)
|
||||||
)
|
)
|
||||||
self.showIdleTime.clicked.connect(self._updateListBox)
|
self.swtShowIdleTime.clicked.connect(self._updateListBox)
|
||||||
|
self.lblShowIdleTime = QLabel(self.tr("Show idle time"), self)
|
||||||
|
self.lblShowIdleTime.setBuddy(self.swtShowIdleTime)
|
||||||
|
|
||||||
self.filterForm.addWidget(QLabel(self.tr("Count novel files"), self), 0, 0)
|
self.filterForm.addWidget(self.lblShowIdleTime, 5, 0)
|
||||||
self.filterForm.addWidget(QLabel(self.tr("Count note files"), self), 1, 0)
|
self.filterForm.addWidget(self.swtShowIdleTime, 5, 1)
|
||||||
self.filterForm.addWidget(QLabel(self.tr("Hide zero word count"), self), 2, 0)
|
|
||||||
self.filterForm.addWidget(QLabel(self.tr("Hide negative word count"), self), 3, 0)
|
|
||||||
self.filterForm.addWidget(QLabel(self.tr("Group entries by day"), self), 4, 0)
|
|
||||||
self.filterForm.addWidget(QLabel(self.tr("Show idle time"), self), 5, 0)
|
|
||||||
self.filterForm.addWidget(self.incNovel, 0, 1)
|
|
||||||
self.filterForm.addWidget(self.incNotes, 1, 1)
|
|
||||||
self.filterForm.addWidget(self.hideZeros, 2, 1)
|
|
||||||
self.filterForm.addWidget(self.hideNegative, 3, 1)
|
|
||||||
self.filterForm.addWidget(self.groupByDay, 4, 1)
|
|
||||||
self.filterForm.addWidget(self.showIdleTime, 5, 1)
|
|
||||||
self.filterForm.setRowStretch(6, 1)
|
|
||||||
|
|
||||||
# Settings
|
# Settings
|
||||||
self.histMax = QSpinBox(self)
|
self.histMax = QSpinBox(self)
|
||||||
@@ -325,12 +348,12 @@ class GuiWritingStats(NToolDialog):
|
|||||||
|
|
||||||
sortCol = self.listBox.sortColumn()
|
sortCol = self.listBox.sortColumn()
|
||||||
sortOrder = header.sortIndicatorOrder() if header else 0
|
sortOrder = header.sortIndicatorOrder() if header else 0
|
||||||
incNovel = self.incNovel.isChecked()
|
incNovel = self.swtIncNovel.isChecked()
|
||||||
incNotes = self.incNotes.isChecked()
|
incNotes = self.swtIncNotes.isChecked()
|
||||||
hideZeros = self.hideZeros.isChecked()
|
hideZeros = self.swtHideZeros.isChecked()
|
||||||
hideNegative = self.hideNegative.isChecked()
|
hideNegative = self.swtHideNegative.isChecked()
|
||||||
groupByDay = self.groupByDay.isChecked()
|
groupByDay = self.swtGroupByDay.isChecked()
|
||||||
showIdleTime = self.showIdleTime.isChecked()
|
showIdleTime = self.swtShowIdleTime.isChecked()
|
||||||
histMax = self.histMax.value()
|
histMax = self.histMax.value()
|
||||||
|
|
||||||
logger.debug("Saving State: GuiWritingStats")
|
logger.debug("Saving State: GuiWritingStats")
|
||||||
@@ -487,11 +510,11 @@ class GuiWritingStats(NToolDialog):
|
|||||||
self.listBox.clear()
|
self.listBox.clear()
|
||||||
self.timeFilter = 0.0
|
self.timeFilter = 0.0
|
||||||
|
|
||||||
incNovel = self.incNovel.isChecked()
|
incNovel = self.swtIncNovel.isChecked()
|
||||||
incNotes = self.incNotes.isChecked()
|
incNotes = self.swtIncNotes.isChecked()
|
||||||
hideZeros = self.hideZeros.isChecked()
|
hideZeros = self.swtHideZeros.isChecked()
|
||||||
hideNegative = self.hideNegative.isChecked()
|
hideNegative = self.swtHideNegative.isChecked()
|
||||||
groupByDay = self.groupByDay.isChecked()
|
groupByDay = self.swtGroupByDay.isChecked()
|
||||||
histMax = self.histMax.value()
|
histMax = self.histMax.value()
|
||||||
|
|
||||||
# Group the data
|
# Group the data
|
||||||
@@ -563,7 +586,7 @@ class GuiWritingStats(NToolDialog):
|
|||||||
# Populate the list
|
# Populate the list
|
||||||
mTrans = Qt.TransformationMode.FastTransformation
|
mTrans = Qt.TransformationMode.FastTransformation
|
||||||
mAspect = Qt.AspectRatioMode.IgnoreAspectRatio
|
mAspect = Qt.AspectRatioMode.IgnoreAspectRatio
|
||||||
showIdleTime = self.showIdleTime.isChecked()
|
showIdleTime = self.swtShowIdleTime.isChecked()
|
||||||
for _, sStart, sDiff, nWords, _, _, sIdle in self.filterData:
|
for _, sStart, sDiff, nWords, _, _, sIdle in self.filterData:
|
||||||
|
|
||||||
if showIdleTime:
|
if showIdleTime:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[Meta]
|
[Meta]
|
||||||
timestamp = 2025-02-22 19:57:47
|
timestamp = 2025-05-11 13:28:11
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
font =
|
font =
|
||||||
@@ -31,6 +31,7 @@ backuppath =
|
|||||||
backuponclose = False
|
backuponclose = False
|
||||||
askbeforebackup = True
|
askbeforebackup = True
|
||||||
askbeforeexit = True
|
askbeforeexit = True
|
||||||
|
lastauthor =
|
||||||
|
|
||||||
[Editor]
|
[Editor]
|
||||||
textfont =
|
textfont =
|
||||||
|
|||||||
@@ -16,16 +16,16 @@
|
|||||||
</lastHandle>
|
</lastHandle>
|
||||||
<autoReplace />
|
<autoReplace />
|
||||||
<status>
|
<status>
|
||||||
<entry key="s000000" count="7" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="s000000" count="7" red="120" green="120" blue="120" shape="STAR">New</entry>
|
||||||
<entry key="s000001" count="0" red="200" green="50" blue="0" shape="SQUARE">Note</entry>
|
<entry key="s000001" count="0" red="205" green="171" blue="143" shape="TRIANGLE">Note</entry>
|
||||||
<entry key="s000002" count="0" red="200" green="150" blue="0" shape="SQUARE">Draft</entry>
|
<entry key="s000002" count="0" red="143" green="240" blue="164" shape="CIRCLE_T">Draft</entry>
|
||||||
<entry key="s000003" count="0" red="50" green="200" blue="0" shape="SQUARE">Finished</entry>
|
<entry key="s000003" count="0" red="249" green="240" blue="107" shape="STAR">Finished</entry>
|
||||||
</status>
|
</status>
|
||||||
<importance>
|
<importance>
|
||||||
<entry key="i000004" count="5" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="i000004" count="5" red="120" green="120" blue="120" shape="SQUARE">New</entry>
|
||||||
<entry key="i000005" count="0" red="200" green="50" blue="0" shape="SQUARE">Minor</entry>
|
<entry key="i000005" count="0" red="220" green="138" blue="221" shape="BLOCK_2">Minor</entry>
|
||||||
<entry key="i000006" count="0" red="200" green="150" blue="0" shape="SQUARE">Major</entry>
|
<entry key="i000006" count="0" red="220" green="138" blue="221" shape="BLOCK_3">Major</entry>
|
||||||
<entry key="i000007" count="0" red="50" green="200" blue="0" shape="SQUARE">Main</entry>
|
<entry key="i000007" count="0" red="220" green="138" blue="221" shape="BLOCK_4">Main</entry>
|
||||||
</importance>
|
</importance>
|
||||||
</settings>
|
</settings>
|
||||||
<content items="12" novelWords="10" notesWords="6" novelChars="45" notesChars="22">
|
<content items="12" novelWords="10" notesWords="6" novelChars="45" notesChars="22">
|
||||||
|
|||||||
@@ -16,16 +16,16 @@
|
|||||||
</lastHandle>
|
</lastHandle>
|
||||||
<autoReplace />
|
<autoReplace />
|
||||||
<status>
|
<status>
|
||||||
<entry key="s000000" count="6" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="s000000" count="6" red="120" green="120" blue="120" shape="STAR">New</entry>
|
||||||
<entry key="s000001" count="0" red="200" green="50" blue="0" shape="SQUARE">Note</entry>
|
<entry key="s000001" count="0" red="205" green="171" blue="143" shape="TRIANGLE">Note</entry>
|
||||||
<entry key="s000002" count="0" red="200" green="150" blue="0" shape="SQUARE">Draft</entry>
|
<entry key="s000002" count="0" red="143" green="240" blue="164" shape="CIRCLE_T">Draft</entry>
|
||||||
<entry key="s000003" count="0" red="50" green="200" blue="0" shape="SQUARE">Finished</entry>
|
<entry key="s000003" count="0" red="249" green="240" blue="107" shape="STAR">Finished</entry>
|
||||||
</status>
|
</status>
|
||||||
<importance>
|
<importance>
|
||||||
<entry key="i000004" count="10" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="i000004" count="10" red="120" green="120" blue="120" shape="SQUARE">New</entry>
|
||||||
<entry key="i000005" count="0" red="200" green="50" blue="0" shape="SQUARE">Minor</entry>
|
<entry key="i000005" count="0" red="220" green="138" blue="221" shape="BLOCK_2">Minor</entry>
|
||||||
<entry key="i000006" count="0" red="200" green="150" blue="0" shape="SQUARE">Major</entry>
|
<entry key="i000006" count="0" red="220" green="138" blue="221" shape="BLOCK_3">Major</entry>
|
||||||
<entry key="i000007" count="0" red="50" green="200" blue="0" shape="SQUARE">Main</entry>
|
<entry key="i000007" count="0" red="220" green="138" blue="221" shape="BLOCK_4">Main</entry>
|
||||||
</importance>
|
</importance>
|
||||||
</settings>
|
</settings>
|
||||||
<content items="16" novelWords="9" notesWords="0" novelChars="40" notesChars="0">
|
<content items="16" novelWords="9" notesWords="0" novelChars="40" notesChars="0">
|
||||||
|
|||||||
@@ -16,16 +16,16 @@
|
|||||||
</lastHandle>
|
</lastHandle>
|
||||||
<autoReplace />
|
<autoReplace />
|
||||||
<status>
|
<status>
|
||||||
<entry key="s000000" count="16" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="s000000" count="16" red="120" green="120" blue="120" shape="STAR">New</entry>
|
||||||
<entry key="s000001" count="0" red="200" green="50" blue="0" shape="SQUARE">Note</entry>
|
<entry key="s000001" count="0" red="205" green="171" blue="143" shape="TRIANGLE">Note</entry>
|
||||||
<entry key="s000002" count="0" red="200" green="150" blue="0" shape="SQUARE">Draft</entry>
|
<entry key="s000002" count="0" red="143" green="240" blue="164" shape="CIRCLE_T">Draft</entry>
|
||||||
<entry key="s000003" count="0" red="50" green="200" blue="0" shape="SQUARE">Finished</entry>
|
<entry key="s000003" count="0" red="249" green="240" blue="107" shape="STAR">Finished</entry>
|
||||||
</status>
|
</status>
|
||||||
<importance>
|
<importance>
|
||||||
<entry key="i000004" count="3" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="i000004" count="3" red="120" green="120" blue="120" shape="SQUARE">New</entry>
|
||||||
<entry key="i000005" count="0" red="200" green="50" blue="0" shape="SQUARE">Minor</entry>
|
<entry key="i000005" count="0" red="220" green="138" blue="221" shape="BLOCK_2">Minor</entry>
|
||||||
<entry key="i000006" count="0" red="200" green="150" blue="0" shape="SQUARE">Major</entry>
|
<entry key="i000006" count="0" red="220" green="138" blue="221" shape="BLOCK_3">Major</entry>
|
||||||
<entry key="i000007" count="0" red="50" green="200" blue="0" shape="SQUARE">Main</entry>
|
<entry key="i000007" count="0" red="220" green="138" blue="221" shape="BLOCK_4">Main</entry>
|
||||||
</importance>
|
</importance>
|
||||||
</settings>
|
</settings>
|
||||||
<content items="19" novelWords="28" notesWords="0" novelChars="129" notesChars="0">
|
<content items="19" novelWords="28" notesWords="0" novelChars="129" notesChars="0">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Jane Doe
|
Jane Doe
|
||||||
Address 1
|
Address Line 1
|
||||||
Address 2
|
Address Line 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ Test Project A
|
|||||||
|
|
||||||
**By Jane Doe**
|
**By Jane Doe**
|
||||||
|
|
||||||
Word Count: 11
|
Word Count: 13
|
||||||
|
|
||||||
# Chapter 1
|
# Chapter 1
|
||||||
|
|
||||||
|
|||||||
@@ -16,16 +16,16 @@
|
|||||||
</lastHandle>
|
</lastHandle>
|
||||||
<autoReplace />
|
<autoReplace />
|
||||||
<status>
|
<status>
|
||||||
<entry key="s000000" count="15" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="s000000" count="15" red="120" green="120" blue="120" shape="STAR">New</entry>
|
||||||
<entry key="s000001" count="0" red="200" green="50" blue="0" shape="SQUARE">Note</entry>
|
<entry key="s000001" count="0" red="205" green="171" blue="143" shape="TRIANGLE">Note</entry>
|
||||||
<entry key="s000002" count="0" red="200" green="150" blue="0" shape="SQUARE">Draft</entry>
|
<entry key="s000002" count="0" red="143" green="240" blue="164" shape="CIRCLE_T">Draft</entry>
|
||||||
<entry key="s000003" count="0" red="50" green="200" blue="0" shape="SQUARE">Finished</entry>
|
<entry key="s000003" count="0" red="249" green="240" blue="107" shape="STAR">Finished</entry>
|
||||||
</status>
|
</status>
|
||||||
<importance>
|
<importance>
|
||||||
<entry key="i000004" count="7" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="i000004" count="7" red="120" green="120" blue="120" shape="SQUARE">New</entry>
|
||||||
<entry key="i000005" count="0" red="200" green="50" blue="0" shape="SQUARE">Minor</entry>
|
<entry key="i000005" count="0" red="220" green="138" blue="221" shape="BLOCK_2">Minor</entry>
|
||||||
<entry key="i000006" count="0" red="200" green="150" blue="0" shape="SQUARE">Major</entry>
|
<entry key="i000006" count="0" red="220" green="138" blue="221" shape="BLOCK_3">Major</entry>
|
||||||
<entry key="i000007" count="0" red="50" green="200" blue="0" shape="SQUARE">Main</entry>
|
<entry key="i000007" count="0" red="220" green="138" blue="221" shape="BLOCK_4">Main</entry>
|
||||||
</importance>
|
</importance>
|
||||||
</settings>
|
</settings>
|
||||||
<content items="22" novelWords="0" notesWords="0" novelChars="0" notesChars="0">
|
<content items="22" novelWords="0" notesWords="0" novelChars="0" notesChars="0">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Jane Doe
|
Jane Doe
|
||||||
Address 1
|
Address Line 1
|
||||||
Address 2
|
Address Line 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ Test Project B
|
|||||||
|
|
||||||
**By Jane Doe**
|
**By Jane Doe**
|
||||||
|
|
||||||
Word Count: 11
|
Word Count: 13
|
||||||
|
|
||||||
* * *
|
* * *
|
||||||
|
|
||||||
|
|||||||
@@ -16,16 +16,16 @@
|
|||||||
</lastHandle>
|
</lastHandle>
|
||||||
<autoReplace />
|
<autoReplace />
|
||||||
<status>
|
<status>
|
||||||
<entry key="s000000" count="9" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="s000000" count="9" red="120" green="120" blue="120" shape="STAR">New</entry>
|
||||||
<entry key="s000001" count="0" red="200" green="50" blue="0" shape="SQUARE">Note</entry>
|
<entry key="s000001" count="0" red="205" green="171" blue="143" shape="TRIANGLE">Note</entry>
|
||||||
<entry key="s000002" count="0" red="200" green="150" blue="0" shape="SQUARE">Draft</entry>
|
<entry key="s000002" count="0" red="143" green="240" blue="164" shape="CIRCLE_T">Draft</entry>
|
||||||
<entry key="s000003" count="0" red="50" green="200" blue="0" shape="SQUARE">Finished</entry>
|
<entry key="s000003" count="0" red="249" green="240" blue="107" shape="STAR">Finished</entry>
|
||||||
</status>
|
</status>
|
||||||
<importance>
|
<importance>
|
||||||
<entry key="i000004" count="7" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="i000004" count="7" red="120" green="120" blue="120" shape="SQUARE">New</entry>
|
||||||
<entry key="i000005" count="0" red="200" green="50" blue="0" shape="SQUARE">Minor</entry>
|
<entry key="i000005" count="0" red="220" green="138" blue="221" shape="BLOCK_2">Minor</entry>
|
||||||
<entry key="i000006" count="0" red="200" green="150" blue="0" shape="SQUARE">Major</entry>
|
<entry key="i000006" count="0" red="220" green="138" blue="221" shape="BLOCK_3">Major</entry>
|
||||||
<entry key="i000007" count="0" red="50" green="200" blue="0" shape="SQUARE">Main</entry>
|
<entry key="i000007" count="0" red="220" green="138" blue="221" shape="BLOCK_4">Main</entry>
|
||||||
</importance>
|
</importance>
|
||||||
</settings>
|
</settings>
|
||||||
<content items="16" novelWords="0" notesWords="0" novelChars="0" notesChars="0">
|
<content items="16" novelWords="0" notesWords="0" novelChars="0" notesChars="0">
|
||||||
|
|||||||
@@ -16,16 +16,16 @@
|
|||||||
</lastHandle>
|
</lastHandle>
|
||||||
<autoReplace />
|
<autoReplace />
|
||||||
<status>
|
<status>
|
||||||
<entry key="s000000" count="5" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="s000000" count="5" red="120" green="120" blue="120" shape="STAR">New</entry>
|
||||||
<entry key="s000001" count="0" red="200" green="50" blue="0" shape="SQUARE">Note</entry>
|
<entry key="s000001" count="0" red="205" green="171" blue="143" shape="TRIANGLE">Note</entry>
|
||||||
<entry key="s000002" count="0" red="200" green="150" blue="0" shape="SQUARE">Draft</entry>
|
<entry key="s000002" count="0" red="143" green="240" blue="164" shape="CIRCLE_T">Draft</entry>
|
||||||
<entry key="s000003" count="0" red="50" green="200" blue="0" shape="SQUARE">Finished</entry>
|
<entry key="s000003" count="0" red="249" green="240" blue="107" shape="STAR">Finished</entry>
|
||||||
</status>
|
</status>
|
||||||
<importance>
|
<importance>
|
||||||
<entry key="i000004" count="7" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="i000004" count="7" red="120" green="120" blue="120" shape="SQUARE">New</entry>
|
||||||
<entry key="i000005" count="0" red="200" green="50" blue="0" shape="SQUARE">Minor</entry>
|
<entry key="i000005" count="0" red="220" green="138" blue="221" shape="BLOCK_2">Minor</entry>
|
||||||
<entry key="i000006" count="0" red="200" green="150" blue="0" shape="SQUARE">Major</entry>
|
<entry key="i000006" count="0" red="220" green="138" blue="221" shape="BLOCK_3">Major</entry>
|
||||||
<entry key="i000007" count="0" red="50" green="200" blue="0" shape="SQUARE">Main</entry>
|
<entry key="i000007" count="0" red="220" green="138" blue="221" shape="BLOCK_4">Main</entry>
|
||||||
</importance>
|
</importance>
|
||||||
</settings>
|
</settings>
|
||||||
<content items="12" novelWords="173" notesWords="27" novelChars="1007" notesChars="133">
|
<content items="12" novelWords="173" notesWords="27" novelChars="1007" notesChars="133">
|
||||||
|
|||||||
@@ -16,16 +16,16 @@
|
|||||||
</lastHandle>
|
</lastHandle>
|
||||||
<autoReplace />
|
<autoReplace />
|
||||||
<status>
|
<status>
|
||||||
<entry key="s000000" count="5" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="s000000" count="5" red="120" green="120" blue="120" shape="STAR">New</entry>
|
||||||
<entry key="s000001" count="0" red="200" green="50" blue="0" shape="SQUARE">Note</entry>
|
<entry key="s000001" count="0" red="205" green="171" blue="143" shape="TRIANGLE">Note</entry>
|
||||||
<entry key="s000002" count="0" red="200" green="150" blue="0" shape="SQUARE">Draft</entry>
|
<entry key="s000002" count="0" red="143" green="240" blue="164" shape="CIRCLE_T">Draft</entry>
|
||||||
<entry key="s000003" count="0" red="50" green="200" blue="0" shape="SQUARE">Finished</entry>
|
<entry key="s000003" count="0" red="249" green="240" blue="107" shape="STAR">Finished</entry>
|
||||||
</status>
|
</status>
|
||||||
<importance>
|
<importance>
|
||||||
<entry key="i000004" count="3" red="100" green="100" blue="100" shape="SQUARE">New</entry>
|
<entry key="i000004" count="3" red="120" green="120" blue="120" shape="SQUARE">New</entry>
|
||||||
<entry key="i000005" count="0" red="200" green="50" blue="0" shape="SQUARE">Minor</entry>
|
<entry key="i000005" count="0" red="220" green="138" blue="221" shape="BLOCK_2">Minor</entry>
|
||||||
<entry key="i000006" count="0" red="200" green="150" blue="0" shape="SQUARE">Major</entry>
|
<entry key="i000006" count="0" red="220" green="138" blue="221" shape="BLOCK_3">Major</entry>
|
||||||
<entry key="i000007" count="0" red="50" green="200" blue="0" shape="SQUARE">Main</entry>
|
<entry key="i000007" count="0" red="220" green="138" blue="221" shape="BLOCK_4">Main</entry>
|
||||||
</importance>
|
</importance>
|
||||||
</settings>
|
</settings>
|
||||||
<content items="8" novelWords="9" notesWords="0" novelChars="40" notesChars="0">
|
<content items="8" novelWords="9" notesWords="0" novelChars="40" notesChars="0">
|
||||||
|
|||||||
@@ -37,8 +37,9 @@ from novelwriter.common import (
|
|||||||
formatFileFilter, formatInt, formatTime, formatTimeStamp, formatVersion,
|
formatFileFilter, formatInt, formatTime, formatTimeStamp, formatVersion,
|
||||||
fuzzyTime, getFileSize, hexToInt, isHandle, isItemClass, isItemLayout,
|
fuzzyTime, getFileSize, hexToInt, isHandle, isItemClass, isItemLayout,
|
||||||
isItemType, isListInstance, isTitleTag, jsonEncode, makeFileNameSafe,
|
isItemType, isListInstance, isTitleTag, jsonEncode, makeFileNameSafe,
|
||||||
minmax, numberToRoman, openExternalPath, readTextFile, simplified,
|
minmax, numberToRoman, openExternalPath, processDialogSymbols,
|
||||||
transferCase, uniqueCompact, xmlElement, xmlIndent, xmlSubElem, yesNo
|
readTextFile, simplified, transferCase, uniqueCompact, xmlElement,
|
||||||
|
xmlIndent, xmlSubElem, yesNo
|
||||||
)
|
)
|
||||||
|
|
||||||
from tests.mocked import causeOSError
|
from tests.mocked import causeOSError
|
||||||
@@ -377,6 +378,14 @@ def testBaseCommon_uniqueCompact():
|
|||||||
assert uniqueCompact("3 2 1") == "123"
|
assert uniqueCompact("3 2 1") == "123"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.base
|
||||||
|
def testBaseCommon_processDialogSymbols():
|
||||||
|
"""Test the processDialogSymbols function."""
|
||||||
|
assert processDialogSymbols("abc") == ""
|
||||||
|
assert processDialogSymbols("\u00ab\u00ab\u00bb\u00bb") == "\u00ab\u00bb"
|
||||||
|
assert processDialogSymbols("-\u2013\u2014\u2015") == "\u2013\u2014\u2015"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.base
|
@pytest.mark.base
|
||||||
def testBaseCommon_elide():
|
def testBaseCommon_elide():
|
||||||
"""Test the elide function."""
|
"""Test the elide function."""
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import datetime
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@@ -189,6 +190,14 @@ def testBaseConfig_Localisation(fncPath, tstPaths):
|
|||||||
languages = tstConf.listLanguages(tstConf.LANG_NW)
|
languages = tstConf.listLanguages(tstConf.LANG_NW)
|
||||||
assert languages == [("en_GB", "British English"), ("fr", "Français")]
|
assert languages == [("en_GB", "British English"), ("fr", "Français")]
|
||||||
|
|
||||||
|
# Date Formats
|
||||||
|
# Checks for bug #2325
|
||||||
|
ts = datetime.datetime.fromtimestamp(1746370775)
|
||||||
|
CONFIG._dShortDate = "dd/MM/yyyy"
|
||||||
|
CONFIG._dShortDateTime = "dd/MM/yyyy HH:mm"
|
||||||
|
assert CONFIG.localDate(ts) == ts.strftime("%d/%m/%Y")
|
||||||
|
assert CONFIG.localDateTime(ts) == ts.strftime("%d/%m/%Y %H:%M")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.base
|
@pytest.mark.base
|
||||||
def testBaseConfig_Methods(fncPath):
|
def testBaseConfig_Methods(fncPath):
|
||||||
@@ -233,6 +242,11 @@ def testBaseConfig_Methods(fncPath):
|
|||||||
# Recent Projects
|
# Recent Projects
|
||||||
assert isinstance(tstConf.recentProjects, RecentProjects)
|
assert isinstance(tstConf.recentProjects, RecentProjects)
|
||||||
|
|
||||||
|
# Last Author
|
||||||
|
assert CONFIG.lastAuthor == ""
|
||||||
|
CONFIG.setLastAuthor(" Jane Doe ")
|
||||||
|
assert CONFIG.lastAuthor == "Jane Doe"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.base
|
@pytest.mark.base
|
||||||
def testBaseConfig_SettersGetters(fncPath):
|
def testBaseConfig_SettersGetters(fncPath):
|
||||||
|
|||||||
@@ -23,11 +23,12 @@ from __future__ import annotations
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from PyQt6.QtCore import QMimeData, QModelIndex, Qt
|
from PyQt6.QtCore import QMimeData, QModelIndex, Qt
|
||||||
|
from PyQt6.QtTest import QAbstractItemModelTester
|
||||||
|
|
||||||
from novelwriter.common import decodeMimeHandles
|
from novelwriter.common import decodeMimeHandles
|
||||||
from novelwriter.constants import nwConst
|
from novelwriter.constants import nwConst
|
||||||
from novelwriter.core.item import NWItem
|
from novelwriter.core.item import NWItem
|
||||||
from novelwriter.core.itemmodel import INV_ROOT, NODE_FLAGS, ProjectNode
|
from novelwriter.core.itemmodel import INV_ROOT, NODE_FLAGS, ProjectModel, ProjectNode
|
||||||
from novelwriter.core.project import NWProject
|
from novelwriter.core.project import NWProject
|
||||||
from novelwriter.enum import nwItemLayout, nwItemType
|
from novelwriter.enum import nwItemLayout, nwItemType
|
||||||
|
|
||||||
@@ -253,6 +254,14 @@ def testCoreItemModel_ProjectNode_Data(mockGUI, mockRnd, fncPath):
|
|||||||
assert scene.flags() == NODE_FLAGS | Qt.ItemFlag.ItemIsDragEnabled
|
assert scene.flags() == NODE_FLAGS | Qt.ItemFlag.ItemIsDragEnabled
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.core
|
||||||
|
def testCoreItemModel_ProjectModel_ModelTest(mockGUI):
|
||||||
|
"""Run the Qt model tester on the model."""
|
||||||
|
project = NWProject()
|
||||||
|
model = ProjectModel(project.tree)
|
||||||
|
QAbstractItemModelTester(model)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreItemModel_ProjectModel_Interface(mockGUI, mockRnd, fncPath):
|
def testCoreItemModel_ProjectModel_Interface(mockGUI, mockRnd, fncPath):
|
||||||
"""Test the model interface for the project model."""
|
"""Test the model interface for the project model."""
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from __future__ import annotations
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from PyQt6.QtCore import QModelIndex, Qt
|
from PyQt6.QtCore import QModelIndex, Qt
|
||||||
|
from PyQt6.QtTest import QAbstractItemModelTester
|
||||||
|
|
||||||
from novelwriter.core.indexdata import IndexHeading
|
from novelwriter.core.indexdata import IndexHeading
|
||||||
from novelwriter.core.novelmodel import NovelModel
|
from novelwriter.core.novelmodel import NovelModel
|
||||||
@@ -32,6 +33,13 @@ from novelwriter.enum import nwNovelExtra
|
|||||||
from tests.tools import C, buildTestProject
|
from tests.tools import C, buildTestProject
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.core
|
||||||
|
def testCoreNovelModel_ModelTest(nwGUI):
|
||||||
|
"""Run the Qt model tester on the model."""
|
||||||
|
model = NovelModel()
|
||||||
|
QAbstractItemModelTester(model)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreNovelModel_Interface(nwGUI, fncPath, mockRnd):
|
def testCoreNovelModel_Interface(nwGUI, fncPath, mockRnd):
|
||||||
"""Test the novel model interface."""
|
"""Test the novel model interface."""
|
||||||
|
|||||||
@@ -269,8 +269,8 @@ def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, fncPath, tstPaths):
|
|||||||
prefs.dialogStyle.setCurrentData(3, 0)
|
prefs.dialogStyle.setCurrentData(3, 0)
|
||||||
prefs.allowOpenDial.setChecked(False)
|
prefs.allowOpenDial.setChecked(False)
|
||||||
prefs.dialogLine.setText("–")
|
prefs.dialogLine.setText("–")
|
||||||
prefs.narratorBreak.setText("–")
|
prefs.narratorBreak.setCurrentData("–", "")
|
||||||
prefs.narratorDialog.setText("–")
|
prefs.narratorDialog.setCurrentData("–", "")
|
||||||
prefs.altDialogOpen.setText("<")
|
prefs.altDialogOpen.setText("<")
|
||||||
prefs.altDialogClose.setText(">")
|
prefs.altDialogClose.setText(">")
|
||||||
prefs.highlightEmph.setChecked(False)
|
prefs.highlightEmph.setChecked(False)
|
||||||
|
|||||||
@@ -214,18 +214,18 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, projPath, mockRn
|
|||||||
|
|
||||||
assert update[0][0] == C.sNew
|
assert update[0][0] == C.sNew
|
||||||
assert update[0][1].name == "New"
|
assert update[0][1].name == "New"
|
||||||
assert update[0][1].color == QColor(100, 100, 100)
|
assert update[0][1].color == QColor(120, 120, 120)
|
||||||
assert update[0][1].shape == nwStatusShape.SQUARE
|
assert update[0][1].shape == nwStatusShape.STAR
|
||||||
|
|
||||||
assert update[1][0] == C.sDraft
|
assert update[1][0] == C.sDraft
|
||||||
assert update[1][1].name == "Draft"
|
assert update[1][1].name == "Draft"
|
||||||
assert update[1][1].color == QColor(200, 150, 0)
|
assert update[1][1].color == QColor(143, 240, 164)
|
||||||
assert update[1][1].shape == nwStatusShape.SQUARE
|
assert update[1][1].shape == nwStatusShape.CIRCLE_T
|
||||||
|
|
||||||
assert update[2][0] == C.sFinished
|
assert update[2][0] == C.sFinished
|
||||||
assert update[2][1].name == "Finished"
|
assert update[2][1].name == "Finished"
|
||||||
assert update[2][1].color == QColor(50, 200, 0)
|
assert update[2][1].color == QColor(249, 240, 107)
|
||||||
assert update[2][1].shape == nwStatusShape.SQUARE
|
assert update[2][1].shape == nwStatusShape.STAR
|
||||||
|
|
||||||
assert update[3][0] is None
|
assert update[3][0] is None
|
||||||
assert update[3][1].name == "Final"
|
assert update[3][1].name == "Final"
|
||||||
@@ -289,18 +289,18 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, projPath, mockRn
|
|||||||
|
|
||||||
assert update[0][0] == C.iNew
|
assert update[0][0] == C.iNew
|
||||||
assert update[0][1].name == "New"
|
assert update[0][1].name == "New"
|
||||||
assert update[0][1].color == QColor(100, 100, 100)
|
assert update[0][1].color == QColor(120, 120, 120)
|
||||||
assert update[0][1].shape == nwStatusShape.SQUARE
|
assert update[0][1].shape == nwStatusShape.SQUARE
|
||||||
|
|
||||||
assert update[1][0] == C.iMajor
|
assert update[1][0] == C.iMajor
|
||||||
assert update[1][1].name == "Major"
|
assert update[1][1].name == "Major"
|
||||||
assert update[1][1].color == QColor(200, 150, 0)
|
assert update[1][1].color == QColor(220, 138, 221)
|
||||||
assert update[1][1].shape == nwStatusShape.SQUARE
|
assert update[1][1].shape == nwStatusShape.BLOCK_3
|
||||||
|
|
||||||
assert update[2][0] == C.iMain
|
assert update[2][0] == C.iMain
|
||||||
assert update[2][1].name == "Main"
|
assert update[2][1].name == "Main"
|
||||||
assert update[2][1].color == QColor(50, 200, 0)
|
assert update[2][1].color == QColor(220, 138, 221)
|
||||||
assert update[2][1].shape == nwStatusShape.SQUARE
|
assert update[2][1].shape == nwStatusShape.BLOCK_4
|
||||||
|
|
||||||
assert update[3][0] is None
|
assert update[3][0] is None
|
||||||
assert update[3][1].name == "Final"
|
assert update[3][1].name == "Final"
|
||||||
@@ -354,10 +354,10 @@ def testDlgProjSettings_StatusImportExport(qtbot, monkeypatch, nwGUI, projPath,
|
|||||||
|
|
||||||
assert expFile.is_file() is True
|
assert expFile.is_file() is True
|
||||||
assert expFile.read_text().split() == [
|
assert expFile.read_text().split() == [
|
||||||
"SQUARE,#646464,New",
|
"STAR,#787878,New",
|
||||||
"SQUARE,#c83200,Note",
|
"TRIANGLE,#cdab8f,Note",
|
||||||
"SQUARE,#c89600,Draft",
|
"CIRCLE_T,#8ff0a4,Draft",
|
||||||
"SQUARE,#32c800,Finished",
|
"STAR,#f9f06b,Finished",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Import Error
|
# Import Error
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
|
|||||||
assert item.text(sessLog.C_COUNT) == f"{200:n}"
|
assert item.text(sessLog.C_COUNT) == f"{200:n}"
|
||||||
|
|
||||||
# No Novel Files
|
# No Novel Files
|
||||||
qtbot.mouseClick(sessLog.incNovel, QtMouseLeft)
|
qtbot.mouseClick(sessLog.swtIncNovel, QtMouseLeft)
|
||||||
assert sessLog._saveData(sessLog.FMT_JSON)
|
assert sessLog._saveData(sessLog.FMT_JSON)
|
||||||
|
|
||||||
jsonStats = tstPaths.tmpDir / "sessionStats.json"
|
jsonStats = tstPaths.tmpDir / "sessionStats.json"
|
||||||
@@ -329,8 +329,8 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
|
|||||||
]
|
]
|
||||||
|
|
||||||
# No Note Files
|
# No Note Files
|
||||||
qtbot.mouseClick(sessLog.incNovel, QtMouseLeft)
|
qtbot.mouseClick(sessLog.swtIncNovel, QtMouseLeft)
|
||||||
qtbot.mouseClick(sessLog.incNotes, QtMouseLeft)
|
qtbot.mouseClick(sessLog.swtIncNotes, QtMouseLeft)
|
||||||
assert sessLog._saveData(sessLog.FMT_JSON)
|
assert sessLog._saveData(sessLog.FMT_JSON)
|
||||||
|
|
||||||
jsonStats = tstPaths.tmpDir / "sessionStats.json"
|
jsonStats = tstPaths.tmpDir / "sessionStats.json"
|
||||||
@@ -398,8 +398,8 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
|
|||||||
]
|
]
|
||||||
|
|
||||||
# No Negative Entries
|
# No Negative Entries
|
||||||
qtbot.mouseClick(sessLog.incNotes, QtMouseLeft)
|
qtbot.mouseClick(sessLog.swtIncNotes, QtMouseLeft)
|
||||||
qtbot.mouseClick(sessLog.hideNegative, QtMouseLeft)
|
qtbot.mouseClick(sessLog.swtHideNegative, QtMouseLeft)
|
||||||
assert sessLog._saveData(sessLog.FMT_JSON)
|
assert sessLog._saveData(sessLog.FMT_JSON)
|
||||||
|
|
||||||
jsonStats = tstPaths.tmpDir / "sessionStats.json"
|
jsonStats = tstPaths.tmpDir / "sessionStats.json"
|
||||||
@@ -439,8 +439,8 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
|
|||||||
]
|
]
|
||||||
|
|
||||||
# Un-hide Zero Entries
|
# Un-hide Zero Entries
|
||||||
qtbot.mouseClick(sessLog.hideNegative, QtMouseLeft)
|
qtbot.mouseClick(sessLog.swtHideNegative, QtMouseLeft)
|
||||||
qtbot.mouseClick(sessLog.hideZeros, QtMouseLeft)
|
qtbot.mouseClick(sessLog.swtHideZeros, QtMouseLeft)
|
||||||
assert sessLog._saveData(sessLog.FMT_JSON)
|
assert sessLog._saveData(sessLog.FMT_JSON)
|
||||||
|
|
||||||
jsonStats = tstPaths.tmpDir / "sessionStats.json"
|
jsonStats = tstPaths.tmpDir / "sessionStats.json"
|
||||||
@@ -526,14 +526,14 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
|
|||||||
assert item is not None
|
assert item is not None
|
||||||
assert item.text(sessLog.C_IDLE) == "4 %"
|
assert item.text(sessLog.C_IDLE) == "4 %"
|
||||||
|
|
||||||
qtbot.mouseClick(sessLog.showIdleTime, QtMouseLeft)
|
qtbot.mouseClick(sessLog.swtShowIdleTime, QtMouseLeft)
|
||||||
|
|
||||||
item = sessLog.listBox.topLevelItem(7)
|
item = sessLog.listBox.topLevelItem(7)
|
||||||
assert item is not None
|
assert item is not None
|
||||||
assert item.text(sessLog.C_IDLE) == "00:01:10"
|
assert item.text(sessLog.C_IDLE) == "00:01:10"
|
||||||
|
|
||||||
# Group by Day
|
# Group by Day
|
||||||
qtbot.mouseClick(sessLog.groupByDay, QtMouseLeft)
|
qtbot.mouseClick(sessLog.swtGroupByDay, QtMouseLeft)
|
||||||
assert sessLog._saveData(sessLog.FMT_JSON)
|
assert sessLog._saveData(sessLog.FMT_JSON)
|
||||||
|
|
||||||
jsonStats = tstPaths.tmpDir / "sessionStats.json"
|
jsonStats = tstPaths.tmpDir / "sessionStats.json"
|
||||||
|
|||||||
Reference in New Issue
Block a user