Clean up core structure (#1502)
This commit is contained in:
@@ -121,8 +121,7 @@ def checkUuid(value: Any, default: str) -> str:
|
||||
|
||||
|
||||
def checkPath(value: Any, default: Path) -> Path:
|
||||
"""Check if a value is a valid path. Non-empty strings are accepted.
|
||||
"""
|
||||
"""Check if a value is a valid path."""
|
||||
if isinstance(value, Path):
|
||||
return value
|
||||
elif isinstance(value, str):
|
||||
@@ -289,8 +288,7 @@ def transferCase(source: str, target: str) -> str:
|
||||
|
||||
|
||||
def fuzzyTime(seconds: int) -> str:
|
||||
"""Converts a time difference in seconds into a fuzzy time string.
|
||||
"""
|
||||
"""Convert a time difference in seconds into a fuzzy time string."""
|
||||
if seconds < 0:
|
||||
return QCoreApplication.translate(
|
||||
"Common", "in the future"
|
||||
@@ -350,8 +348,7 @@ def fuzzyTime(seconds: int) -> str:
|
||||
|
||||
|
||||
def numberToRoman(value: int, toLower: bool = False) -> str:
|
||||
"""Convert an integer to a Roman number.
|
||||
"""
|
||||
"""Convert an integer to a Roman number."""
|
||||
if not isinstance(value, int):
|
||||
return "NAN"
|
||||
if value < 1 or value > 4999:
|
||||
@@ -424,12 +421,14 @@ def jsonEncode(data: dict | list | tuple, n: int = 0, nmax: int = 0) -> str:
|
||||
return "".join(buffer)
|
||||
|
||||
|
||||
def xmlIndent(tree: ET.Element | ET.ElementTree):
|
||||
def xmlIndent(tree: ET.Element | ET.ElementTree) -> None:
|
||||
"""A modified version of the XML indent function in the standard
|
||||
library. It behaves more closely to how the one from lxml does.
|
||||
"""
|
||||
if isinstance(tree, ET.ElementTree):
|
||||
tree = tree.getroot()
|
||||
if not isinstance(tree, ET.Element):
|
||||
return
|
||||
|
||||
indentations = ["\n"]
|
||||
|
||||
|
||||
+198
-201
@@ -28,18 +28,23 @@ import json
|
||||
import logging
|
||||
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt5.QtGui import QFontDatabase
|
||||
from PyQt5.QtCore import (
|
||||
QT_VERSION, QT_VERSION_STR, PYQT_VERSION, PYQT_VERSION_STR, QStandardPaths,
|
||||
QSysInfo, QLocale, QLibraryInfo, QTranslator
|
||||
PYQT_VERSION, PYQT_VERSION_STR, QT_VERSION, QT_VERSION_STR, QLibraryInfo,
|
||||
QLocale, QStandardPaths, QSysInfo, QTranslator
|
||||
)
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
|
||||
from novelwriter.error import logException, formatException
|
||||
from novelwriter.common import checkPath, formatTimeStamp, NWConfigParser
|
||||
from novelwriter.error import formatException, logException
|
||||
from novelwriter.common import NWConfigParser, checkInt, checkPath, formatTimeStamp
|
||||
from novelwriter.constants import nwFiles, nwUnicode
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.gui.theme import GuiTheme
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -48,7 +53,7 @@ class Config:
|
||||
LANG_NW = 1
|
||||
LANG_PROJ = 2
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
|
||||
# Initialisation
|
||||
# ==============
|
||||
@@ -64,6 +69,7 @@ class Config:
|
||||
self._confPath = confRoot.absolute() / self.appHandle # The user config location
|
||||
self._dataPath = dataRoot.absolute() / self.appHandle # The user data location
|
||||
self._homePath = Path.home().absolute() # The user's home directory
|
||||
self._backPath = self._homePath / "Backups"
|
||||
|
||||
self._appPath = Path(__file__).parent.absolute()
|
||||
self._appRoot = self._appPath.parent
|
||||
@@ -90,7 +96,8 @@ class Config:
|
||||
# User Settings
|
||||
# =============
|
||||
|
||||
self._recentProj = RecentProjects(self)
|
||||
self._themeObj = None
|
||||
self._recentObj = RecentProjects(self)
|
||||
|
||||
# General GUI Settings
|
||||
self.guiLocale = self._qLocale.name()
|
||||
@@ -102,7 +109,6 @@ class Config:
|
||||
self.hideVScroll = False # Hide vertical scroll bars on main widgets
|
||||
self.hideHScroll = False # Hide horizontal scroll bars on main widgets
|
||||
self.lastNotes = "0x0" # The latest release notes that have been shown
|
||||
self._lastPath = self._homePath # The user's last used path
|
||||
|
||||
# Size Settings
|
||||
self._mainWinSize = [1200, 650] # Last size of the main GUI window
|
||||
@@ -116,7 +122,6 @@ class Config:
|
||||
self.autoSaveProj = 60 # Interval for auto-saving project, in seconds
|
||||
self.autoSaveDoc = 30 # Interval for auto-saving document, in seconds
|
||||
self.emphLabels = True # Add emphasis to H1 and H2 item labels
|
||||
self._backupPath = None # Backup path to use, can be none
|
||||
self.backupOnClose = False # Flag for running automatic backups
|
||||
self.askBeforeBackup = True # Flag for asking before running automatic backup
|
||||
|
||||
@@ -169,6 +174,10 @@ class Config:
|
||||
self.fmtPadAfter = ""
|
||||
self.fmtPadThin = False
|
||||
|
||||
# User Paths
|
||||
self._lastPath = self._homePath # The user's last used path
|
||||
self._backupPath = self._backPath # Backup path to use, can be none
|
||||
|
||||
# Spell Checking Settings
|
||||
self.spellLanguage = "en"
|
||||
|
||||
@@ -228,53 +237,59 @@ class Config:
|
||||
##
|
||||
|
||||
@property
|
||||
def hasError(self):
|
||||
def hasError(self) -> bool:
|
||||
return self._hasError
|
||||
|
||||
@property
|
||||
def recentProjects(self):
|
||||
return self._recentProj
|
||||
def recentProjects(self) -> RecentProjects:
|
||||
return self._recentObj
|
||||
|
||||
@property
|
||||
def mainWinSize(self):
|
||||
def theme(self) -> GuiTheme:
|
||||
if self._themeObj is None:
|
||||
raise Exception("Cannot access GUI theme before it is initialised")
|
||||
return self._themeObj
|
||||
|
||||
@property
|
||||
def mainWinSize(self) -> list[int]:
|
||||
return [int(x*self.guiScale) for x in self._mainWinSize]
|
||||
|
||||
@property
|
||||
def preferencesWinSize(self):
|
||||
def preferencesWinSize(self) -> list[int]:
|
||||
return [int(x*self.guiScale) for x in self._prefsWinSize]
|
||||
|
||||
@property
|
||||
def projLoadColWidths(self):
|
||||
def projLoadColWidths(self) -> list[int]:
|
||||
return [int(x*self.guiScale) for x in self._projLoadCols]
|
||||
|
||||
@property
|
||||
def mainPanePos(self):
|
||||
def mainPanePos(self) -> list[int]:
|
||||
return [int(x*self.guiScale) for x in self._mainPanePos]
|
||||
|
||||
@property
|
||||
def viewPanePos(self):
|
||||
def viewPanePos(self) -> list[int]:
|
||||
return [int(x*self.guiScale) for x in self._viewPanePos]
|
||||
|
||||
@property
|
||||
def outlinePanePos(self):
|
||||
def outlinePanePos(self) -> list[int]:
|
||||
return [int(x*self.guiScale) for x in self._outlnPanePos]
|
||||
|
||||
##
|
||||
# Getters
|
||||
##
|
||||
|
||||
def getTextWidth(self, focusMode=False):
|
||||
def getTextWidth(self, focusMode: bool = False) -> int:
|
||||
"""Get the text with for the correct editor mode."""
|
||||
if focusMode:
|
||||
return self.pxInt(max(self.focusWidth, 200))
|
||||
else:
|
||||
return self.pxInt(max(self.textWidth, 200))
|
||||
|
||||
def getTextMargin(self):
|
||||
def getTextMargin(self) -> int:
|
||||
"""Get the scaled text margin."""
|
||||
return self.pxInt(max(self.textMargin, 0))
|
||||
|
||||
def getTabWidth(self):
|
||||
def getTabWidth(self) -> int:
|
||||
"""Get the scaled tab width."""
|
||||
return self.pxInt(max(self.tabWidth, 0))
|
||||
|
||||
@@ -282,65 +297,70 @@ class Config:
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setMainWinSize(self, newWidth, newHeight):
|
||||
def setThemeInstance(self, theme: GuiTheme) -> None:
|
||||
"""Set the applications theme instance."""
|
||||
self._themeObj = theme
|
||||
return
|
||||
|
||||
def setMainWinSize(self, width: int, height: int) -> None:
|
||||
"""Set the size of the main window, but only if the change is
|
||||
larger than 5 pixels. The OS window manager will sometimes
|
||||
adjust it a bit, and we don't want the main window to shrink or
|
||||
grow each time the app is opened.
|
||||
"""
|
||||
newWidth = int(newWidth/self.guiScale)
|
||||
newHeight = int(newHeight/self.guiScale)
|
||||
if abs(self._mainWinSize[0] - newWidth) > 5:
|
||||
self._mainWinSize[0] = newWidth
|
||||
if abs(self._mainWinSize[1] - newHeight) > 5:
|
||||
self._mainWinSize[1] = newHeight
|
||||
width = int(width/self.guiScale)
|
||||
height = int(height/self.guiScale)
|
||||
if abs(self._mainWinSize[0] - width) > 5:
|
||||
self._mainWinSize[0] = width
|
||||
if abs(self._mainWinSize[1] - height) > 5:
|
||||
self._mainWinSize[1] = height
|
||||
return
|
||||
|
||||
def setPreferencesWinSize(self, newWidth, newHeight):
|
||||
def setPreferencesWinSize(self, width: int, height: int) -> None:
|
||||
"""Set the size of the Preferences dialog window."""
|
||||
self._prefsWinSize[0] = int(newWidth/self.guiScale)
|
||||
self._prefsWinSize[1] = int(newHeight/self.guiScale)
|
||||
self._prefsWinSize[0] = int(width/self.guiScale)
|
||||
self._prefsWinSize[1] = int(height/self.guiScale)
|
||||
return
|
||||
|
||||
def setProjLoadColWidths(self, colWidths):
|
||||
def setProjLoadColWidths(self, widths: list[int]) -> None:
|
||||
"""Set the column widths of the Load Project dialog."""
|
||||
self._projLoadCols = [int(x/self.guiScale) for x in colWidths]
|
||||
self._projLoadCols = [int(x/self.guiScale) for x in widths]
|
||||
return
|
||||
|
||||
def setMainPanePos(self, panePos):
|
||||
def setMainPanePos(self, pos: list[int]) -> None:
|
||||
"""Set the position of the main GUI splitter."""
|
||||
self._mainPanePos = [int(x/self.guiScale) for x in panePos]
|
||||
self._mainPanePos = [int(x/self.guiScale) for x in pos]
|
||||
return
|
||||
|
||||
def setViewPanePos(self, panePos):
|
||||
def setViewPanePos(self, pos: list[int]) -> None:
|
||||
"""Set the position of the viewer meta data splitter."""
|
||||
self._viewPanePos = [int(x/self.guiScale) for x in panePos]
|
||||
self._viewPanePos = [int(x/self.guiScale) for x in pos]
|
||||
return
|
||||
|
||||
def setOutlinePanePos(self, panePos):
|
||||
def setOutlinePanePos(self, pos: list[int]) -> None:
|
||||
"""Set the position of the outline details splitter."""
|
||||
self._outlnPanePos = [int(x/self.guiScale) for x in panePos]
|
||||
self._outlnPanePos = [int(x/self.guiScale) for x in pos]
|
||||
return
|
||||
|
||||
def setLastPath(self, lastPath):
|
||||
def setLastPath(self, path: str | Path) -> None:
|
||||
"""Set the last used path. Only the folder is saved, so if the
|
||||
path is not a folder, the parent of the path is used instead.
|
||||
"""
|
||||
if isinstance(lastPath, (str, Path)):
|
||||
lastPath = checkPath(lastPath, self._homePath)
|
||||
if not lastPath.is_dir():
|
||||
lastPath = lastPath.parent
|
||||
if lastPath.is_dir():
|
||||
self._lastPath = lastPath
|
||||
if isinstance(path, (str, Path)):
|
||||
path = checkPath(path, self._homePath)
|
||||
if not path.is_dir():
|
||||
path = path.parent
|
||||
if path.is_dir():
|
||||
self._lastPath = path
|
||||
logger.debug("Last path updated: %s" % self._lastPath)
|
||||
return
|
||||
|
||||
def setBackupPath(self, backupPath: Path | None):
|
||||
def setBackupPath(self, path: Path | str) -> None:
|
||||
"""Set the current backup path."""
|
||||
self._backupPath = checkPath(backupPath, None)
|
||||
self._backupPath = checkPath(path, self._backPath)
|
||||
return
|
||||
|
||||
def setTextFont(self, family: str | None, pointSize: int = 12):
|
||||
def setTextFont(self, family: str | None, pointSize: int = 12) -> None:
|
||||
"""Set the text font if it exists. If it doesn't, or is None,
|
||||
set to default font.
|
||||
"""
|
||||
@@ -364,15 +384,11 @@ class Config:
|
||||
##
|
||||
|
||||
def pxInt(self, value: int) -> int:
|
||||
"""Used to scale fixed gui sizes by the screen scale factor.
|
||||
This function returns an int, which is always rounded down.
|
||||
"""
|
||||
"""Scale fixed gui sizes by the screen scale factor."""
|
||||
return int(value*self.guiScale)
|
||||
|
||||
def rpxInt(self, value: int) -> int:
|
||||
"""Used to un-scale fixed gui sizes by the screen scale factor.
|
||||
This function returns an int, which is always rounded down.
|
||||
"""
|
||||
"""Un-scale fixed gui sizes by the screen scale factor."""
|
||||
return int(value/self.guiScale)
|
||||
|
||||
def dataPath(self, target: str | None = None) -> Path:
|
||||
@@ -395,12 +411,12 @@ class Config:
|
||||
return self._lastPath
|
||||
return self._homePath
|
||||
|
||||
def backupPath(self) -> Path | None:
|
||||
def backupPath(self) -> Path:
|
||||
"""Return the backup path."""
|
||||
if isinstance(self._backupPath, Path):
|
||||
if self._backupPath.is_dir():
|
||||
return self._backupPath
|
||||
return None
|
||||
return self._backPath
|
||||
|
||||
def errorText(self) -> str:
|
||||
"""Compile and return error messages from the initialisation of
|
||||
@@ -442,7 +458,8 @@ class Config:
|
||||
# Config Actions
|
||||
##
|
||||
|
||||
def initConfig(self, confPath: str | Path | None = None, dataPath: str | Path | None = None):
|
||||
def initConfig(self, confPath: str | Path | None = None,
|
||||
dataPath: str | Path | None = None) -> None:
|
||||
"""Initialise the config class. The manual setting of confPath
|
||||
and dataPath is mainly intended for the test suite.
|
||||
"""
|
||||
@@ -479,16 +496,15 @@ class Config:
|
||||
else:
|
||||
self.saveConfig()
|
||||
|
||||
self._recentProj.loadCache()
|
||||
self._recentObj.loadCache()
|
||||
self._checkOptionalPackages()
|
||||
|
||||
logger.debug("Config initialisation complete")
|
||||
|
||||
return
|
||||
|
||||
def initLocalisation(self, nwApp):
|
||||
"""Initialise the localisation of the GUI.
|
||||
"""
|
||||
def initLocalisation(self, nwApp: QApplication) -> None:
|
||||
"""Initialise the localisation of the GUI."""
|
||||
self._qLocale = QLocale(self.guiLocale)
|
||||
QLocale.setDefault(self._qLocale)
|
||||
self._qtTrans = {}
|
||||
@@ -509,16 +525,15 @@ class Config:
|
||||
|
||||
return
|
||||
|
||||
def loadConfig(self):
|
||||
"""Load preferences from file and replace default settings.
|
||||
"""
|
||||
def loadConfig(self) -> bool:
|
||||
"""Load preferences from file and replace default settings."""
|
||||
logger.debug("Loading config file")
|
||||
|
||||
theConf = NWConfigParser()
|
||||
conf = NWConfigParser()
|
||||
cnfPath = self._confPath / nwFiles.CONF_FILE
|
||||
try:
|
||||
with open(cnfPath, mode="r", encoding="utf-8") as inFile:
|
||||
theConf.read_file(inFile)
|
||||
conf.read_file(inFile)
|
||||
except Exception as exc:
|
||||
logger.error("Could not load config file")
|
||||
logException()
|
||||
@@ -528,98 +543,98 @@ class Config:
|
||||
return False
|
||||
|
||||
# Main
|
||||
cnfSec = "Main"
|
||||
self.guiTheme = theConf.rdStr(cnfSec, "theme", self.guiTheme)
|
||||
self.guiSyntax = theConf.rdStr(cnfSec, "syntax", self.guiSyntax)
|
||||
self.guiFont = theConf.rdStr(cnfSec, "font", self.guiFont)
|
||||
self.guiFontSize = theConf.rdInt(cnfSec, "fontsize", self.guiFontSize)
|
||||
self.guiLocale = theConf.rdStr(cnfSec, "localisation", self.guiLocale)
|
||||
self.hideVScroll = theConf.rdBool(cnfSec, "hidevscroll", self.hideVScroll)
|
||||
self.hideHScroll = theConf.rdBool(cnfSec, "hidehscroll", self.hideHScroll)
|
||||
self.lastNotes = theConf.rdStr(cnfSec, "lastnotes", self.lastNotes)
|
||||
self._lastPath = theConf.rdPath(cnfSec, "lastpath", self._lastPath)
|
||||
sec = "Main"
|
||||
self.guiTheme = conf.rdStr(sec, "theme", self.guiTheme)
|
||||
self.guiSyntax = conf.rdStr(sec, "syntax", self.guiSyntax)
|
||||
self.guiFont = conf.rdStr(sec, "font", self.guiFont)
|
||||
self.guiFontSize = conf.rdInt(sec, "fontsize", self.guiFontSize)
|
||||
self.guiLocale = conf.rdStr(sec, "localisation", self.guiLocale)
|
||||
self.hideVScroll = conf.rdBool(sec, "hidevscroll", self.hideVScroll)
|
||||
self.hideHScroll = conf.rdBool(sec, "hidehscroll", self.hideHScroll)
|
||||
self.lastNotes = conf.rdStr(sec, "lastnotes", self.lastNotes)
|
||||
self._lastPath = conf.rdPath(sec, "lastpath", self._lastPath)
|
||||
|
||||
# Sizes
|
||||
cnfSec = "Sizes"
|
||||
self._mainWinSize = theConf.rdIntList(cnfSec, "mainwindow", self._mainWinSize)
|
||||
self._prefsWinSize = theConf.rdIntList(cnfSec, "preferences", self._prefsWinSize)
|
||||
self._projLoadCols = theConf.rdIntList(cnfSec, "projloadcols", self._projLoadCols)
|
||||
self._mainPanePos = theConf.rdIntList(cnfSec, "mainpane", self._mainPanePos)
|
||||
self._viewPanePos = theConf.rdIntList(cnfSec, "viewpane", self._viewPanePos)
|
||||
self._outlnPanePos = theConf.rdIntList(cnfSec, "outlinepane", self._outlnPanePos)
|
||||
sec = "Sizes"
|
||||
self._mainWinSize = conf.rdIntList(sec, "mainwindow", self._mainWinSize)
|
||||
self._prefsWinSize = conf.rdIntList(sec, "preferences", self._prefsWinSize)
|
||||
self._projLoadCols = conf.rdIntList(sec, "projloadcols", self._projLoadCols)
|
||||
self._mainPanePos = conf.rdIntList(sec, "mainpane", self._mainPanePos)
|
||||
self._viewPanePos = conf.rdIntList(sec, "viewpane", self._viewPanePos)
|
||||
self._outlnPanePos = conf.rdIntList(sec, "outlinepane", self._outlnPanePos)
|
||||
|
||||
# Project
|
||||
cnfSec = "Project"
|
||||
self.autoSaveProj = theConf.rdInt(cnfSec, "autosaveproject", self.autoSaveProj)
|
||||
self.autoSaveDoc = theConf.rdInt(cnfSec, "autosavedoc", self.autoSaveDoc)
|
||||
self.emphLabels = theConf.rdBool(cnfSec, "emphlabels", self.emphLabels)
|
||||
self._backupPath = theConf.rdPath(cnfSec, "backuppath", self._backupPath)
|
||||
self.backupOnClose = theConf.rdBool(cnfSec, "backuponclose", self.backupOnClose)
|
||||
self.askBeforeBackup = theConf.rdBool(cnfSec, "askbeforebackup", self.askBeforeBackup)
|
||||
sec = "Project"
|
||||
self.autoSaveProj = conf.rdInt(sec, "autosaveproject", self.autoSaveProj)
|
||||
self.autoSaveDoc = conf.rdInt(sec, "autosavedoc", self.autoSaveDoc)
|
||||
self.emphLabels = conf.rdBool(sec, "emphlabels", self.emphLabels)
|
||||
self._backupPath = conf.rdPath(sec, "backuppath", self._backupPath)
|
||||
self.backupOnClose = conf.rdBool(sec, "backuponclose", self.backupOnClose)
|
||||
self.askBeforeBackup = conf.rdBool(sec, "askbeforebackup", self.askBeforeBackup)
|
||||
|
||||
# Editor
|
||||
cnfSec = "Editor"
|
||||
self.textFont = theConf.rdStr(cnfSec, "textfont", self.textFont)
|
||||
self.textSize = theConf.rdInt(cnfSec, "textsize", self.textSize)
|
||||
self.textWidth = theConf.rdInt(cnfSec, "width", self.textWidth)
|
||||
self.textMargin = theConf.rdInt(cnfSec, "margin", self.textMargin)
|
||||
self.tabWidth = theConf.rdInt(cnfSec, "tabwidth", self.tabWidth)
|
||||
self.focusWidth = theConf.rdInt(cnfSec, "focuswidth", self.focusWidth)
|
||||
self.hideFocusFooter = theConf.rdBool(cnfSec, "hidefocusfooter", self.hideFocusFooter)
|
||||
self.doJustify = theConf.rdBool(cnfSec, "justify", self.doJustify)
|
||||
self.autoSelect = theConf.rdBool(cnfSec, "autoselect", self.autoSelect)
|
||||
self.doReplace = theConf.rdBool(cnfSec, "autoreplace", self.doReplace)
|
||||
self.doReplaceSQuote = theConf.rdBool(cnfSec, "repsquotes", self.doReplaceSQuote)
|
||||
self.doReplaceDQuote = theConf.rdBool(cnfSec, "repdquotes", self.doReplaceDQuote)
|
||||
self.doReplaceDash = theConf.rdBool(cnfSec, "repdash", self.doReplaceDash)
|
||||
self.doReplaceDots = theConf.rdBool(cnfSec, "repdots", self.doReplaceDots)
|
||||
self.scrollPastEnd = theConf.rdInt(cnfSec, "scrollpastend", self.scrollPastEnd)
|
||||
self.autoScroll = theConf.rdBool(cnfSec, "autoscroll", self.autoScroll)
|
||||
self.autoScrollPos = theConf.rdInt(cnfSec, "autoscrollpos", self.autoScrollPos)
|
||||
self.fmtSQuoteOpen = theConf.rdStr(cnfSec, "fmtsquoteopen", self.fmtSQuoteOpen)
|
||||
self.fmtSQuoteClose = theConf.rdStr(cnfSec, "fmtsquoteclose", self.fmtSQuoteClose)
|
||||
self.fmtDQuoteOpen = theConf.rdStr(cnfSec, "fmtdquoteopen", self.fmtDQuoteOpen)
|
||||
self.fmtDQuoteClose = theConf.rdStr(cnfSec, "fmtdquoteclose", self.fmtDQuoteClose)
|
||||
self.fmtPadBefore = theConf.rdStr(cnfSec, "fmtpadbefore", self.fmtPadBefore)
|
||||
self.fmtPadAfter = theConf.rdStr(cnfSec, "fmtpadafter", self.fmtPadAfter)
|
||||
self.fmtPadThin = theConf.rdBool(cnfSec, "fmtpadthin", self.fmtPadThin)
|
||||
self.spellLanguage = theConf.rdStr(cnfSec, "spellcheck", self.spellLanguage)
|
||||
self.showTabsNSpaces = theConf.rdBool(cnfSec, "showtabsnspaces", self.showTabsNSpaces)
|
||||
self.showLineEndings = theConf.rdBool(cnfSec, "showlineendings", self.showLineEndings)
|
||||
self.showMultiSpaces = theConf.rdBool(cnfSec, "showmultispaces", self.showMultiSpaces)
|
||||
self.wordCountTimer = theConf.rdFlt(cnfSec, "wordcounttimer", self.wordCountTimer)
|
||||
self.bigDocLimit = theConf.rdInt(cnfSec, "bigdoclimit", self.bigDocLimit)
|
||||
self.incNotesWCount = theConf.rdBool(cnfSec, "incnoteswcount", self.incNotesWCount)
|
||||
self.showFullPath = theConf.rdBool(cnfSec, "showfullpath", self.showFullPath)
|
||||
self.highlightQuotes = theConf.rdBool(cnfSec, "highlightquotes", self.highlightQuotes)
|
||||
self.allowOpenSQuote = theConf.rdBool(cnfSec, "allowopensquote", self.allowOpenSQuote)
|
||||
self.allowOpenDQuote = theConf.rdBool(cnfSec, "allowopendquote", self.allowOpenDQuote)
|
||||
self.highlightEmph = theConf.rdBool(cnfSec, "highlightemph", self.highlightEmph)
|
||||
self.stopWhenIdle = theConf.rdBool(cnfSec, "stopwhenidle", self.stopWhenIdle)
|
||||
self.userIdleTime = theConf.rdInt(cnfSec, "useridletime", self.userIdleTime)
|
||||
sec = "Editor"
|
||||
self.textFont = conf.rdStr(sec, "textfont", self.textFont)
|
||||
self.textSize = conf.rdInt(sec, "textsize", self.textSize)
|
||||
self.textWidth = conf.rdInt(sec, "width", self.textWidth)
|
||||
self.textMargin = conf.rdInt(sec, "margin", self.textMargin)
|
||||
self.tabWidth = conf.rdInt(sec, "tabwidth", self.tabWidth)
|
||||
self.focusWidth = conf.rdInt(sec, "focuswidth", self.focusWidth)
|
||||
self.hideFocusFooter = conf.rdBool(sec, "hidefocusfooter", self.hideFocusFooter)
|
||||
self.doJustify = conf.rdBool(sec, "justify", self.doJustify)
|
||||
self.autoSelect = conf.rdBool(sec, "autoselect", self.autoSelect)
|
||||
self.doReplace = conf.rdBool(sec, "autoreplace", self.doReplace)
|
||||
self.doReplaceSQuote = conf.rdBool(sec, "repsquotes", self.doReplaceSQuote)
|
||||
self.doReplaceDQuote = conf.rdBool(sec, "repdquotes", self.doReplaceDQuote)
|
||||
self.doReplaceDash = conf.rdBool(sec, "repdash", self.doReplaceDash)
|
||||
self.doReplaceDots = conf.rdBool(sec, "repdots", self.doReplaceDots)
|
||||
self.scrollPastEnd = conf.rdInt(sec, "scrollpastend", self.scrollPastEnd)
|
||||
self.autoScroll = conf.rdBool(sec, "autoscroll", self.autoScroll)
|
||||
self.autoScrollPos = conf.rdInt(sec, "autoscrollpos", self.autoScrollPos)
|
||||
self.fmtSQuoteOpen = conf.rdStr(sec, "fmtsquoteopen", self.fmtSQuoteOpen)
|
||||
self.fmtSQuoteClose = conf.rdStr(sec, "fmtsquoteclose", self.fmtSQuoteClose)
|
||||
self.fmtDQuoteOpen = conf.rdStr(sec, "fmtdquoteopen", self.fmtDQuoteOpen)
|
||||
self.fmtDQuoteClose = conf.rdStr(sec, "fmtdquoteclose", self.fmtDQuoteClose)
|
||||
self.fmtPadBefore = conf.rdStr(sec, "fmtpadbefore", self.fmtPadBefore)
|
||||
self.fmtPadAfter = conf.rdStr(sec, "fmtpadafter", self.fmtPadAfter)
|
||||
self.fmtPadThin = conf.rdBool(sec, "fmtpadthin", self.fmtPadThin)
|
||||
self.spellLanguage = conf.rdStr(sec, "spellcheck", self.spellLanguage)
|
||||
self.showTabsNSpaces = conf.rdBool(sec, "showtabsnspaces", self.showTabsNSpaces)
|
||||
self.showLineEndings = conf.rdBool(sec, "showlineendings", self.showLineEndings)
|
||||
self.showMultiSpaces = conf.rdBool(sec, "showmultispaces", self.showMultiSpaces)
|
||||
self.wordCountTimer = conf.rdFlt(sec, "wordcounttimer", self.wordCountTimer)
|
||||
self.bigDocLimit = conf.rdInt(sec, "bigdoclimit", self.bigDocLimit)
|
||||
self.incNotesWCount = conf.rdBool(sec, "incnoteswcount", self.incNotesWCount)
|
||||
self.showFullPath = conf.rdBool(sec, "showfullpath", self.showFullPath)
|
||||
self.highlightQuotes = conf.rdBool(sec, "highlightquotes", self.highlightQuotes)
|
||||
self.allowOpenSQuote = conf.rdBool(sec, "allowopensquote", self.allowOpenSQuote)
|
||||
self.allowOpenDQuote = conf.rdBool(sec, "allowopendquote", self.allowOpenDQuote)
|
||||
self.highlightEmph = conf.rdBool(sec, "highlightemph", self.highlightEmph)
|
||||
self.stopWhenIdle = conf.rdBool(sec, "stopwhenidle", self.stopWhenIdle)
|
||||
self.userIdleTime = conf.rdInt(sec, "useridletime", self.userIdleTime)
|
||||
|
||||
# State
|
||||
cnfSec = "State"
|
||||
self.showRefPanel = theConf.rdBool(cnfSec, "showrefpanel", self.showRefPanel)
|
||||
self.viewComments = theConf.rdBool(cnfSec, "viewcomments", self.viewComments)
|
||||
self.viewSynopsis = theConf.rdBool(cnfSec, "viewsynopsis", self.viewSynopsis)
|
||||
self.searchCase = theConf.rdBool(cnfSec, "searchcase", self.searchCase)
|
||||
self.searchWord = theConf.rdBool(cnfSec, "searchword", self.searchWord)
|
||||
self.searchRegEx = theConf.rdBool(cnfSec, "searchregex", self.searchRegEx)
|
||||
self.searchLoop = theConf.rdBool(cnfSec, "searchloop", self.searchLoop)
|
||||
self.searchNextFile = theConf.rdBool(cnfSec, "searchnextfile", self.searchNextFile)
|
||||
self.searchMatchCap = theConf.rdBool(cnfSec, "searchmatchcap", self.searchMatchCap)
|
||||
sec = "State"
|
||||
self.showRefPanel = conf.rdBool(sec, "showrefpanel", self.showRefPanel)
|
||||
self.viewComments = conf.rdBool(sec, "viewcomments", self.viewComments)
|
||||
self.viewSynopsis = conf.rdBool(sec, "viewsynopsis", self.viewSynopsis)
|
||||
self.searchCase = conf.rdBool(sec, "searchcase", self.searchCase)
|
||||
self.searchWord = conf.rdBool(sec, "searchword", self.searchWord)
|
||||
self.searchRegEx = conf.rdBool(sec, "searchregex", self.searchRegEx)
|
||||
self.searchLoop = conf.rdBool(sec, "searchloop", self.searchLoop)
|
||||
self.searchNextFile = conf.rdBool(sec, "searchnextfile", self.searchNextFile)
|
||||
self.searchMatchCap = conf.rdBool(sec, "searchmatchcap", self.searchMatchCap)
|
||||
|
||||
# Deprecated Settings or Locations as of 2.0
|
||||
# ToDo: These will be loaded for a few minor releases until the users have converted them
|
||||
self.guiFont = theConf.rdStr("Main", "guifont", self.guiFont)
|
||||
self.guiFontSize = theConf.rdInt("Main", "guifontsize", self.guiFontSize)
|
||||
self.guiLocale = theConf.rdStr("Main", "guilang", self.guiLocale)
|
||||
self._backupPath = theConf.rdPath("Backup", "backuppath", self._backupPath)
|
||||
self.backupOnClose = theConf.rdBool("Backup", "backuponclose", self.backupOnClose)
|
||||
self.askBeforeBackup = theConf.rdBool("Backup", "askbeforebackup", self.askBeforeBackup)
|
||||
fmtSingleQuotes = theConf.rdStrList(cnfSec, "fmtsinglequote", [])
|
||||
fmtDoubleQuotes = theConf.rdStrList(cnfSec, "fmtdoublequote", [])
|
||||
self.guiFont = conf.rdStr("Main", "guifont", self.guiFont)
|
||||
self.guiFontSize = conf.rdInt("Main", "guifontsize", self.guiFontSize)
|
||||
self.guiLocale = conf.rdStr("Main", "guilang", self.guiLocale)
|
||||
self._backupPath = conf.rdPath("Backup", "backuppath", self._backupPath)
|
||||
self.backupOnClose = conf.rdBool("Backup", "backuponclose", self.backupOnClose)
|
||||
self.askBeforeBackup = conf.rdBool("Backup", "askbeforebackup", self.askBeforeBackup)
|
||||
fmtSingleQuotes = conf.rdStrList(sec, "fmtsinglequote", [])
|
||||
fmtDoubleQuotes = conf.rdStrList(sec, "fmtdoublequote", [])
|
||||
|
||||
if isinstance(fmtSingleQuotes, list) and len(fmtSingleQuotes) == 2:
|
||||
self.fmtSQuoteOpen = fmtSingleQuotes[0]
|
||||
@@ -631,9 +646,6 @@ class Config:
|
||||
# Check Values
|
||||
# ============
|
||||
|
||||
# Check Certain Values for None
|
||||
self.spellLanguage = self._checkNone(self.spellLanguage)
|
||||
|
||||
# If we're using straight quotes, disable auto-replace
|
||||
if self.fmtSQuoteOpen == self.fmtSQuoteClose == "'" and self.doReplaceSQuote:
|
||||
logger.info("Using straight single quotes, so disabling auto-replace")
|
||||
@@ -645,18 +657,17 @@ class Config:
|
||||
|
||||
return True
|
||||
|
||||
def saveConfig(self):
|
||||
"""Save the current preferences to file.
|
||||
"""
|
||||
def saveConfig(self) -> bool:
|
||||
"""Save the current preferences to file."""
|
||||
logger.debug("Saving config file")
|
||||
|
||||
theConf = NWConfigParser()
|
||||
conf = NWConfigParser()
|
||||
|
||||
theConf["Meta"] = {
|
||||
conf["Meta"] = {
|
||||
"timestamp": formatTimeStamp(time()),
|
||||
}
|
||||
|
||||
theConf["Main"] = {
|
||||
conf["Main"] = {
|
||||
"theme": str(self.guiTheme),
|
||||
"syntax": str(self.guiSyntax),
|
||||
"font": str(self.guiFont),
|
||||
@@ -668,7 +679,7 @@ class Config:
|
||||
"lastpath": str(self._lastPath),
|
||||
}
|
||||
|
||||
theConf["Sizes"] = {
|
||||
conf["Sizes"] = {
|
||||
"mainwindow": self._packList(self._mainWinSize),
|
||||
"preferences": self._packList(self._prefsWinSize),
|
||||
"projloadcols": self._packList(self._projLoadCols),
|
||||
@@ -677,16 +688,16 @@ class Config:
|
||||
"outlinepane": self._packList(self._outlnPanePos),
|
||||
}
|
||||
|
||||
theConf["Project"] = {
|
||||
conf["Project"] = {
|
||||
"autosaveproject": str(self.autoSaveProj),
|
||||
"autosavedoc": str(self.autoSaveDoc),
|
||||
"emphlabels": str(self.emphLabels),
|
||||
"backuppath": str(self._backupPath or ""),
|
||||
"backuppath": str(self._backupPath),
|
||||
"backuponclose": str(self.backupOnClose),
|
||||
"askbeforebackup": str(self.askBeforeBackup),
|
||||
}
|
||||
|
||||
theConf["Editor"] = {
|
||||
conf["Editor"] = {
|
||||
"textfont": str(self.textFont),
|
||||
"textsize": str(self.textSize),
|
||||
"width": str(self.textWidth),
|
||||
@@ -727,7 +738,7 @@ class Config:
|
||||
"useridletime": str(self.userIdleTime),
|
||||
}
|
||||
|
||||
theConf["State"] = {
|
||||
conf["State"] = {
|
||||
"showrefpanel": str(self.showRefPanel),
|
||||
"viewcomments": str(self.viewComments),
|
||||
"viewsynopsis": str(self.viewSynopsis),
|
||||
@@ -743,7 +754,7 @@ class Config:
|
||||
cnfPath = self._confPath / nwFiles.CONF_FILE
|
||||
try:
|
||||
with open(cnfPath, mode="w", encoding="utf-8") as outFile:
|
||||
theConf.write(outFile)
|
||||
conf.write(outFile)
|
||||
except Exception as exc:
|
||||
logger.error("Could not save config file")
|
||||
logException()
|
||||
@@ -758,26 +769,14 @@ class Config:
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _packList(self, inData):
|
||||
def _packList(self, data: list) -> str:
|
||||
"""Pack a list of items into a comma-separated string for saving
|
||||
to the config file.
|
||||
"""
|
||||
return ", ".join([str(inVal) for inVal in inData])
|
||||
return ", ".join([str(inVal) for inVal in data])
|
||||
|
||||
def _checkNone(self, checkVal):
|
||||
"""Return a NoneType if the value corresponds to None, otherwise
|
||||
return the value unchanged.
|
||||
"""
|
||||
if checkVal is None:
|
||||
return None
|
||||
if isinstance(checkVal, str):
|
||||
if checkVal.lower() == "none":
|
||||
return None
|
||||
return checkVal
|
||||
|
||||
def _checkOptionalPackages(self):
|
||||
"""Check if we have the optional packages used by some features.
|
||||
"""
|
||||
def _checkOptionalPackages(self) -> None:
|
||||
"""Check optional packages used by some features."""
|
||||
try:
|
||||
import enchant # noqa: F401
|
||||
except ImportError:
|
||||
@@ -793,14 +792,13 @@ class Config:
|
||||
|
||||
class RecentProjects:
|
||||
|
||||
def __init__(self, config):
|
||||
def __init__(self, config: Config) -> None:
|
||||
self._conf = config
|
||||
self._data = {}
|
||||
return
|
||||
|
||||
def loadCache(self):
|
||||
"""Load the cache file for recent projects.
|
||||
"""
|
||||
def loadCache(self) -> bool:
|
||||
"""Load the cache file for recent projects."""
|
||||
self._data = {}
|
||||
|
||||
cacheFile = self._conf.dataPath(nwFiles.RECENT_FILE)
|
||||
@@ -823,9 +821,8 @@ class RecentProjects:
|
||||
|
||||
return True
|
||||
|
||||
def saveCache(self):
|
||||
"""Save the cache dictionary of recent projects.
|
||||
"""
|
||||
def saveCache(self) -> bool:
|
||||
"""Save the cache dictionary of recent projects."""
|
||||
cacheFile = self._conf.dataPath(nwFiles.RECENT_FILE)
|
||||
cacheTemp = cacheFile.with_suffix(".tmp")
|
||||
try:
|
||||
@@ -839,27 +836,27 @@ class RecentProjects:
|
||||
|
||||
return True
|
||||
|
||||
def listEntries(self):
|
||||
"""List all items in the cache.
|
||||
"""
|
||||
return [(k, e["title"], e["words"], e["time"]) for k, e in self._data.items()]
|
||||
def listEntries(self) -> list[tuple[str, str, int, int]]:
|
||||
"""List all items in the cache."""
|
||||
return [
|
||||
(str(k), str(e["title"]), checkInt(e["words"], 0), checkInt(e["time"], 0))
|
||||
for k, e in self._data.items()
|
||||
]
|
||||
|
||||
def update(self, projPath, projTitle, wordCount, saveTime):
|
||||
"""Add or update recent cache information on a given project.
|
||||
"""
|
||||
self._data[str(projPath)] = {
|
||||
"title": projTitle,
|
||||
"words": int(wordCount),
|
||||
"time": int(saveTime),
|
||||
def update(self, path: str | Path, title: str, words: int, saved: float | int) -> None:
|
||||
"""Add or update recent cache information on a given project."""
|
||||
self._data[str(path)] = {
|
||||
"title": title,
|
||||
"words": int(words),
|
||||
"time": int(saved),
|
||||
}
|
||||
self.saveCache()
|
||||
return
|
||||
|
||||
def remove(self, projPath):
|
||||
"""Try to remove a path from the recent projects cache.
|
||||
"""
|
||||
if self._data.pop(str(projPath), None) is not None:
|
||||
logger.debug("Removed recent: %s", projPath)
|
||||
def remove(self, path: str | Path) -> None:
|
||||
"""Try to remove a path from the recent projects cache."""
|
||||
if self._data.pop(str(path), None) is not None:
|
||||
logger.debug("Removed recent: %s", path)
|
||||
self.saveCache()
|
||||
return
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ class BuildSettings:
|
||||
The settings can be packed/unpacked to/from a dictionary for JSON.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
self._name = ""
|
||||
self._uuid = str(uuid.uuid4())
|
||||
self._path = Path.home()
|
||||
@@ -239,12 +239,12 @@ class BuildSettings:
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setName(self, name: str):
|
||||
def setName(self, name: str) -> None:
|
||||
"""Set the build setting display name."""
|
||||
self._name = str(name)
|
||||
return
|
||||
|
||||
def setBuildID(self, value: str | uuid.UUID):
|
||||
def setBuildID(self, value: str | uuid.UUID) -> None:
|
||||
"""Set a UUID build ID."""
|
||||
value = checkUuid(value, "")
|
||||
if not value:
|
||||
@@ -253,7 +253,7 @@ class BuildSettings:
|
||||
self._uuid = value
|
||||
return
|
||||
|
||||
def setLastPath(self, path: Path | str | None):
|
||||
def setLastPath(self, path: Path | str | None) -> None:
|
||||
"""Set the last used build path."""
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
@@ -264,41 +264,41 @@ class BuildSettings:
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def setLastBuildName(self, name: str):
|
||||
def setLastBuildName(self, name: str) -> None:
|
||||
"""Set the last used build name."""
|
||||
self._build = str(name).strip()
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def setLastFormat(self, value: nwBuildFmt):
|
||||
def setLastFormat(self, value: nwBuildFmt) -> None:
|
||||
"""Set the last used build format."""
|
||||
if isinstance(value, nwBuildFmt):
|
||||
self._format = value
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def setFiltered(self, tHandle: str):
|
||||
def setFiltered(self, tHandle: str) -> None:
|
||||
"""Set an item as filtered."""
|
||||
self._excluded.discard(tHandle)
|
||||
self._included.discard(tHandle)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def setIncluded(self, tHandle: str):
|
||||
def setIncluded(self, tHandle: str) -> None:
|
||||
"""Set an item as explicitly included."""
|
||||
self._excluded.discard(tHandle)
|
||||
self._included.add(tHandle)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def setExcluded(self, tHandle: str):
|
||||
def setExcluded(self, tHandle: str) -> None:
|
||||
"""Set an item as explicitly excluded."""
|
||||
self._excluded.add(tHandle)
|
||||
self._included.discard(tHandle)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def setAllowRoot(self, tHandle: str, state: bool):
|
||||
def setAllowRoot(self, tHandle: str, state: bool) -> None:
|
||||
"""Set a specific root folder as allowed or not."""
|
||||
if state is True:
|
||||
self._skipRoot.discard(tHandle)
|
||||
@@ -386,7 +386,7 @@ class BuildSettings:
|
||||
|
||||
return result
|
||||
|
||||
def resetChangedState(self):
|
||||
def resetChangedState(self) -> None:
|
||||
"""Reset the changed status of the settings object. This must be
|
||||
called when the changes have been safely saved or passed on.
|
||||
"""
|
||||
@@ -410,7 +410,7 @@ class BuildSettings:
|
||||
}
|
||||
}
|
||||
|
||||
def unpack(self, data: dict):
|
||||
def unpack(self, data: dict) -> None:
|
||||
"""Unpack a dictionary and populate the class."""
|
||||
settings = data.get("settings", {})
|
||||
content = data.get("content", {})
|
||||
@@ -454,13 +454,13 @@ class BuildCollection:
|
||||
project folder.
|
||||
"""
|
||||
|
||||
def __init__(self, project: NWProject):
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
self._project = project
|
||||
self._builds = {}
|
||||
self._loadCollection()
|
||||
return
|
||||
|
||||
def __len__(self):
|
||||
def __len__(self) -> int:
|
||||
"""Return the number of builds."""
|
||||
return len(self._builds)
|
||||
|
||||
@@ -476,7 +476,7 @@ class BuildCollection:
|
||||
build.unpack(self._builds[buildID])
|
||||
return build
|
||||
|
||||
def setBuild(self, build: BuildSettings):
|
||||
def setBuild(self, build: BuildSettings) -> None:
|
||||
"""Set build settings data in the collection."""
|
||||
if isinstance(build, BuildSettings):
|
||||
buildID = build.buildID
|
||||
@@ -484,7 +484,7 @@ class BuildCollection:
|
||||
self._saveCollection()
|
||||
return
|
||||
|
||||
def removeBuild(self, buildID: str):
|
||||
def removeBuild(self, buildID: str) -> None:
|
||||
"""Remove the a build from the collection."""
|
||||
self._builds.pop(buildID, None)
|
||||
self._saveCollection()
|
||||
|
||||
@@ -80,7 +80,7 @@ class DocMerger:
|
||||
and a new doc label. Calling this function resets the class.
|
||||
"""
|
||||
srcItem = self._project.tree[srcHandle]
|
||||
if srcItem is None:
|
||||
if srcItem is None or srcItem.itemParent is None:
|
||||
return None
|
||||
|
||||
newHandle = self._project.newFile(docLabel, srcItem.itemParent)
|
||||
@@ -210,7 +210,7 @@ class DocSplitter:
|
||||
"""An iterator that will write each document in the buffer, and
|
||||
return its new handle, parent handle, and sibling handle.
|
||||
"""
|
||||
if self._srcHandle is None or self._srcItem is None:
|
||||
if self._srcHandle is None or self._srcItem is None or self._parHandle is None:
|
||||
return
|
||||
|
||||
pHandle = self._parHandle
|
||||
@@ -385,9 +385,10 @@ class ProjectBuilder:
|
||||
aDoc = project.storage.getDocument(hChapter)
|
||||
aDoc.writeDocument(f"## {lblNewChapter}\n\n")
|
||||
|
||||
hScene = project.newFile(lblNewScene, hChapter)
|
||||
aDoc = project.storage.getDocument(hScene)
|
||||
aDoc.writeDocument(f"### {lblNewScene}\n\n")
|
||||
if hChapter:
|
||||
hScene = project.newFile(lblNewScene, hChapter)
|
||||
aDoc = project.storage.getDocument(hScene)
|
||||
aDoc.writeDocument(f"### {lblNewScene}\n\n")
|
||||
|
||||
project.newRoot(nwItemClass.PLOT)
|
||||
project.newRoot(nwItemClass.CHARACTER)
|
||||
@@ -418,7 +419,7 @@ class ProjectBuilder:
|
||||
aDoc.writeDocument(f"## {chTitle}\n\n% Synopsis: {chSynop}\n\n")
|
||||
|
||||
# Create chapter scenes
|
||||
if numScenes > 0:
|
||||
if numScenes > 0 and cHandle:
|
||||
for sc in range(numScenes):
|
||||
scTitle = self.tr("Scene {0}").format(f"{ch+1:d}.{sc+1:d}")
|
||||
sHandle = project.newFile(scTitle, cHandle)
|
||||
|
||||
@@ -54,7 +54,7 @@ class NWBuildDocument:
|
||||
|
||||
__slots__ = ("_project", "_build", "_queue", "_error", "_cache")
|
||||
|
||||
def __init__(self, project: NWProject, build: BuildSettings):
|
||||
def __init__(self, project: NWProject, build: BuildSettings) -> None:
|
||||
self._project = project
|
||||
self._build = build
|
||||
self._queue = []
|
||||
@@ -91,12 +91,12 @@ class NWBuildDocument:
|
||||
# Methods
|
||||
##
|
||||
|
||||
def addDocument(self, tHandle: str):
|
||||
def addDocument(self, tHandle: str) -> None:
|
||||
"""Add a document to the build queue manually."""
|
||||
self._queue.append(tHandle)
|
||||
return
|
||||
|
||||
def queueAll(self):
|
||||
def queueAll(self) -> None:
|
||||
"""Queue all document as defined by the build settings."""
|
||||
self._queue = []
|
||||
filtered = self._build.buildItemFilter(self._project)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – Project Wrapper
|
||||
=============================
|
||||
The parent class for a novelWriter project
|
||||
|
||||
File History:
|
||||
Created: 2018-09-29 [0.0.1]
|
||||
@@ -416,14 +415,6 @@ class NWProject(QObject):
|
||||
logger.info("Backing up project")
|
||||
self.mainGui.setStatus(self.tr("Backing up project ..."))
|
||||
|
||||
backupPath = CONFIG.backupPath()
|
||||
if not isinstance(backupPath, Path):
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Cannot backup project because no valid backup path is set. "
|
||||
"Please set a valid backup location in Preferences."
|
||||
), level=nwAlert.ERROR)
|
||||
return False
|
||||
|
||||
if not self._data.name:
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Cannot backup project because no project name is set. "
|
||||
@@ -432,9 +423,10 @@ class NWProject(QObject):
|
||||
return False
|
||||
|
||||
cleanName = makeFileNameSafe(self._data.name)
|
||||
backupPath = CONFIG.backupPath()
|
||||
baseDir = backupPath / cleanName
|
||||
try:
|
||||
baseDir.mkdir(exist_ok=True)
|
||||
baseDir.mkdir(exist_ok=True, parents=True)
|
||||
except Exception as exc:
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Could not create backup folder."
|
||||
@@ -444,11 +436,12 @@ class NWProject(QObject):
|
||||
timeStamp = formatTimeStamp(time(), fileSafe=True)
|
||||
archName = baseDir / f"{cleanName} {timeStamp}.zip"
|
||||
if self._storage.zipIt(archName, compression=2):
|
||||
size = archName.stat().st_size
|
||||
size = formatInt(archName.stat().st_size)
|
||||
if doNotify:
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Backup archive file written to: {0} [{1}B]"
|
||||
).format(str(archName), formatInt(size)))
|
||||
self.mainGui.makeAlert(
|
||||
self.tr("Created a backup of your project of size {0}B.").format(size),
|
||||
info=self.tr("Path: {0}").format(str(backupPath))
|
||||
)
|
||||
else:
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Could not write backup archive."
|
||||
|
||||
@@ -26,13 +26,16 @@ from __future__ import annotations
|
||||
import uuid
|
||||
import logging
|
||||
|
||||
from typing import Any
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from novelwriter.common import (
|
||||
checkBool, checkInt, checkStringNone, checkUuid, isHandle, simplified
|
||||
)
|
||||
from novelwriter.core.status import NWStatus
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -43,9 +46,9 @@ class NWProjectData:
|
||||
the list of project items.
|
||||
"""
|
||||
|
||||
def __init__(self, theProject):
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
|
||||
self.theProject = theProject
|
||||
self._project = project
|
||||
|
||||
# Project Meta
|
||||
self._uuid = ""
|
||||
@@ -184,16 +187,16 @@ class NWProjectData:
|
||||
# Methods
|
||||
##
|
||||
|
||||
def incSaveCount(self):
|
||||
def incSaveCount(self) -> None:
|
||||
"""Increment the save count by one."""
|
||||
self._saveCount += 1
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def incAutoCount(self):
|
||||
def incAutoCount(self) -> None:
|
||||
"""Increment the auto save count by one."""
|
||||
self._autoCount += 1
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
##
|
||||
@@ -208,93 +211,93 @@ class NWProjectData:
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setUuid(self, value: Any):
|
||||
def setUuid(self, value: Any) -> None:
|
||||
"""Set the project id."""
|
||||
value = checkUuid(value, "")
|
||||
if not value:
|
||||
self._uuid = str(uuid.uuid4())
|
||||
elif value != self._uuid:
|
||||
self._uuid = value
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setName(self, value: str | None):
|
||||
def setName(self, value: str | None) -> None:
|
||||
"""Set a new project name."""
|
||||
if value != self._name:
|
||||
self._name = simplified(str(value or ""))
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setTitle(self, value: str | None):
|
||||
def setTitle(self, value: str | None) -> None:
|
||||
"""Set a new novel title."""
|
||||
if value != self._title:
|
||||
self._title = simplified(str(value or ""))
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setAuthor(self, value: str | None):
|
||||
def setAuthor(self, value: str | None) -> None:
|
||||
"""Set the author value."""
|
||||
if value != self._title:
|
||||
self._author = simplified(str(value or ""))
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setSaveCount(self, value: Any):
|
||||
def setSaveCount(self, value: Any) -> None:
|
||||
"""Set the save count from last session."""
|
||||
self._saveCount = checkInt(value, 0)
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setAutoCount(self, value: Any):
|
||||
def setAutoCount(self, value: Any) -> None:
|
||||
"""Set the auto save count from last session."""
|
||||
self._autoCount = checkInt(value, 0)
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setEditTime(self, value: Any):
|
||||
def setEditTime(self, value: Any) -> None:
|
||||
"""Set the edit time from last session."""
|
||||
self._editTime = checkInt(value, 0)
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setDoBackup(self, value: Any):
|
||||
def setDoBackup(self, value: Any) -> None:
|
||||
"""Set the do write backup flag."""
|
||||
if value != self._doBackup:
|
||||
self._doBackup = checkBool(value, False)
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setLanguage(self, value: str | None):
|
||||
def setLanguage(self, value: str | None) -> None:
|
||||
"""Set the project language."""
|
||||
if value != self._language:
|
||||
self._language = checkStringNone(value, None)
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setSpellCheck(self, value: Any):
|
||||
def setSpellCheck(self, value: Any) -> None:
|
||||
"""Set the spell check flag."""
|
||||
if value != self._spellCheck:
|
||||
self._spellCheck = checkBool(value, False)
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setSpellLang(self, value: str | None):
|
||||
def setSpellLang(self, value: str | None) -> None:
|
||||
"""Set the spell check language."""
|
||||
if value != self._spellLang:
|
||||
self._spellLang = checkStringNone(value, None)
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setLastHandle(self, value: str | None, component: str):
|
||||
def setLastHandle(self, value: str | None, component: str) -> None:
|
||||
"""Set a last used handle into the handle registry for a given
|
||||
component.
|
||||
"""
|
||||
if isinstance(component, str):
|
||||
self._lastHandle[component] = checkStringNone(value, None)
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setLastHandles(self, value: dict):
|
||||
def setLastHandles(self, value: dict) -> None:
|
||||
"""Set the full last handles dictionary to a new set of values.
|
||||
This is intended to be used at project load.
|
||||
"""
|
||||
@@ -302,10 +305,10 @@ class NWProjectData:
|
||||
for key, entry in value.items():
|
||||
if key in self._lastHandle:
|
||||
self._lastHandle[key] = str(entry) if isHandle(entry) else None
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setInitCounts(self, novel: Any = None, notes: Any = None):
|
||||
def setInitCounts(self, novel: Any = None, notes: Any = None) -> None:
|
||||
"""Set the word count totals for novel and note files."""
|
||||
if novel is not None:
|
||||
self._initCounts[0] = checkInt(novel, 0)
|
||||
@@ -315,7 +318,7 @@ class NWProjectData:
|
||||
self._currCounts[1] = checkInt(notes, 0)
|
||||
return
|
||||
|
||||
def setCurrCounts(self, novel: Any = None, notes: Any = None):
|
||||
def setCurrCounts(self, novel: Any = None, notes: Any = None) -> None:
|
||||
"""Set the word count totals for novel and note files."""
|
||||
if novel is not None:
|
||||
self._currCounts[0] = checkInt(novel, 0)
|
||||
@@ -323,14 +326,14 @@ class NWProjectData:
|
||||
self._currCounts[1] = checkInt(notes, 0)
|
||||
return
|
||||
|
||||
def setAutoReplace(self, value: dict):
|
||||
def setAutoReplace(self, value: dict) -> None:
|
||||
"""Set the auto-replace dictionary."""
|
||||
if isinstance(value, dict):
|
||||
self._autoReplace = {}
|
||||
for key, entry in value.items():
|
||||
if isinstance(entry, str):
|
||||
self._autoReplace[key] = simplified(entry)
|
||||
self.theProject.setProjectChanged(True)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
# END Class NWProjectData
|
||||
|
||||
@@ -110,7 +110,7 @@ class ProjectXMLReader:
|
||||
Rev 1: Drops the titleFormat section of settings.
|
||||
"""
|
||||
|
||||
def __init__(self, path):
|
||||
def __init__(self, path: str | Path) -> None:
|
||||
self._path = Path(path)
|
||||
self._state = XMLReadState.NO_ACTION
|
||||
self._root = ""
|
||||
@@ -236,7 +236,7 @@ class ProjectXMLReader:
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _parseProjectMeta(self, xSection: ET.Element, data: NWProjectData):
|
||||
def _parseProjectMeta(self, xSection: ET.Element, data: NWProjectData) -> None:
|
||||
"""Parse the project section of the XML file."""
|
||||
logger.debug("Parsing <project> section")
|
||||
|
||||
@@ -267,7 +267,7 @@ class ProjectXMLReader:
|
||||
|
||||
return
|
||||
|
||||
def _parseProjectSettings(self, xSection: ET.Element, data: NWProjectData):
|
||||
def _parseProjectSettings(self, xSection: ET.Element, data: NWProjectData) -> None:
|
||||
"""Parse the settings section of the XML file."""
|
||||
logger.debug("Parsing <settings> section")
|
||||
|
||||
@@ -307,7 +307,9 @@ class ProjectXMLReader:
|
||||
|
||||
return
|
||||
|
||||
def _parseProjectContent(self, xSection: ET.Element, data: NWProjectData, content: list):
|
||||
def _parseProjectContent(
|
||||
self, xSection: ET.Element, data: NWProjectData, content: list
|
||||
) -> None:
|
||||
"""Parse the content section of the XML file."""
|
||||
logger.debug("Parsing <content> section")
|
||||
|
||||
@@ -362,7 +364,9 @@ class ProjectXMLReader:
|
||||
|
||||
return
|
||||
|
||||
def _parseProjectContentLegacy(self, xSection: ET.Element, data: NWProjectData, content: list):
|
||||
def _parseProjectContentLegacy(
|
||||
self, xSection: ET.Element, data: NWProjectData, content: list
|
||||
) -> None:
|
||||
"""Parse the content section of the XML file for older versions."""
|
||||
logger.debug("Parsing <content> section (legacy format)")
|
||||
|
||||
@@ -438,7 +442,7 @@ class ProjectXMLReader:
|
||||
|
||||
return
|
||||
|
||||
def _parseStatusImport(self, xItem: ET.Element, sObject: NWStatus):
|
||||
def _parseStatusImport(self, xItem: ET.Element, sObject: NWStatus) -> None:
|
||||
"""Parse a status or importance entry."""
|
||||
for xEntry in xItem:
|
||||
if xEntry.tag == "entry":
|
||||
@@ -447,7 +451,7 @@ class ProjectXMLReader:
|
||||
green = checkInt(xEntry.attrib.get("green", 0), 0)
|
||||
blue = checkInt(xEntry.attrib.get("blue", 0), 0)
|
||||
count = checkInt(xEntry.attrib.get("count", 0), 0)
|
||||
sObject.write(key, xEntry.text, (red, green, blue), count)
|
||||
sObject.write(key, xEntry.text or "", (red, green, blue), count)
|
||||
return
|
||||
|
||||
def _parseDictKeyText(self, xItem: ET.Element) -> dict:
|
||||
@@ -460,7 +464,7 @@ class ProjectXMLReader:
|
||||
result[xEntry.attrib["key"]] = checkString(xEntry.text, "")
|
||||
return result
|
||||
|
||||
def _parseDictTagText(self, xItem):
|
||||
def _parseDictTagText(self, xItem) -> dict:
|
||||
"""Parse a dictionary stored with key as the tag and the value
|
||||
as the text property.
|
||||
"""
|
||||
@@ -476,7 +480,7 @@ class ProjectXMLWriter:
|
||||
very latest spec.
|
||||
"""
|
||||
|
||||
def __init__(self, path):
|
||||
def __init__(self, path: str | Path) -> None:
|
||||
self._path = Path(path)
|
||||
self._error = None
|
||||
return
|
||||
@@ -585,13 +589,13 @@ class ProjectXMLWriter:
|
||||
|
||||
def _packSingleValue(
|
||||
self, xParent: ET.Element, name: str, value: str | None, attrib: dict | None = None
|
||||
):
|
||||
) -> None:
|
||||
"""Pack a single value into an XML element."""
|
||||
xItem = ET.SubElement(xParent, name, attrib=attrib or {})
|
||||
xItem.text = str(value) or ""
|
||||
return
|
||||
|
||||
def _packDictKeyValue(self, xParent: ET.Element, name: str, data: dict):
|
||||
def _packDictKeyValue(self, xParent: ET.Element, name: str, data: dict) -> None:
|
||||
"""Pack the entries of a dictionary into an XML element."""
|
||||
xItem = ET.SubElement(xParent, name)
|
||||
for key, value in data.items():
|
||||
|
||||
@@ -47,7 +47,7 @@ class NWSessionLog:
|
||||
format. That is, one JSON object per line.
|
||||
"""
|
||||
|
||||
def __init__(self, project: NWProject):
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
self._project = project
|
||||
self._start = 0.0
|
||||
return
|
||||
@@ -65,7 +65,7 @@ class NWSessionLog:
|
||||
# Methods
|
||||
##
|
||||
|
||||
def startSession(self):
|
||||
def startSession(self) -> None:
|
||||
"""Start the writing session."""
|
||||
self._start = time()
|
||||
return
|
||||
|
||||
@@ -45,7 +45,7 @@ class NWSpellEnchant:
|
||||
between spell check tools.
|
||||
"""
|
||||
|
||||
def __init__(self, project: NWProject):
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
self._project = project
|
||||
self._dictObj = FakeEnchant()
|
||||
self._userDict = UserDictionary(project)
|
||||
@@ -165,7 +165,7 @@ class NWSpellEnchant:
|
||||
|
||||
class FakeEnchant:
|
||||
"""Fallback for when Enchant is selected, but not installed."""
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
|
||||
class FakeProvider:
|
||||
name = ""
|
||||
@@ -189,7 +189,7 @@ class FakeEnchant:
|
||||
|
||||
class UserDictionary:
|
||||
|
||||
def __init__(self, project: NWProject):
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
self._project = project
|
||||
self._words = set()
|
||||
self._path = None
|
||||
@@ -210,7 +210,7 @@ class UserDictionary:
|
||||
self._words.add(word)
|
||||
return True
|
||||
|
||||
def load(self):
|
||||
def load(self) -> None:
|
||||
"""Load the user's dictionary."""
|
||||
self._path = self._project.storage.getMetaFile(nwFiles.DICT_FILE)
|
||||
if not isinstance(self._path, Path):
|
||||
@@ -224,7 +224,7 @@ class UserDictionary:
|
||||
logException()
|
||||
return
|
||||
|
||||
def save(self):
|
||||
def save(self) -> None:
|
||||
"""Save the user's dictionary."""
|
||||
if self._path is None:
|
||||
self._path = self._project.storage.getMetaFile(nwFiles.DICT_FILE)
|
||||
|
||||
+48
-64
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – Project Item Status Class
|
||||
=======================================
|
||||
Data class for the status/importance settings of a project item
|
||||
|
||||
File History:
|
||||
Created: 2019-05-19 [0.1.3]
|
||||
@@ -23,16 +22,22 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import logging
|
||||
|
||||
from typing import TYPE_CHECKING, ItemsView, Iterator, KeysView, Literal, ValuesView
|
||||
|
||||
from PyQt5.QtGui import QIcon, QPainter, QPainterPath, QPixmap, QColor
|
||||
from PyQt5.QtCore import QRectF, Qt
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.common import minmax, simplified
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from typing import TypeGuard # Requires Python 3.10
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -41,9 +46,9 @@ class NWStatus:
|
||||
STATUS = 1
|
||||
IMPORT = 2
|
||||
|
||||
def __init__(self, type):
|
||||
def __init__(self, kind: Literal[1, 2]) -> None:
|
||||
|
||||
self._type = type
|
||||
self._type = kind
|
||||
self._store = {}
|
||||
self._default = None
|
||||
|
||||
@@ -66,7 +71,7 @@ class NWStatus:
|
||||
|
||||
return
|
||||
|
||||
def write(self, key, name, col, count=None):
|
||||
def write(self, key: str | None, name: str, col: tuple, count: int | None = None) -> str:
|
||||
"""Add or update a status entry. If the key is invalid, a new
|
||||
key is generated.
|
||||
"""
|
||||
@@ -96,10 +101,8 @@ class NWStatus:
|
||||
|
||||
return key
|
||||
|
||||
def remove(self, key):
|
||||
"""Remove an entry in the list, but not if the count is larger
|
||||
than 0.
|
||||
"""
|
||||
def remove(self, key: str) -> bool:
|
||||
"""Remove an entry in the list, except if the count > 0."""
|
||||
if key not in self._store:
|
||||
return False
|
||||
if self._store[key]["count"] > 0:
|
||||
@@ -116,59 +119,48 @@ class NWStatus:
|
||||
|
||||
return True
|
||||
|
||||
def check(self, value):
|
||||
"""Check the key against the stored status names.
|
||||
"""
|
||||
def check(self, value: str) -> str:
|
||||
"""Check the key against the stored status names."""
|
||||
if self._isKey(value) and value in self._store:
|
||||
return value
|
||||
elif self._default is not None:
|
||||
return self._default
|
||||
else:
|
||||
return ""
|
||||
return ""
|
||||
|
||||
def name(self, key):
|
||||
"""Return the name associated with a given key.
|
||||
"""
|
||||
def name(self, key: str | None) -> str:
|
||||
"""Return the name associated with a given key."""
|
||||
if key in self._store:
|
||||
return self._store[key]["name"]
|
||||
elif self._default is not None:
|
||||
return self._store[self._default]["name"]
|
||||
else:
|
||||
return ""
|
||||
return ""
|
||||
|
||||
def cols(self, key):
|
||||
"""Return the colours associated with a given key.
|
||||
"""
|
||||
def cols(self, key: str | None) -> tuple[int, int, int]:
|
||||
"""Return the colours associated with a given key."""
|
||||
if key in self._store:
|
||||
return self._store[key]["cols"]
|
||||
elif self._default is not None:
|
||||
return self._store[self._default]["cols"]
|
||||
else:
|
||||
return (100, 100, 100)
|
||||
return 100, 100, 100
|
||||
|
||||
def count(self, key):
|
||||
"""Return the count associated with a given key.
|
||||
"""
|
||||
def count(self, key: str | None) -> int:
|
||||
"""Return the count associated with a given key."""
|
||||
if key in self._store:
|
||||
return self._store[key]["count"]
|
||||
elif self._default is not None:
|
||||
return self._store[self._default]["count"]
|
||||
else:
|
||||
return 0
|
||||
return 0
|
||||
|
||||
def icon(self, key):
|
||||
"""Return the icon associated with a given key.
|
||||
"""
|
||||
def icon(self, key: str | None) -> QIcon:
|
||||
"""Return the icon associated with a given key."""
|
||||
if key in self._store:
|
||||
return self._store[key]["icon"]
|
||||
elif self._default is not None:
|
||||
return self._store[self._default]["icon"]
|
||||
else:
|
||||
return self._defaultIcon
|
||||
return self._defaultIcon
|
||||
|
||||
def reorder(self, order):
|
||||
"""Reorder the items according to list.
|
||||
"""
|
||||
def reorder(self, order: list[str]) -> bool:
|
||||
"""Reorder the items according to list."""
|
||||
if len(order) != len(self._store):
|
||||
logger.error("Length mismatch between new and old order")
|
||||
return False
|
||||
@@ -188,23 +180,20 @@ class NWStatus:
|
||||
|
||||
return True
|
||||
|
||||
def resetCounts(self):
|
||||
"""Clear the counts of references to the status entries.
|
||||
"""
|
||||
def resetCounts(self) -> None:
|
||||
"""Clear the counts of references to the status entries."""
|
||||
for key in self._store:
|
||||
self._store[key]["count"] = 0
|
||||
return
|
||||
|
||||
def increment(self, key):
|
||||
"""Increment the counter for a given entry.
|
||||
"""
|
||||
def increment(self, key: str) -> None:
|
||||
"""Increment the counter for a given entry."""
|
||||
if key in self._store:
|
||||
self._store[key]["count"] += 1
|
||||
return
|
||||
|
||||
def pack(self):
|
||||
"""Pack the status entries into a dictionary.
|
||||
"""
|
||||
def pack(self) -> Iterator[tuple[str, dict]]:
|
||||
"""Pack the status entries into a dictionary."""
|
||||
for key, data in self._store.items():
|
||||
yield (data["name"], {
|
||||
"key": key,
|
||||
@@ -215,25 +204,22 @@ class NWStatus:
|
||||
})
|
||||
return
|
||||
|
||||
def unpack(self, data):
|
||||
"""Unpack a data dictionary and set the class values.
|
||||
"""
|
||||
def unpack(self, data: dict) -> None:
|
||||
"""Unpack a data dictionary and set the class values."""
|
||||
self._store = {}
|
||||
self._default = None
|
||||
|
||||
for key, entry in data.items():
|
||||
label = entry.get("label", "")
|
||||
colour = entry.get("colour", (100, 100, 100))
|
||||
count = entry.get("count", 0)
|
||||
self.write(key, label, colour, count)
|
||||
|
||||
return True
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _newKey(self):
|
||||
def _newKey(self) -> str:
|
||||
"""Generate a new key for a status flag. This method is
|
||||
recursive, but should only fail if there is an issue with the
|
||||
random number generator or the user has added a lot of status
|
||||
@@ -245,9 +231,8 @@ class NWStatus:
|
||||
key = self._newKey()
|
||||
return key
|
||||
|
||||
def _isKey(self, value):
|
||||
"""Check if a value is a key or not.
|
||||
"""
|
||||
def _isKey(self, value: str | None) -> TypeGuard[str]:
|
||||
"""Check if a value is a key or not."""
|
||||
if not isinstance(value, str):
|
||||
return False
|
||||
if len(value) != 7:
|
||||
@@ -259,9 +244,8 @@ class NWStatus:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _createIcon(self, red, green, blue):
|
||||
"""Generate an icon for a status label.
|
||||
"""
|
||||
def _createIcon(self, red: int, green: int, blue: int) -> QIcon:
|
||||
"""Generate an icon for a status label."""
|
||||
pixmap = QPixmap(self._iPX, self._iPX)
|
||||
pixmap.fill(Qt.transparent)
|
||||
|
||||
@@ -276,22 +260,22 @@ class NWStatus:
|
||||
# Iterator Bits
|
||||
##
|
||||
|
||||
def __len__(self):
|
||||
def __len__(self) -> int:
|
||||
return len(self._store)
|
||||
|
||||
def __getitem__(self, key):
|
||||
def __getitem__(self, key: str) -> dict:
|
||||
return self._store[key]
|
||||
|
||||
def __iter__(self):
|
||||
def __iter__(self) -> Iterator[dict]:
|
||||
return iter(self._store)
|
||||
|
||||
def keys(self):
|
||||
def keys(self) -> KeysView[str]:
|
||||
return self._store.keys()
|
||||
|
||||
def items(self):
|
||||
def items(self) -> ItemsView[str, dict]:
|
||||
return self._store.items()
|
||||
|
||||
def values(self):
|
||||
def values(self) -> ValuesView[dict]:
|
||||
return self._store.values()
|
||||
|
||||
# END Class NWStatus
|
||||
|
||||
@@ -55,7 +55,7 @@ class NWStorage:
|
||||
MODE_INPLACE = 1
|
||||
MODE_ARCHIVE = 2
|
||||
|
||||
def __init__(self, project: NWProject):
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
self._project = project
|
||||
self._storagePath = None
|
||||
self._runtimePath = None
|
||||
@@ -63,7 +63,7 @@ class NWStorage:
|
||||
self._openMode = self.MODE_INACTIVE
|
||||
return
|
||||
|
||||
def clear(self):
|
||||
def clear(self) -> None:
|
||||
"""Reset internal variables."""
|
||||
self._storagePath = None
|
||||
self._runtimePath = None
|
||||
@@ -145,7 +145,7 @@ class NWStorage:
|
||||
return True
|
||||
return True
|
||||
|
||||
def closeSession(self):
|
||||
def closeSession(self) -> None:
|
||||
"""Run tasks related to closing the session."""
|
||||
self.clearLockFile()
|
||||
self.clear()
|
||||
@@ -353,11 +353,11 @@ class _LegacyStorage:
|
||||
file/folder layout to the current project format.
|
||||
"""
|
||||
|
||||
def __init__(self, project: NWProject):
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
self._project = project
|
||||
return
|
||||
|
||||
def legacyDataFolder(self, path: Path, child: Path):
|
||||
def legacyDataFolder(self, path: Path, child: Path) -> None:
|
||||
"""Handle the content of a legacy data folder from a version 1.0
|
||||
project.
|
||||
"""
|
||||
@@ -396,7 +396,7 @@ class _LegacyStorage:
|
||||
|
||||
return
|
||||
|
||||
def deprecatedFiles(self, path: Path):
|
||||
def deprecatedFiles(self, path: Path) -> None:
|
||||
"""Handle files that are no longer used by novelWriter."""
|
||||
self._convertOldWordList( # Changed in 2.1 Beta 1
|
||||
path / "meta" / "wordlist.txt",
|
||||
@@ -440,7 +440,7 @@ class _LegacyStorage:
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _convertOldWordList(self, wordList: Path, wordJson: Path):
|
||||
def _convertOldWordList(self, wordList: Path, wordJson: Path) -> None:
|
||||
"""Convert the old word list plain text file to new format."""
|
||||
if wordJson.exists() or not wordList.exists():
|
||||
# If the new file already exists, we won't overwrite it
|
||||
@@ -466,7 +466,7 @@ class _LegacyStorage:
|
||||
|
||||
return
|
||||
|
||||
def _convertOldLogFile(self, sessLog: Path, sessJson: Path):
|
||||
def _convertOldLogFile(self, sessLog: Path, sessJson: Path) -> None:
|
||||
"""Convert the old text log file format to the new JSON Lines
|
||||
format.
|
||||
"""
|
||||
@@ -507,7 +507,7 @@ class _LegacyStorage:
|
||||
|
||||
return
|
||||
|
||||
def _convertOldOptionsFile(self, optsOld: Path, optsNew: Path):
|
||||
def _convertOldOptionsFile(self, optsOld: Path, optsNew: Path) -> None:
|
||||
"""Convert the old options state file format to the format."""
|
||||
if optsNew.exists() or not optsOld.exists():
|
||||
# If the new file already exists, we won't overwrite it
|
||||
|
||||
+12
-12
@@ -49,12 +49,12 @@ class ToHtml(Tokenizer):
|
||||
M_EXPORT = 1 # Tweak output for saving to HTML or printing
|
||||
M_EBOOK = 2 # Tweak output for converting to epub
|
||||
|
||||
def __init__(self, project: NWProject):
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
super().__init__(project)
|
||||
|
||||
self._genMode = self.M_EXPORT
|
||||
self._cssStyles = True
|
||||
self._fullHTML = []
|
||||
self._fullHTML: list[str] = []
|
||||
|
||||
# Internals
|
||||
self._trMap = {}
|
||||
@@ -67,14 +67,14 @@ class ToHtml(Tokenizer):
|
||||
##
|
||||
|
||||
@property
|
||||
def fullHTML(self):
|
||||
def fullHTML(self) -> list[str]:
|
||||
return self._fullHTML
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setPreview(self, doComments: bool, doSynopsis: bool):
|
||||
def setPreview(self, doComments: bool, doSynopsis: bool) -> None:
|
||||
"""If we're using this class to generate markdown preview, we
|
||||
need to make a few changes to formatting, which is managed by
|
||||
these flags.
|
||||
@@ -85,14 +85,14 @@ class ToHtml(Tokenizer):
|
||||
self._doSynopsis = doSynopsis
|
||||
return
|
||||
|
||||
def setStyles(self, cssStyles: bool):
|
||||
def setStyles(self, cssStyles: bool) -> None:
|
||||
"""Enable or disable CSS styling. Some elements may still have
|
||||
class tags.
|
||||
"""
|
||||
self._cssStyles = cssStyles
|
||||
return
|
||||
|
||||
def setReplaceUnicode(self, doReplace: bool):
|
||||
def setReplaceUnicode(self, doReplace: bool) -> None:
|
||||
"""Set the translation map to either minimal or full unicode for
|
||||
html entities replacement.
|
||||
"""
|
||||
@@ -113,7 +113,7 @@ class ToHtml(Tokenizer):
|
||||
"""Return the size of the full HTML result."""
|
||||
return sum([len(x) for x in self._fullHTML])
|
||||
|
||||
def doPreProcessing(self):
|
||||
def doPreProcessing(self) -> None:
|
||||
"""Extend the auto-replace to also properly encode some unicode
|
||||
characters into their respective HTML entities.
|
||||
"""
|
||||
@@ -121,7 +121,7 @@ class ToHtml(Tokenizer):
|
||||
self._text = self._text.translate(self._trMap)
|
||||
return
|
||||
|
||||
def doConvert(self):
|
||||
def doConvert(self) -> None:
|
||||
"""Convert the list of text tokens into a HTML document saved
|
||||
to _result.
|
||||
"""
|
||||
@@ -299,7 +299,7 @@ class ToHtml(Tokenizer):
|
||||
|
||||
return
|
||||
|
||||
def saveHtml5(self, path: str | Path):
|
||||
def saveHtml5(self, path: str | Path) -> None:
|
||||
"""Save the data to an HTML file."""
|
||||
with open(path, mode="w", encoding="utf-8") as fObj:
|
||||
fObj.write((
|
||||
@@ -326,7 +326,7 @@ class ToHtml(Tokenizer):
|
||||
logger.info("Wrote file: %s", path)
|
||||
return
|
||||
|
||||
def saveHtmlJson(self, path: str | Path):
|
||||
def saveHtmlJson(self, path: str | Path) -> None:
|
||||
"""Save the data to a JSON file."""
|
||||
timeStamp = time()
|
||||
data = {
|
||||
@@ -347,7 +347,7 @@ class ToHtml(Tokenizer):
|
||||
logger.info("Wrote file: %s", path)
|
||||
return
|
||||
|
||||
def replaceTabs(self, nSpaces: int = 8, spaceChar: str = " "):
|
||||
def replaceTabs(self, nSpaces: int = 8, spaceChar: str = " ") -> None:
|
||||
"""Replace tabs with spaces in the html."""
|
||||
htmlText = []
|
||||
tabSpace = spaceChar*nSpaces
|
||||
@@ -357,7 +357,7 @@ class ToHtml(Tokenizer):
|
||||
self._fullHTML = htmlText
|
||||
return
|
||||
|
||||
def getStyleSheet(self) -> list:
|
||||
def getStyleSheet(self) -> list[str]:
|
||||
"""Generate a stylesheet for the current settings."""
|
||||
styles = []
|
||||
if not self._cssStyles:
|
||||
|
||||
@@ -44,7 +44,7 @@ from novelwriter.core.project import NWProject
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def stripEscape(text):
|
||||
def stripEscape(text) -> str:
|
||||
"""Helper function to strip escaped Markdown characters from
|
||||
paragraph text.
|
||||
"""
|
||||
@@ -100,7 +100,7 @@ class Tokenizer(ABC):
|
||||
A_IND_L = 0x0100 # Left indentation
|
||||
A_IND_R = 0x0200 # Right indentation
|
||||
|
||||
def __init__(self, project: NWProject):
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
|
||||
self._project = project
|
||||
|
||||
@@ -191,116 +191,116 @@ class Tokenizer(ABC):
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setTitleFormat(self, hFormat: str):
|
||||
def setTitleFormat(self, hFormat: str) -> None:
|
||||
"""Set the title format pattern."""
|
||||
self._fmtTitle = hFormat.strip()
|
||||
return
|
||||
|
||||
def setChapterFormat(self, hFormat: str):
|
||||
def setChapterFormat(self, hFormat: str) -> None:
|
||||
"""Set the chapert format pattern."""
|
||||
self._fmtChapter = hFormat.strip()
|
||||
return
|
||||
|
||||
def setUnNumberedFormat(self, hFormat: str):
|
||||
def setUnNumberedFormat(self, hFormat: str) -> None:
|
||||
"""Set the unnumbered format pattern."""
|
||||
self._fmtUnNum = hFormat.strip()
|
||||
return
|
||||
|
||||
def setSceneFormat(self, hFormat: str, hide: bool):
|
||||
def setSceneFormat(self, hFormat: str, hide: bool) -> None:
|
||||
"""Set the scene format pattern and hidden status."""
|
||||
self._fmtScene = hFormat.strip()
|
||||
self._hideScene = hide
|
||||
return
|
||||
|
||||
def setSectionFormat(self, hFormat: str, hide: bool):
|
||||
def setSectionFormat(self, hFormat: str, hide: bool) -> None:
|
||||
"""Set the section format pattern and hidden status."""
|
||||
self._fmtSection = hFormat.strip()
|
||||
self._hideSection = hide
|
||||
return
|
||||
|
||||
def setFont(self, family: str, size: int, isFixed: bool = False):
|
||||
def setFont(self, family: str, size: int, isFixed: bool = False) -> None:
|
||||
"""Set the build font."""
|
||||
self._textFont = family
|
||||
self._textSize = round(int(size))
|
||||
self._textFixed = isFixed
|
||||
return
|
||||
|
||||
def setLineHeight(self, height: float):
|
||||
def setLineHeight(self, height: float) -> None:
|
||||
"""Set the line height between 0.5 and 5.0."""
|
||||
self._lineHeight = min(max(float(height), 0.5), 5.0)
|
||||
return
|
||||
|
||||
def setBlockIndent(self, indent: float):
|
||||
def setBlockIndent(self, indent: float) -> None:
|
||||
"""Set the block indent between 0.0 and 10.0."""
|
||||
self._blockIndent = min(max(float(indent), 0.0), 10.0)
|
||||
return
|
||||
|
||||
def setJustify(self, state: bool):
|
||||
def setJustify(self, state: bool) -> None:
|
||||
"""Enable or disable text justification."""
|
||||
self._doJustify = state
|
||||
return
|
||||
|
||||
def setTitleMargins(self, upper: float, lower: float):
|
||||
def setTitleMargins(self, upper: float, lower: float) -> None:
|
||||
"""Set the upper and lower title margin."""
|
||||
self._marginTitle = (float(upper), float(lower))
|
||||
return
|
||||
|
||||
def setHead1Margins(self, upper: float, lower: float):
|
||||
def setHead1Margins(self, upper: float, lower: float) -> None:
|
||||
"""Set the upper and lower header 1 margin."""
|
||||
self._marginHead1 = (float(upper), float(lower))
|
||||
return
|
||||
|
||||
def setHead2Margins(self, upper: float, lower: float):
|
||||
def setHead2Margins(self, upper: float, lower: float) -> None:
|
||||
"""Set the upper and lower header 2 margin."""
|
||||
self._marginHead2 = (float(upper), float(lower))
|
||||
return
|
||||
|
||||
def setHead3Margins(self, upper: float, lower: float):
|
||||
def setHead3Margins(self, upper: float, lower: float) -> None:
|
||||
"""Set the upper and lower header 3 margin."""
|
||||
self._marginHead3 = (float(upper), float(lower))
|
||||
return
|
||||
|
||||
def setHead4Margins(self, upper: float, lower: float):
|
||||
def setHead4Margins(self, upper: float, lower: float) -> None:
|
||||
"""Set the upper and lower header 4 margin."""
|
||||
self._marginHead4 = (float(upper), float(lower))
|
||||
return
|
||||
|
||||
def setTextMargins(self, upper: float, lower: float):
|
||||
def setTextMargins(self, upper: float, lower: float) -> None:
|
||||
"""Set the upper and lower text margin."""
|
||||
self._marginText = (float(upper), float(lower))
|
||||
return
|
||||
|
||||
def setMetaMargins(self, upper: float, lower: float):
|
||||
def setMetaMargins(self, upper: float, lower: float) -> None:
|
||||
"""Set the upper and lower meta text margin."""
|
||||
self._marginMeta = (float(upper), float(lower))
|
||||
return
|
||||
|
||||
def setLinkHeaders(self, state: bool):
|
||||
def setLinkHeaders(self, state: bool) -> None:
|
||||
"""Enable or disable adding an anchor before headers."""
|
||||
self._linkHeaders = state
|
||||
return
|
||||
|
||||
def setBodyText(self, state: bool):
|
||||
def setBodyText(self, state: bool) -> None:
|
||||
"""Include body text in build."""
|
||||
self._doBodyText = state
|
||||
return
|
||||
|
||||
def setSynopsis(self, state: bool):
|
||||
def setSynopsis(self, state: bool) -> None:
|
||||
"""Include synopsis comments in build."""
|
||||
self._doSynopsis = state
|
||||
return
|
||||
|
||||
def setComments(self, state: bool):
|
||||
def setComments(self, state: bool) -> None:
|
||||
"""Include comments in build."""
|
||||
self._doComments = state
|
||||
return
|
||||
|
||||
def setKeywords(self, state: bool):
|
||||
def setKeywords(self, state: bool) -> None:
|
||||
"""Include keywords in build."""
|
||||
self._doKeywords = state
|
||||
return
|
||||
|
||||
def setKeepMarkdown(self, state: bool):
|
||||
def setKeepMarkdown(self, state: bool) -> None:
|
||||
"""Keep original markdown during build."""
|
||||
self._keepMarkdown = state
|
||||
return
|
||||
@@ -310,7 +310,7 @@ class Tokenizer(ABC):
|
||||
##
|
||||
|
||||
@abstractmethod
|
||||
def doConvert(self):
|
||||
def doConvert(self) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
def addRootHeading(self, tHandle: str) -> bool:
|
||||
@@ -365,7 +365,7 @@ class Tokenizer(ABC):
|
||||
|
||||
return True
|
||||
|
||||
def doPreProcessing(self):
|
||||
def doPreProcessing(self) -> None:
|
||||
"""Run trough the various replace dictionaries."""
|
||||
# Process the user's auto-replace dictionary
|
||||
autoReplace = self._project.data.autoReplace
|
||||
@@ -382,7 +382,7 @@ class Tokenizer(ABC):
|
||||
|
||||
return
|
||||
|
||||
def tokenizeText(self):
|
||||
def tokenizeText(self) -> None:
|
||||
"""Scan the text for either lines starting with specific
|
||||
characters that indicate headers, comments, commands etc, or
|
||||
just contain plain text. In the case of plain text, apply the
|
||||
@@ -742,14 +742,14 @@ class Tokenizer(ABC):
|
||||
|
||||
return True
|
||||
|
||||
def saveRawMarkdown(self, path: str | Path):
|
||||
def saveRawMarkdown(self, path: str | Path) -> None:
|
||||
"""Save the raw text to a plain text file."""
|
||||
with open(path, mode="w", encoding="utf-8") as outFile:
|
||||
for nwdPage in self._allMarkdown:
|
||||
outFile.write(nwdPage)
|
||||
return
|
||||
|
||||
def saveRawMarkdownJSON(self, path: str | Path):
|
||||
def saveRawMarkdownJSON(self, path: str | Path) -> None:
|
||||
"""Save the raw text to a JSON file."""
|
||||
timeStamp = time()
|
||||
data = {
|
||||
@@ -773,30 +773,30 @@ class Tokenizer(ABC):
|
||||
|
||||
class HeadingFormatter:
|
||||
|
||||
def __init__(self, project: NWProject):
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
self._project = project
|
||||
self._chCount = 0
|
||||
self._scChCount = 0
|
||||
self._scAbsCount = 0
|
||||
return
|
||||
|
||||
def incChapter(self):
|
||||
def incChapter(self) -> None:
|
||||
"""Increment the chapter counter."""
|
||||
self._chCount += 1
|
||||
return
|
||||
|
||||
def incScene(self):
|
||||
def incScene(self) -> None:
|
||||
"""Increment the scene counters."""
|
||||
self._scChCount += 1
|
||||
self._scAbsCount += 1
|
||||
return
|
||||
|
||||
def resetScene(self):
|
||||
def resetScene(self) -> None:
|
||||
"""Reset the chapter scene counter."""
|
||||
self._scChCount = 0
|
||||
return
|
||||
|
||||
def apply(self, hFormat: str, text: str):
|
||||
def apply(self, hFormat: str, text: str) -> str:
|
||||
"""Apply formatting to a specific heading."""
|
||||
hFormat = hFormat.replace(nwHeadFmt.TITLE, text)
|
||||
hFormat = hFormat.replace(nwHeadFmt.CH_NUM, str(self._chCount))
|
||||
|
||||
@@ -45,12 +45,10 @@ class ToMarkdown(Tokenizer):
|
||||
M_STD = 0 # Standard Markdown
|
||||
M_GH = 1 # GitHub Markdown
|
||||
|
||||
def __init__(self, project: NWProject):
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
super().__init__(project)
|
||||
|
||||
self._genMode = self.M_STD
|
||||
self._fullMD = []
|
||||
|
||||
self._fullMD: list[str] = []
|
||||
return
|
||||
|
||||
##
|
||||
@@ -58,7 +56,7 @@ class ToMarkdown(Tokenizer):
|
||||
##
|
||||
|
||||
@property
|
||||
def fullMD(self) -> list:
|
||||
def fullMD(self) -> list[str]:
|
||||
"""Return the markdown as a list."""
|
||||
return self._fullMD
|
||||
|
||||
@@ -66,11 +64,11 @@ class ToMarkdown(Tokenizer):
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setStandardMarkdown(self):
|
||||
def setStandardMarkdown(self) -> None:
|
||||
self._genMode = self.M_STD
|
||||
return
|
||||
|
||||
def setGitHubMarkdown(self):
|
||||
def setGitHubMarkdown(self) -> None:
|
||||
self._genMode = self.M_GH
|
||||
return
|
||||
|
||||
@@ -82,7 +80,7 @@ class ToMarkdown(Tokenizer):
|
||||
"""Return the size of the full Markdown result."""
|
||||
return sum([len(x) for x in self._fullMD])
|
||||
|
||||
def doConvert(self):
|
||||
def doConvert(self) -> None:
|
||||
"""Convert the list of text tokens into a HTML document saved
|
||||
to theResult.
|
||||
"""
|
||||
@@ -175,14 +173,14 @@ class ToMarkdown(Tokenizer):
|
||||
|
||||
return
|
||||
|
||||
def saveMarkdown(self, path: str | Path):
|
||||
def saveMarkdown(self, path: str | Path) -> None:
|
||||
"""Save the data to a plain text file."""
|
||||
with open(path, mode="w", encoding="utf-8") as outFile:
|
||||
outFile.write("".join(self._fullMD))
|
||||
logger.info("Wrote file: %s", path)
|
||||
return
|
||||
|
||||
def replaceTabs(self, nSpaces: int = 8, spaceChar: str = " "):
|
||||
def replaceTabs(self, nSpaces: int = 8, spaceChar: str = " ") -> None:
|
||||
"""Replace tabs with spaces."""
|
||||
spaces = spaceChar*nSpaces
|
||||
self._fullMD = [p.replace("\t", spaces) for p in self._fullMD]
|
||||
|
||||
+44
-46
@@ -98,7 +98,7 @@ class ToOdt(Tokenizer):
|
||||
Test with: https://odfvalidator.org/
|
||||
"""
|
||||
|
||||
def __init__(self, project: NWProject, isFlat: bool):
|
||||
def __init__(self, project: NWProject, isFlat: bool) -> None:
|
||||
super().__init__(project)
|
||||
|
||||
self._isFlat = isFlat # Flat: .fodt, otherwise .odt
|
||||
@@ -188,7 +188,7 @@ class ToOdt(Tokenizer):
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setLanguage(self, language: str):
|
||||
def setLanguage(self, language: str) -> None:
|
||||
"""Set language for the document."""
|
||||
if language:
|
||||
langBits = language.split("_")
|
||||
@@ -197,7 +197,7 @@ class ToOdt(Tokenizer):
|
||||
self._dCountry = langBits[1]
|
||||
return
|
||||
|
||||
def setColourHeaders(self, state: bool):
|
||||
def setColourHeaders(self, state: bool) -> None:
|
||||
"""Enable/disable coloured headings and comments."""
|
||||
self._colourHead = state
|
||||
return
|
||||
@@ -205,7 +205,7 @@ class ToOdt(Tokenizer):
|
||||
def setPageLayout(
|
||||
self, width: int | float, height: int | float,
|
||||
top: int | float, bottom: int | float, left: int | float, right: int | float
|
||||
):
|
||||
) -> None:
|
||||
"""Set the document page size and margins in millimetres."""
|
||||
self._mDocWidth = f"{width/10.0:.3f}cm"
|
||||
self._mDocHeight = f"{height/10.0:.3f}cm"
|
||||
@@ -219,7 +219,7 @@ class ToOdt(Tokenizer):
|
||||
# Class Methods
|
||||
##
|
||||
|
||||
def initDocument(self):
|
||||
def initDocument(self) -> None:
|
||||
"""Initialises a new open document XML tree."""
|
||||
# Initialise Variables
|
||||
# ====================
|
||||
@@ -381,7 +381,7 @@ class ToOdt(Tokenizer):
|
||||
|
||||
return
|
||||
|
||||
def doConvert(self):
|
||||
def doConvert(self) -> None:
|
||||
"""Convert the list of text tokens into XML elements."""
|
||||
self._result = "" # Not used, but cleared just in case
|
||||
|
||||
@@ -599,7 +599,7 @@ class ToOdt(Tokenizer):
|
||||
def _addTextPar(
|
||||
self, styleName: str, oStyle: ODTParagraphStyle, tText: str, tFmt: str = "",
|
||||
isHead: bool = False, oLevel: str | None = None
|
||||
):
|
||||
) -> None:
|
||||
"""Add a text paragraph to the text XML element."""
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("text", "style-name")] = self._paraStyle(styleName, oStyle)
|
||||
@@ -726,7 +726,7 @@ class ToOdt(Tokenizer):
|
||||
# Style Elements
|
||||
##
|
||||
|
||||
def _pageStyles(self):
|
||||
def _pageStyles(self) -> None:
|
||||
"""Set the default page style."""
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("style", "name")] = "PM1"
|
||||
@@ -756,7 +756,7 @@ class ToOdt(Tokenizer):
|
||||
|
||||
return
|
||||
|
||||
def _defaultStyles(self):
|
||||
def _defaultStyles(self) -> None:
|
||||
"""Set the default styles."""
|
||||
# Add Paragraph Family Style
|
||||
# ==========================
|
||||
@@ -829,7 +829,7 @@ class ToOdt(Tokenizer):
|
||||
|
||||
return
|
||||
|
||||
def _useableStyles(self):
|
||||
def _useableStyles(self) -> None:
|
||||
"""Set the usable styles."""
|
||||
# Add Text Body Style
|
||||
# ===================
|
||||
@@ -1002,7 +1002,7 @@ class ToOdt(Tokenizer):
|
||||
|
||||
return
|
||||
|
||||
def _writeHeader(self):
|
||||
def _writeHeader(self) -> None:
|
||||
"""Write the header elements."""
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("style", "name")] = "Standard"
|
||||
@@ -1048,7 +1048,7 @@ class ODTParagraphStyle:
|
||||
VALID_CLASS = ["text", "chapter"]
|
||||
VALID_WEIGHT = ["normal", "inherit", "bold"]
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
|
||||
# Attributes
|
||||
self._mAttr = {
|
||||
@@ -1087,26 +1087,26 @@ class ODTParagraphStyle:
|
||||
# Attribute Setters
|
||||
##
|
||||
|
||||
def setDisplayName(self, value: str | None):
|
||||
def setDisplayName(self, value: str | None) -> None:
|
||||
self._mAttr["display-name"][1] = value
|
||||
return
|
||||
|
||||
def setParentStyleName(self, value: str | None):
|
||||
def setParentStyleName(self, value: str | None) -> None:
|
||||
self._mAttr["parent-style-name"][1] = value
|
||||
return
|
||||
|
||||
def setNextStyleName(self, value: str | None):
|
||||
def setNextStyleName(self, value: str | None) -> None:
|
||||
self._mAttr["next-style-name"][1] = value
|
||||
return
|
||||
|
||||
def setOutlineLevel(self, value: str | None):
|
||||
def setOutlineLevel(self, value: str | None) -> None:
|
||||
if value in self.VALID_LEVEL:
|
||||
self._mAttr["default-outline-level"][1] = value
|
||||
else:
|
||||
self._mAttr["default-outline-level"][1] = None
|
||||
return
|
||||
|
||||
def setClass(self, value: str | None):
|
||||
def setClass(self, value: str | None) -> None:
|
||||
if value in self.VALID_CLASS:
|
||||
self._mAttr["class"][1] = value
|
||||
else:
|
||||
@@ -1117,41 +1117,41 @@ class ODTParagraphStyle:
|
||||
# Paragraph Setters
|
||||
##
|
||||
|
||||
def setMarginTop(self, value: str | None):
|
||||
def setMarginTop(self, value: str | None) -> None:
|
||||
self._pAttr["margin-top"][1] = value
|
||||
return
|
||||
|
||||
def setMarginBottom(self, value: str | None):
|
||||
def setMarginBottom(self, value: str | None) -> None:
|
||||
self._pAttr["margin-bottom"][1] = value
|
||||
return
|
||||
|
||||
def setMarginLeft(self, value: str | None):
|
||||
def setMarginLeft(self, value: str | None) -> None:
|
||||
self._pAttr["margin-left"][1] = value
|
||||
return
|
||||
|
||||
def setMarginRight(self, value: str | None):
|
||||
def setMarginRight(self, value: str | None) -> None:
|
||||
self._pAttr["margin-right"][1] = value
|
||||
return
|
||||
|
||||
def setLineHeight(self, value: str | None):
|
||||
def setLineHeight(self, value: str | None) -> None:
|
||||
self._pAttr["line-height"][1] = value
|
||||
return
|
||||
|
||||
def setTextAlign(self, value: str | None):
|
||||
def setTextAlign(self, value: str | None) -> None:
|
||||
if value in self.VALID_ALIGN:
|
||||
self._pAttr["text-align"][1] = value
|
||||
else:
|
||||
self._pAttr["text-align"][1] = None
|
||||
return
|
||||
|
||||
def setBreakBefore(self, value: str | None):
|
||||
def setBreakBefore(self, value: str | None) -> None:
|
||||
if value in self.VALID_BREAK:
|
||||
self._pAttr["break-before"][1] = value
|
||||
else:
|
||||
self._pAttr["break-before"][1] = None
|
||||
return
|
||||
|
||||
def setBreakAfter(self, value: str | None):
|
||||
def setBreakAfter(self, value: str | None) -> None:
|
||||
if value in self.VALID_BREAK:
|
||||
self._pAttr["break-after"][1] = value
|
||||
else:
|
||||
@@ -1162,30 +1162,30 @@ class ODTParagraphStyle:
|
||||
# Text Setters
|
||||
##
|
||||
|
||||
def setFontName(self, value: str | None):
|
||||
def setFontName(self, value: str | None) -> None:
|
||||
self._tAttr["font-name"][1] = value
|
||||
return
|
||||
|
||||
def setFontFamily(self, value: str | None):
|
||||
def setFontFamily(self, value: str | None) -> None:
|
||||
self._tAttr["font-family"][1] = value
|
||||
return
|
||||
|
||||
def setFontSize(self, value: str | None):
|
||||
def setFontSize(self, value: str | None) -> None:
|
||||
self._tAttr["font-size"][1] = value
|
||||
return
|
||||
|
||||
def setFontWeight(self, value: str | None):
|
||||
def setFontWeight(self, value: str | None) -> None:
|
||||
if value in self.VALID_WEIGHT:
|
||||
self._tAttr["font-weight"][1] = value
|
||||
else:
|
||||
self._tAttr["font-weight"][1] = None
|
||||
return
|
||||
|
||||
def setColor(self, value: str | None):
|
||||
def setColor(self, value: str | None) -> None:
|
||||
self._tAttr["color"][1] = value
|
||||
return
|
||||
|
||||
def setOpacity(self, value: str | None):
|
||||
def setOpacity(self, value: str | None) -> None:
|
||||
self._tAttr["opacity"][1] = value
|
||||
return
|
||||
|
||||
@@ -1193,7 +1193,7 @@ class ODTParagraphStyle:
|
||||
# Methods
|
||||
##
|
||||
|
||||
def checkNew(self, refStyle: ODTParagraphStyle):
|
||||
def checkNew(self, refStyle: ODTParagraphStyle) -> bool:
|
||||
"""Check if there are new settings in refStyle that differ from
|
||||
those in the current object.
|
||||
"""
|
||||
@@ -1217,7 +1217,7 @@ class ODTParagraphStyle:
|
||||
)
|
||||
return sha256(theString.encode()).hexdigest()
|
||||
|
||||
def packXML(self, xParent: ET.Element, name: str):
|
||||
def packXML(self, xParent: ET.Element, name: str) -> None:
|
||||
"""Pack the content into an xml element."""
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("style", "name")] = name
|
||||
@@ -1259,8 +1259,7 @@ class ODTTextStyle:
|
||||
VALID_LSTYLE = ["none", "solid"]
|
||||
VALID_LTYPE = ["none", "single", "double"]
|
||||
|
||||
def __init__(self):
|
||||
|
||||
def __init__(self) -> None:
|
||||
# Text Attributes
|
||||
self._tAttr = {
|
||||
"font-weight": ["fo", None],
|
||||
@@ -1268,35 +1267,34 @@ class ODTTextStyle:
|
||||
"text-line-through-style": ["style", None],
|
||||
"text-line-through-type": ["style", None],
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setFontWeight(self, value: str | None):
|
||||
def setFontWeight(self, value: str | None) -> None:
|
||||
if value in self.VALID_WEIGHT:
|
||||
self._tAttr["font-weight"][1] = value
|
||||
else:
|
||||
self._tAttr["font-weight"][1] = None
|
||||
return
|
||||
|
||||
def setFontStyle(self, value: str | None):
|
||||
def setFontStyle(self, value: str | None) -> None:
|
||||
if value in self.VALID_STYLE:
|
||||
self._tAttr["font-style"][1] = value
|
||||
else:
|
||||
self._tAttr["font-style"][1] = None
|
||||
return
|
||||
|
||||
def setStrikeStyle(self, value: str | None):
|
||||
def setStrikeStyle(self, value: str | None) -> None:
|
||||
if value in self.VALID_LSTYLE:
|
||||
self._tAttr["text-line-through-style"][1] = value
|
||||
else:
|
||||
self._tAttr["text-line-through-style"][1] = None
|
||||
return
|
||||
|
||||
def setStrikeType(self, value: str | None):
|
||||
def setStrikeType(self, value: str | None) -> None:
|
||||
if value in self.VALID_LTYPE:
|
||||
self._tAttr["text-line-through-type"][1] = value
|
||||
else:
|
||||
@@ -1307,7 +1305,7 @@ class ODTTextStyle:
|
||||
# Methods
|
||||
##
|
||||
|
||||
def packXML(self, xParent: ET.Element, name: str):
|
||||
def packXML(self, xParent: ET.Element, name: str) -> None:
|
||||
"""Pack the content into an xml element."""
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("style", "name")] = name
|
||||
@@ -1357,7 +1355,7 @@ class XMLParagraph:
|
||||
object and attribute is written to,
|
||||
"""
|
||||
|
||||
def __init__(self, xRoot: ET.Element):
|
||||
def __init__(self, xRoot: ET.Element) -> None:
|
||||
|
||||
self._xRoot = xRoot
|
||||
self._xTail = ET.Element("")
|
||||
@@ -1370,7 +1368,7 @@ class XMLParagraph:
|
||||
|
||||
return
|
||||
|
||||
def appendText(self, tText: str):
|
||||
def appendText(self, tText: str) -> None:
|
||||
"""Append text to the XML element. We do this one character at
|
||||
the time in order to be able to process line breaks, tabs and
|
||||
spaces separately. Multiple spaces are concatenated into a
|
||||
@@ -1435,7 +1433,7 @@ class XMLParagraph:
|
||||
|
||||
return
|
||||
|
||||
def appendSpan(self, tText: str, tFmt: str):
|
||||
def appendSpan(self, tText: str, tFmt: str) -> None:
|
||||
"""Append a text span to the XML element. The span is always
|
||||
closed since we do not allow nested spans (like Libre Office).
|
||||
Therefore we return to the root element level when we're done
|
||||
@@ -1449,7 +1447,7 @@ class XMLParagraph:
|
||||
self._nState = X_ROOT_TAIL
|
||||
return
|
||||
|
||||
def checkError(self):
|
||||
def checkError(self) -> tuple[int, str]:
|
||||
"""Check that the number of characters written matches the
|
||||
number of characters received.
|
||||
"""
|
||||
@@ -1463,7 +1461,7 @@ class XMLParagraph:
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _processSpaces(self, nSpaces: int):
|
||||
def _processSpaces(self, nSpaces: int) -> None:
|
||||
"""Add spaces to paragraph. The first space is always written
|
||||
as-is (unless it's the first character of the paragraph). The
|
||||
second space uses the dedicated tag for spaces, and from the
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI About Box
|
||||
===========================
|
||||
The about novelWriter dialog box
|
||||
|
||||
File History:
|
||||
Created: 2020-05-21 [0.5.2]
|
||||
@@ -22,6 +21,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import novelwriter
|
||||
@@ -31,8 +31,8 @@ from datetime import datetime
|
||||
from PyQt5.QtGui import QCursor
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import (
|
||||
qApp, QDialog, QHBoxLayout, QVBoxLayout, QDialogButtonBox, QTabWidget,
|
||||
QTextBrowser, QLabel
|
||||
qApp, QDialog, QDialogButtonBox, QHBoxLayout, QLabel, QTabWidget,
|
||||
QTextBrowser, QVBoxLayout, QWidget
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG
|
||||
@@ -44,15 +44,12 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class GuiAbout(QDialog):
|
||||
|
||||
def __init__(self, mainGui):
|
||||
super().__init__(parent=mainGui)
|
||||
def __init__(self, parent: QWidget):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
logger.debug("Create: GuiAbout")
|
||||
self.setObjectName("GuiAbout")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.innerBox = QHBoxLayout()
|
||||
self.innerBox.setSpacing(CONFIG.pxInt(16))
|
||||
@@ -63,7 +60,7 @@ class GuiAbout(QDialog):
|
||||
|
||||
nPx = CONFIG.pxInt(96)
|
||||
self.nwIcon = QLabel()
|
||||
self.nwIcon.setPixmap(self.mainGui.mainTheme.getPixmap("novelwriter", (nPx, nPx)))
|
||||
self.nwIcon.setPixmap(CONFIG.theme.getPixmap("novelwriter", (nPx, nPx)))
|
||||
self.lblName = QLabel("<b>novelWriter</b>")
|
||||
self.lblVers = QLabel(f"v{novelwriter.__version__}")
|
||||
self.lblDate = QLabel(datetime.strptime(novelwriter.__date__, "%Y-%m-%d").strftime("%x"))
|
||||
@@ -231,12 +228,12 @@ class GuiAbout(QDialog):
|
||||
" color: rgb({kColR},{kColG},{kColB});"
|
||||
"}}\n"
|
||||
).format(
|
||||
hColR=self.mainGui.mainTheme.colHead[0],
|
||||
hColG=self.mainGui.mainTheme.colHead[1],
|
||||
hColB=self.mainGui.mainTheme.colHead[2],
|
||||
kColR=self.mainTheme.colKey[0],
|
||||
kColG=self.mainTheme.colKey[1],
|
||||
kColB=self.mainTheme.colKey[2],
|
||||
hColR=CONFIG.theme.colHead[0],
|
||||
hColG=CONFIG.theme.colHead[1],
|
||||
hColB=CONFIG.theme.colHead[2],
|
||||
kColR=CONFIG.theme.colKey[0],
|
||||
kColG=CONFIG.theme.colKey[1],
|
||||
kColB=CONFIG.theme.colKey[2],
|
||||
)
|
||||
self.pageAbout.document().setDefaultStyleSheet(styleSheet)
|
||||
self.pageNotes.document().setDefaultStyleSheet(styleSheet)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Doc Merge Dialog
|
||||
==================================
|
||||
Custom dialog class for merging documents.
|
||||
|
||||
File History:
|
||||
Created: 2020-01-23 [0.4.3]
|
||||
@@ -23,6 +22,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
@@ -49,9 +49,7 @@ class GuiDocMerge(QDialog):
|
||||
logger.debug("Create: GuiDocMerge")
|
||||
self.setObjectName("GuiDocMerge")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
self._data = {}
|
||||
|
||||
@@ -60,9 +58,9 @@ class GuiDocMerge(QDialog):
|
||||
self.headLabel = QLabel("<b>{0}</b>".format(self.tr("Documents to Merge")))
|
||||
self.helpLabel = NHelpLabel(self.tr(
|
||||
"Drag and drop items to change the order, or uncheck to exclude."
|
||||
), self.mainTheme.helpText)
|
||||
), CONFIG.theme.helpText)
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
hSp = CONFIG.pxInt(12)
|
||||
vSp = CONFIG.pxInt(8)
|
||||
bSp = CONFIG.pxInt(12)
|
||||
@@ -157,11 +155,11 @@ class GuiDocMerge(QDialog):
|
||||
|
||||
self.listBox.clear()
|
||||
for tHandle in itemList:
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
nwItem = self.mainGui.project.tree[tHandle]
|
||||
if nwItem is None or not nwItem.isFileType():
|
||||
continue
|
||||
|
||||
itemIcon = self.mainTheme.getItemIcon(
|
||||
itemIcon = CONFIG.theme.getItemIcon(
|
||||
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, nwItem.mainHeading
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Doc Split Dialog
|
||||
==================================
|
||||
Custom dialog class for splitting documents.
|
||||
|
||||
File History:
|
||||
Created: 2020-02-01 [0.4.3]
|
||||
@@ -23,6 +22,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
@@ -51,9 +51,7 @@ class GuiDocSplit(QDialog):
|
||||
logger.debug("Create: GuiDocSplit")
|
||||
self.setObjectName("GuiDocSplit")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
self._data = {}
|
||||
self._text = []
|
||||
@@ -63,16 +61,16 @@ class GuiDocSplit(QDialog):
|
||||
self.headLabel = QLabel("<b>{0}</b>".format(self.tr("Document Headers")))
|
||||
self.helpLabel = NHelpLabel(
|
||||
self.tr("Select the maximum level to split into files."),
|
||||
self.mainGui.mainTheme.helpText
|
||||
CONFIG.theme.helpText
|
||||
)
|
||||
|
||||
# Values
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
hSp = CONFIG.pxInt(12)
|
||||
vSp = CONFIG.pxInt(8)
|
||||
bSp = CONFIG.pxInt(12)
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
spLevel = pOptions.getInt("GuiDocSplit", "spLevel", 3)
|
||||
intoFolder = pOptions.getBool("GuiDocSplit", "intoFolder", True)
|
||||
docHierarchy = pOptions.getBool("GuiDocSplit", "docHierarchy", True)
|
||||
@@ -171,7 +169,7 @@ class GuiDocSplit(QDialog):
|
||||
self._data["docHierarchy"] = docHierarchy
|
||||
self._data["moveToTrash"] = moveToTrash
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
pOptions.setValue("GuiDocSplit", "spLevel", spLevel)
|
||||
pOptions.setValue("GuiDocSplit", "intoFolder", intoFolder)
|
||||
pOptions.setValue("GuiDocSplit", "docHierarchy", docHierarchy)
|
||||
@@ -201,13 +199,13 @@ class GuiDocSplit(QDialog):
|
||||
|
||||
self.listBox.clear()
|
||||
|
||||
nwItem = self.theProject.tree[sHandle]
|
||||
nwItem = self.mainGui.project.tree[sHandle]
|
||||
if nwItem is None or not nwItem.isFileType():
|
||||
return
|
||||
|
||||
spLevel = self.splitLevel.currentData()
|
||||
if not self._text:
|
||||
inDoc = self.theProject.storage.getDocument(sHandle)
|
||||
inDoc = self.mainGui.project.storage.getDocument(sHandle)
|
||||
self._text = (inDoc.readDocument() or "").splitlines()
|
||||
|
||||
for lineNo, aLine in enumerate(self._text):
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – Edit Label Dialog
|
||||
===============================
|
||||
A simple dialog for editing a label
|
||||
|
||||
File History:
|
||||
Created: 2022-06-11 [2.0rc1]
|
||||
@@ -22,6 +21,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Preferences
|
||||
=============================
|
||||
GUI classes for the user preferences dialog
|
||||
|
||||
File History:
|
||||
Created: 2019-06-10 [0.1.5]
|
||||
@@ -22,6 +21,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
@@ -49,8 +49,7 @@ class GuiPreferences(NPagedDialog):
|
||||
logger.debug("Create: GuiPreferences")
|
||||
self.setObjectName("GuiPreferences")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
self.setWindowTitle(self.tr("Preferences"))
|
||||
|
||||
@@ -160,13 +159,11 @@ class GuiPreferencesGeneral(QWidget):
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.prefsGui = prefsGui
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
self.prefsGui = prefsGui
|
||||
|
||||
# The Form
|
||||
self.mainForm = NConfigLayout()
|
||||
self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
|
||||
self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
|
||||
self.setLayout(self.mainForm)
|
||||
|
||||
# Look and Feel
|
||||
@@ -193,7 +190,7 @@ class GuiPreferencesGeneral(QWidget):
|
||||
# Select Theme
|
||||
self.guiTheme = QComboBox()
|
||||
self.guiTheme.setMinimumWidth(minWidth)
|
||||
self.theThemes = self.mainTheme.listThemes()
|
||||
self.theThemes = CONFIG.theme.listThemes()
|
||||
for themeDir, themeName in self.theThemes:
|
||||
self.guiTheme.addItem(themeName, themeDir)
|
||||
themeIdx = self.guiTheme.findData(CONFIG.guiTheme)
|
||||
@@ -209,7 +206,7 @@ class GuiPreferencesGeneral(QWidget):
|
||||
# Editor Theme
|
||||
self.guiSyntax = QComboBox()
|
||||
self.guiSyntax.setMinimumWidth(CONFIG.pxInt(200))
|
||||
self.theSyntaxes = self.mainTheme.listSyntax()
|
||||
self.theSyntaxes = CONFIG.theme.listSyntax()
|
||||
for syntaxFile, syntaxName in self.theSyntaxes:
|
||||
self.guiSyntax.addItem(syntaxName, syntaxFile)
|
||||
syntaxIdx = self.guiSyntax.findData(CONFIG.guiSyntax)
|
||||
@@ -228,7 +225,7 @@ class GuiPreferencesGeneral(QWidget):
|
||||
self.guiFont.setFixedWidth(CONFIG.pxInt(162))
|
||||
self.guiFont.setText(CONFIG.guiFont)
|
||||
self.fontButton = QPushButton("...")
|
||||
self.fontButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
|
||||
self.fontButton.setMaximumWidth(int(2.5*CONFIG.theme.getTextWidth("...")))
|
||||
self.fontButton.clicked.connect(self._selectFont)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Font family"),
|
||||
@@ -342,12 +339,9 @@ class GuiPreferencesProjects(QWidget):
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
|
||||
# The Form
|
||||
self.mainForm = NConfigLayout()
|
||||
self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
|
||||
self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
|
||||
self.setLayout(self.mainForm)
|
||||
|
||||
# Automatic Save
|
||||
@@ -497,12 +491,9 @@ class GuiPreferencesDocuments(QWidget):
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
|
||||
# The Form
|
||||
self.mainForm = NConfigLayout()
|
||||
self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
|
||||
self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
|
||||
self.setLayout(self.mainForm)
|
||||
|
||||
# Text Style
|
||||
@@ -515,7 +506,7 @@ class GuiPreferencesDocuments(QWidget):
|
||||
self.textFont.setFixedWidth(CONFIG.pxInt(162))
|
||||
self.textFont.setText(CONFIG.textFont)
|
||||
self.fontButton = QPushButton("...")
|
||||
self.fontButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
|
||||
self.fontButton.setMaximumWidth(int(2.5*CONFIG.theme.getTextWidth("...")))
|
||||
self.fontButton.clicked.connect(self._selectFont)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Font family"),
|
||||
@@ -654,12 +645,11 @@ class GuiPreferencesEditor(QWidget):
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
self.mainGui = prefsGui.mainGui
|
||||
|
||||
# The Form
|
||||
self.mainForm = NConfigLayout()
|
||||
self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
|
||||
self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
|
||||
self.setLayout(self.mainForm)
|
||||
|
||||
mW = CONFIG.pxInt(250)
|
||||
@@ -825,13 +815,11 @@ class GuiPreferencesSyntax(QWidget):
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.prefsGui = prefsGui
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
self.prefsGui = prefsGui
|
||||
|
||||
# The Form
|
||||
self.mainForm = NConfigLayout()
|
||||
self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
|
||||
self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
|
||||
self.setLayout(self.mainForm)
|
||||
|
||||
# Quotes & Dialogue
|
||||
@@ -931,12 +919,9 @@ class GuiPreferencesAutomation(QWidget):
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
|
||||
# The Form
|
||||
self.mainForm = NConfigLayout()
|
||||
self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
|
||||
self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
|
||||
self.setLayout(self.mainForm)
|
||||
|
||||
# Automatic Features
|
||||
@@ -1085,12 +1070,9 @@ class GuiPreferencesQuotes(QWidget):
|
||||
def __init__(self, prefsGui):
|
||||
super().__init__(parent=prefsGui)
|
||||
|
||||
self.mainGui = prefsGui.mainGui
|
||||
self.mainTheme = prefsGui.mainGui.mainTheme
|
||||
|
||||
# The Form
|
||||
self.mainForm = NConfigLayout()
|
||||
self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
|
||||
self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
|
||||
self.setLayout(self.mainForm)
|
||||
|
||||
# Quotation Style
|
||||
@@ -1098,7 +1080,7 @@ class GuiPreferencesQuotes(QWidget):
|
||||
self.mainForm.addGroupLabel(self.tr("Quotation Style"))
|
||||
|
||||
qWidth = CONFIG.pxInt(40)
|
||||
bWidth = int(2.5*self.mainTheme.getTextWidth("..."))
|
||||
bWidth = int(2.5*CONFIG.theme.getTextWidth("..."))
|
||||
self.quoteSym = {}
|
||||
|
||||
# Single Quote Style
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Project Details
|
||||
=================================
|
||||
Class holding the project details dialog
|
||||
|
||||
File History:
|
||||
Created: 2021-01-03 [1.1rc1]
|
||||
@@ -22,6 +21,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
import logging
|
||||
@@ -36,9 +36,9 @@ from PyQt5.QtWidgets import (
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.common import formatTime, numberToRoman
|
||||
from novelwriter.constants import nwUnicode
|
||||
from novelwriter.gui.components import NovelSelector
|
||||
from novelwriter.extensions.switch import NSwitch
|
||||
from novelwriter.extensions.pageddialog import NPagedDialog
|
||||
from novelwriter.extensions.novelselector import NovelSelector
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -51,14 +51,13 @@ class GuiProjectDetails(NPagedDialog):
|
||||
logger.debug("Create: GuiProjectDetails")
|
||||
self.setObjectName("GuiProjectDetails")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
self.setWindowTitle(self.tr("Project Details"))
|
||||
|
||||
wW = CONFIG.pxInt(600)
|
||||
wH = CONFIG.pxInt(400)
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
|
||||
self.setMinimumWidth(wW)
|
||||
self.setMinimumHeight(wH)
|
||||
@@ -67,8 +66,8 @@ class GuiProjectDetails(NPagedDialog):
|
||||
CONFIG.pxInt(pOptions.getInt("GuiProjectDetails", "winHeight", wH))
|
||||
)
|
||||
|
||||
self.tabMain = GuiProjectDetailsMain(self.mainGui, self.theProject)
|
||||
self.tabContents = GuiProjectDetailsContents(self.mainGui, self.theProject)
|
||||
self.tabMain = GuiProjectDetailsMain(self.mainGui)
|
||||
self.tabContents = GuiProjectDetailsContents(self.mainGui)
|
||||
|
||||
self.addTab(self.tabMain, self.tr("Overview"))
|
||||
self.addTab(self.tabContents, self.tr("Contents"))
|
||||
@@ -125,7 +124,7 @@ class GuiProjectDetails(NPagedDialog):
|
||||
countFrom = self.tabContents.poValue.value()
|
||||
clearDouble = self.tabContents.dblValue.isChecked()
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
pOptions.setValue("GuiProjectDetails", "winWidth", winWidth)
|
||||
pOptions.setValue("GuiProjectDetails", "winHeight", winHeight)
|
||||
pOptions.setValue("GuiProjectDetails", "widthCol0", widthCol0)
|
||||
@@ -144,15 +143,13 @@ class GuiProjectDetails(NPagedDialog):
|
||||
|
||||
class GuiProjectDetailsMain(QWidget):
|
||||
|
||||
def __init__(self, mainGui, theProject):
|
||||
def __init__(self, mainGui):
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
self.theProject = theProject
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = mainGui
|
||||
|
||||
fPx = self.mainTheme.fontPixelSize
|
||||
fPt = self.mainTheme.fontPointSize
|
||||
fPx = CONFIG.theme.fontPixelSize
|
||||
fPt = CONFIG.theme.fontPointSize
|
||||
vPx = CONFIG.pxInt(4)
|
||||
hPx = CONFIG.pxInt(12)
|
||||
|
||||
@@ -247,22 +244,23 @@ class GuiProjectDetailsMain(QWidget):
|
||||
def updateValues(self):
|
||||
"""Set all the values.
|
||||
"""
|
||||
pIndex = self.theProject.index
|
||||
project = self.mainGui.project
|
||||
pIndex = project.index
|
||||
hCounts = pIndex.getNovelTitleCounts()
|
||||
nwCount = pIndex.getNovelWordCount()
|
||||
edTime = self.theProject.getCurrentEditTime()
|
||||
edTime = project.getCurrentEditTime()
|
||||
|
||||
self.bookTitle.setText(self.theProject.data.title or self.theProject.data.name)
|
||||
self.projName.setText(self.tr("Project: {0}").format(self.theProject.data.name))
|
||||
self.bookAuthors.setText(self.tr("By {0}").format(self.theProject.data.author))
|
||||
self.bookTitle.setText(project.data.title or project.data.name)
|
||||
self.projName.setText(self.tr("Project: {0}").format(project.data.name))
|
||||
self.bookAuthors.setText(self.tr("By {0}").format(project.data.author))
|
||||
|
||||
self.wordCountVal.setText(f"{nwCount:n}")
|
||||
self.chapCountVal.setText(f"{hCounts[2]:n}")
|
||||
self.sceneCountVal.setText(f"{hCounts[3]:n}")
|
||||
self.revCountVal.setText(f"{self.theProject.data.saveCount:n}")
|
||||
self.revCountVal.setText(f"{project.data.saveCount:n}")
|
||||
self.editTimeVal.setText(formatTime(edTime))
|
||||
|
||||
self.projPathVal.setText(str(self.theProject.storage.storagePath))
|
||||
self.projPathVal.setText(str(project.storage.storagePath))
|
||||
|
||||
return
|
||||
|
||||
@@ -277,28 +275,26 @@ class GuiProjectDetailsContents(QWidget):
|
||||
C_PAGE = 3
|
||||
C_PROG = 4
|
||||
|
||||
def __init__(self, mainGui, theProject):
|
||||
def __init__(self, mainGui):
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
self.theProject = theProject
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = mainGui
|
||||
|
||||
# Internal
|
||||
self._theToC = []
|
||||
self._currentRoot = None
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
hPx = CONFIG.pxInt(12)
|
||||
vPx = CONFIG.pxInt(4)
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
|
||||
# Header
|
||||
# ======
|
||||
|
||||
self.tocLabel = QLabel("<b>%s</b>" % self.tr("Table of Contents"))
|
||||
|
||||
self.novelValue = NovelSelector(self, self.theProject, self.mainGui)
|
||||
self.novelValue = NovelSelector(self, self.mainGui)
|
||||
self.novelValue.setMinimumWidth(CONFIG.pxInt(200))
|
||||
self.novelValue.novelSelectionChanged.connect(self._novelValueChanged)
|
||||
|
||||
@@ -447,7 +443,7 @@ class GuiProjectDetailsContents(QWidget):
|
||||
"""Extract the information from the project index.
|
||||
"""
|
||||
logger.debug("Populating ToC from handle '%s'", rootHandle)
|
||||
self._theToC = self.theProject.index.getTableOfContents(rootHandle, 2)
|
||||
self._theToC = self.mainGui.project.index.getTableOfContents(rootHandle, 2)
|
||||
self._theToC.append(("", 0, self.tr("END"), 0))
|
||||
return
|
||||
|
||||
@@ -500,7 +496,7 @@ class GuiProjectDetailsContents(QWidget):
|
||||
progPage = f"{cPage:n}"
|
||||
progText = f"{pgProg:.1f}{nwUnicode.U_THSP}%"
|
||||
|
||||
hDec = self.mainTheme.getHeaderDecoration(tLevel)
|
||||
hDec = CONFIG.theme.getHeaderDecoration(tLevel)
|
||||
if tTitle.strip() == "":
|
||||
tTitle = self.tr("Untitled")
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Open Project
|
||||
==============================
|
||||
GUI class for the load/browse/new project dialog
|
||||
|
||||
File History:
|
||||
Created: 2020-02-26 [0.4.5]
|
||||
@@ -22,6 +21,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
@@ -62,13 +62,12 @@ class GuiProjectLoad(QDialog):
|
||||
self.setObjectName("GuiProjectLoad")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.openState = self.NONE_STATE
|
||||
self.openPath = None
|
||||
|
||||
sPx = CONFIG.pxInt(16)
|
||||
nPx = CONFIG.pxInt(96)
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.innerBox = QHBoxLayout()
|
||||
@@ -80,7 +79,7 @@ class GuiProjectLoad(QDialog):
|
||||
self.setMinimumHeight(CONFIG.pxInt(400))
|
||||
|
||||
self.nwIcon = QLabel()
|
||||
self.nwIcon.setPixmap(self.mainGui.mainTheme.getPixmap("novelwriter", (nPx, nPx)))
|
||||
self.nwIcon.setPixmap(CONFIG.theme.getPixmap("novelwriter", (nPx, nPx)))
|
||||
self.innerBox.addWidget(self.nwIcon, 0, Qt.AlignTop)
|
||||
|
||||
self.projectForm = QGridLayout()
|
||||
@@ -101,8 +100,9 @@ class GuiProjectLoad(QDialog):
|
||||
self.listBox.setIconSize(QSize(iPx, iPx))
|
||||
|
||||
treeHead = self.listBox.headerItem()
|
||||
treeHead.setTextAlignment(self.C_COUNT, Qt.AlignRight)
|
||||
treeHead.setTextAlignment(self.C_TIME, Qt.AlignRight)
|
||||
if treeHead:
|
||||
treeHead.setTextAlignment(self.C_COUNT, Qt.AlignRight)
|
||||
treeHead.setTextAlignment(self.C_TIME, Qt.AlignRight)
|
||||
|
||||
self.lblRecent = QLabel("<b>%s</b>" % self.tr("Recently Opened Projects"))
|
||||
self.lblPath = QLabel("<b>%s</b>" % self.tr("Path"))
|
||||
@@ -110,7 +110,7 @@ class GuiProjectLoad(QDialog):
|
||||
self.selPath.setReadOnly(True)
|
||||
|
||||
self.browseButton = QPushButton("...")
|
||||
self.browseButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
|
||||
self.browseButton.setMaximumWidth(int(2.5*CONFIG.theme.getTextWidth("...")))
|
||||
self.browseButton.clicked.connect(self._doBrowse)
|
||||
|
||||
self.projectForm.addWidget(self.lblRecent, 0, 0, 1, 3)
|
||||
@@ -268,7 +268,7 @@ class GuiProjectLoad(QDialog):
|
||||
self.listBox.clear()
|
||||
dataList = CONFIG.recentProjects.listEntries()
|
||||
sortList = sorted(dataList, key=lambda x: x[3], reverse=True)
|
||||
nwxIcon = self.mainGui.mainTheme.getIcon("proj_nwx")
|
||||
nwxIcon = CONFIG.theme.getIcon("proj_nwx")
|
||||
for path, title, words, time in sortList:
|
||||
newItem = QTreeWidgetItem([""]*4)
|
||||
newItem.setIcon(self.C_NAME, nwxIcon)
|
||||
@@ -279,11 +279,10 @@ class GuiProjectLoad(QDialog):
|
||||
newItem.setTextAlignment(self.C_NAME, Qt.AlignLeft | Qt.AlignVCenter)
|
||||
newItem.setTextAlignment(self.C_COUNT, Qt.AlignRight | Qt.AlignVCenter)
|
||||
newItem.setTextAlignment(self.C_TIME, Qt.AlignRight | Qt.AlignVCenter)
|
||||
newItem.setFont(self.C_TIME, self.mainTheme.guiFontFixed)
|
||||
newItem.setFont(self.C_TIME, CONFIG.theme.guiFontFixed)
|
||||
self.listBox.addTopLevelItem(newItem)
|
||||
|
||||
if self.listBox.topLevelItemCount() > 0:
|
||||
self.listBox.topLevelItem(0).setSelected(True)
|
||||
self.listBox.setCurrentItem(self.listBox.topLevelItem(0))
|
||||
|
||||
projColWidth = CONFIG.projLoadColWidths
|
||||
if len(projColWidth) == 3:
|
||||
|
||||
@@ -60,15 +60,13 @@ class GuiProjectSettings(NPagedDialog):
|
||||
logger.debug("Create: GuiProjectSettings")
|
||||
self.setObjectName("GuiProjectSettings")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.theProject = mainGui.theProject
|
||||
|
||||
self.theProject.countStatus()
|
||||
self.mainGui = mainGui
|
||||
self.mainGui.project.countStatus()
|
||||
self.setWindowTitle(self.tr("Project Settings"))
|
||||
|
||||
wW = CONFIG.pxInt(570)
|
||||
wH = CONFIG.pxInt(375)
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
|
||||
self.setMinimumWidth(wW)
|
||||
self.setMinimumHeight(wH)
|
||||
@@ -117,34 +115,35 @@ class GuiProjectSettings(NPagedDialog):
|
||||
def _doSave(self):
|
||||
"""Save settings and close dialog.
|
||||
"""
|
||||
project = self.mainGui.project
|
||||
projName = self.tabMain.editName.text()
|
||||
bookTitle = self.tabMain.editTitle.text()
|
||||
bookAuthor = self.tabMain.editAuthor.text()
|
||||
spellLang = self.tabMain.spellLang.currentData()
|
||||
doBackup = not self.tabMain.doBackup.isChecked()
|
||||
|
||||
self.theProject.data.setName(projName)
|
||||
self.theProject.data.setTitle(bookTitle)
|
||||
self.theProject.data.setAuthor(bookAuthor)
|
||||
self.theProject.data.setDoBackup(doBackup)
|
||||
project.data.setName(projName)
|
||||
project.data.setTitle(bookTitle)
|
||||
project.data.setAuthor(bookAuthor)
|
||||
project.data.setDoBackup(doBackup)
|
||||
|
||||
# Remember this as updating spell dictionary can be expensive
|
||||
self._spellChanged = self.theProject.data.setSpellLang(spellLang)
|
||||
self._spellChanged = project.data.setSpellLang(spellLang)
|
||||
|
||||
if self.tabStatus.colChanged:
|
||||
newList, delList = self.tabStatus.getNewList()
|
||||
self.theProject.setStatusColours(newList, delList)
|
||||
project.setStatusColours(newList, delList)
|
||||
|
||||
if self.tabImport.colChanged:
|
||||
newList, delList = self.tabImport.getNewList()
|
||||
self.theProject.setImportColours(newList, delList)
|
||||
project.setImportColours(newList, delList)
|
||||
|
||||
if self.tabStatus.colChanged or self.tabImport.colChanged:
|
||||
self.mainGui.rebuildTrees()
|
||||
|
||||
if self.tabReplace.arChanged:
|
||||
newList = self.tabReplace.getNewList()
|
||||
self.theProject.data.setAutoReplace(newList)
|
||||
project.data.setAutoReplace(newList)
|
||||
|
||||
self._saveGuiSettings()
|
||||
self.accept()
|
||||
@@ -184,7 +183,7 @@ class GuiProjectSettings(NPagedDialog):
|
||||
statusColW = CONFIG.rpxInt(self.tabStatus.listBox.columnWidth(0))
|
||||
importColW = CONFIG.rpxInt(self.tabImport.listBox.columnWidth(0))
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
pOptions.setValue("GuiProjectSettings", "winWidth", winWidth)
|
||||
pOptions.setValue("GuiProjectSettings", "winHeight", winHeight)
|
||||
pOptions.setValue("GuiProjectSettings", "replaceColW", replaceColW)
|
||||
@@ -201,22 +200,22 @@ class GuiProjectEditMain(QWidget):
|
||||
def __init__(self, projGui):
|
||||
super().__init__(parent=projGui)
|
||||
|
||||
self.mainGui = projGui.mainGui
|
||||
self.theProject = projGui.theProject
|
||||
self.mainGui = projGui.mainGui
|
||||
|
||||
# The Form
|
||||
self.mainForm = NConfigLayout()
|
||||
self.mainForm.setHelpTextStyle(self.mainGui.mainTheme.helpText)
|
||||
self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
|
||||
self.setLayout(self.mainForm)
|
||||
|
||||
self.mainForm.addGroupLabel(self.tr("Project Settings"))
|
||||
|
||||
xW = CONFIG.pxInt(250)
|
||||
pData = self.mainGui.project.data
|
||||
|
||||
self.editName = QLineEdit()
|
||||
self.editName.setMaxLength(200)
|
||||
self.editName.setMaximumWidth(xW)
|
||||
self.editName.setText(self.theProject.data.name)
|
||||
self.editName.setText(pData.name)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Project name"),
|
||||
self.editName,
|
||||
@@ -226,7 +225,7 @@ class GuiProjectEditMain(QWidget):
|
||||
self.editTitle = QLineEdit()
|
||||
self.editTitle.setMaxLength(200)
|
||||
self.editTitle.setMaximumWidth(xW)
|
||||
self.editTitle.setText(self.theProject.data.title)
|
||||
self.editTitle.setText(pData.title)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Novel title"),
|
||||
self.editTitle,
|
||||
@@ -236,7 +235,7 @@ class GuiProjectEditMain(QWidget):
|
||||
self.editAuthor = QLineEdit()
|
||||
self.editAuthor.setMaxLength(200)
|
||||
self.editAuthor.setMaximumWidth(xW)
|
||||
self.editAuthor.setText(self.theProject.data.author)
|
||||
self.editAuthor.setText(pData.author)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Author(s)"),
|
||||
self.editAuthor,
|
||||
@@ -259,13 +258,13 @@ class GuiProjectEditMain(QWidget):
|
||||
)
|
||||
|
||||
spellIdx = 0
|
||||
if self.theProject.data.spellLang is not None:
|
||||
spellIdx = self.spellLang.findData(self.theProject.data.spellLang)
|
||||
if pData.spellLang is not None:
|
||||
spellIdx = self.spellLang.findData(pData.spellLang)
|
||||
if spellIdx != -1:
|
||||
self.spellLang.setCurrentIndex(spellIdx)
|
||||
|
||||
self.doBackup = NSwitch(self)
|
||||
self.doBackup.setChecked(not self.theProject.data.doBackup)
|
||||
self.doBackup.setChecked(not pData.doBackup)
|
||||
self.mainForm.addRow(
|
||||
self.tr("No backup on close"),
|
||||
self.doBackup,
|
||||
@@ -289,28 +288,26 @@ class GuiProjectEditStatus(QWidget):
|
||||
def __init__(self, projGui, isStatus):
|
||||
super().__init__(parent=projGui)
|
||||
|
||||
self.mainGui = projGui.mainGui
|
||||
self.theProject = projGui.theProject
|
||||
self.mainTheme = projGui.mainGui.mainTheme
|
||||
self.mainGui = projGui.mainGui
|
||||
|
||||
if isStatus:
|
||||
self.theStatus = self.theProject.data.itemStatus
|
||||
self.theStatus = self.mainGui.project.data.itemStatus
|
||||
pageLabel = self.tr("Novel File Status Levels")
|
||||
colSetting = "statusColW"
|
||||
else:
|
||||
self.theStatus = self.theProject.data.itemImport
|
||||
self.theStatus = self.mainGui.project.data.itemImport
|
||||
pageLabel = self.tr("Note File Importance Levels")
|
||||
colSetting = "importColW"
|
||||
|
||||
wCol0 = CONFIG.pxInt(
|
||||
self.theProject.options.getInt("GuiProjectSettings", colSetting, 130)
|
||||
self.mainGui.project.options.getInt("GuiProjectSettings", colSetting, 130)
|
||||
)
|
||||
|
||||
self.colDeleted = []
|
||||
self.colChanged = False
|
||||
self.selColour = QColor(100, 100, 100)
|
||||
|
||||
self.iPx = self.mainTheme.baseIconSize
|
||||
self.iPx = CONFIG.theme.baseIconSize
|
||||
|
||||
# The List
|
||||
# ========
|
||||
@@ -329,16 +326,16 @@ class GuiProjectEditStatus(QWidget):
|
||||
# List Controls
|
||||
# =============
|
||||
|
||||
self.addButton = QPushButton(self.mainTheme.getIcon("add"), "")
|
||||
self.addButton = QPushButton(CONFIG.theme.getIcon("add"), "")
|
||||
self.addButton.clicked.connect(self._newItem)
|
||||
|
||||
self.delButton = QPushButton(self.mainTheme.getIcon("remove"), "")
|
||||
self.delButton = QPushButton(CONFIG.theme.getIcon("remove"), "")
|
||||
self.delButton.clicked.connect(self._delItem)
|
||||
|
||||
self.upButton = QPushButton(self.mainTheme.getIcon("up"), "")
|
||||
self.upButton = QPushButton(CONFIG.theme.getIcon("up"), "")
|
||||
self.upButton.clicked.connect(lambda: self._moveItem(-1))
|
||||
|
||||
self.dnButton = QPushButton(self.mainTheme.getIcon("down"), "")
|
||||
self.dnButton = QPushButton(CONFIG.theme.getIcon("down"), "")
|
||||
self.dnButton.clicked.connect(lambda: self._moveItem(1))
|
||||
|
||||
# Edit Form
|
||||
@@ -577,13 +574,11 @@ class GuiProjectEditReplace(QWidget):
|
||||
def __init__(self, projGui):
|
||||
super().__init__(parent=projGui)
|
||||
|
||||
self.mainGui = projGui.mainGui
|
||||
self.mainTheme = projGui.mainGui.mainTheme
|
||||
self.theProject = projGui.theProject
|
||||
self.arChanged = False
|
||||
self.mainGui = projGui.mainGui
|
||||
self.arChanged = False
|
||||
|
||||
wCol0 = CONFIG.pxInt(
|
||||
self.theProject.options.getInt("GuiProjectSettings", "replaceColW", 130)
|
||||
self.mainGui.project.options.getInt("GuiProjectSettings", "replaceColW", 130)
|
||||
)
|
||||
pageLabel = self.tr("Text Replace List for Preview and Export")
|
||||
|
||||
@@ -599,7 +594,7 @@ class GuiProjectEditReplace(QWidget):
|
||||
self.listBox.setColumnWidth(self.COL_KEY, wCol0)
|
||||
self.listBox.setIndentation(0)
|
||||
|
||||
for aKey, aVal in self.theProject.data.autoReplace.items():
|
||||
for aKey, aVal in self.mainGui.project.data.autoReplace.items():
|
||||
newItem = QTreeWidgetItem(["<%s>" % aKey, aVal])
|
||||
self.listBox.addTopLevelItem(newItem)
|
||||
|
||||
@@ -609,10 +604,10 @@ class GuiProjectEditReplace(QWidget):
|
||||
# List Controls
|
||||
# =============
|
||||
|
||||
self.addButton = QPushButton(self.mainTheme.getIcon("add"), "")
|
||||
self.addButton = QPushButton(CONFIG.theme.getIcon("add"), "")
|
||||
self.addButton.clicked.connect(self._addEntry)
|
||||
|
||||
self.delButton = QPushButton(self.mainTheme.getIcon("remove"), "")
|
||||
self.delButton = QPushButton(CONFIG.theme.getIcon("remove"), "")
|
||||
self.delButton.clicked.connect(self._delEntry)
|
||||
|
||||
# Edit Form
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Quotes Dialog
|
||||
===============================
|
||||
GUI class for quotes dialog
|
||||
|
||||
File History:
|
||||
Created: 2020-06-18 [0.9]
|
||||
@@ -22,6 +21,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Updates
|
||||
=========================
|
||||
A dialog box for checking for latest updates
|
||||
|
||||
File History:
|
||||
Created: 2021-08-21 [1.5b1]
|
||||
@@ -22,6 +21,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
@@ -49,9 +49,6 @@ class GuiUpdates(QDialog):
|
||||
|
||||
logger.debug("Create: GuiUpdates")
|
||||
self.setObjectName("GuiUpdates")
|
||||
|
||||
self.mainGui = mainGui
|
||||
|
||||
self.setWindowTitle(self.tr("Check for Updates"))
|
||||
|
||||
nPx = CONFIG.pxInt(96)
|
||||
@@ -61,7 +58,7 @@ class GuiUpdates(QDialog):
|
||||
|
||||
# Left Box
|
||||
self.nwIcon = QLabel()
|
||||
self.nwIcon.setPixmap(self.mainGui.mainTheme.getPixmap("novelwriter", (nPx, nPx)))
|
||||
self.nwIcon.setPixmap(CONFIG.theme.getPixmap("novelwriter", (nPx, nPx)))
|
||||
|
||||
self.leftBox = QVBoxLayout()
|
||||
self.leftBox.addWidget(self.nwIcon)
|
||||
|
||||
@@ -50,17 +50,14 @@ class GuiWordList(QDialog):
|
||||
|
||||
logger.debug("Create: GuiWordList")
|
||||
self.setObjectName("GuiWordList")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
|
||||
self.setWindowTitle(self.tr("Project Word List"))
|
||||
|
||||
self.mainGui = mainGui
|
||||
|
||||
mS = CONFIG.pxInt(250)
|
||||
wW = CONFIG.pxInt(320)
|
||||
wH = CONFIG.pxInt(340)
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
|
||||
self.setMinimumWidth(mS)
|
||||
self.setMinimumHeight(mS)
|
||||
@@ -80,10 +77,10 @@ class GuiWordList(QDialog):
|
||||
|
||||
self.newEntry = QLineEdit()
|
||||
|
||||
self.addButton = QPushButton(self.mainTheme.getIcon("add"), "")
|
||||
self.addButton = QPushButton(CONFIG.theme.getIcon("add"), "")
|
||||
self.addButton.clicked.connect(self._doAdd)
|
||||
|
||||
self.delButton = QPushButton(self.mainTheme.getIcon("remove"), "")
|
||||
self.delButton = QPushButton(CONFIG.theme.getIcon("remove"), "")
|
||||
self.delButton.clicked.connect(self._doDelete)
|
||||
|
||||
self.editBox = QHBoxLayout()
|
||||
@@ -152,7 +149,7 @@ class GuiWordList(QDialog):
|
||||
def _doSave(self):
|
||||
"""Save the new word list and close."""
|
||||
self._saveGuiSettings()
|
||||
userDict = UserDictionary(self.theProject)
|
||||
userDict = UserDictionary(self.mainGui.project)
|
||||
for i in range(self.listBox.count()):
|
||||
item = self.listBox.item(i)
|
||||
if isinstance(item, QListWidgetItem):
|
||||
@@ -175,7 +172,7 @@ class GuiWordList(QDialog):
|
||||
|
||||
def _loadWordList(self):
|
||||
"""Load the project's word list, if it exists."""
|
||||
userDict = UserDictionary(self.theProject)
|
||||
userDict = UserDictionary(self.mainGui.project)
|
||||
userDict.load()
|
||||
self.listBox.clear()
|
||||
for word in userDict:
|
||||
@@ -188,7 +185,7 @@ class GuiWordList(QDialog):
|
||||
winWidth = CONFIG.rpxInt(self.width())
|
||||
winHeight = CONFIG.rpxInt(self.height())
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
pOptions.setValue("GuiWordList", "winWidth", winWidth)
|
||||
pOptions.setValue("GuiWordList", "winHeight", winHeight)
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – Enums
|
||||
===================
|
||||
Global enum values
|
||||
|
||||
File History:
|
||||
Created: 2018-11-02 [0.0.1]
|
||||
|
||||
@@ -42,7 +42,7 @@ class NProgressCircle(QProgressBar):
|
||||
"_cPen", "_bPen", "_tColor"
|
||||
)
|
||||
|
||||
def __init__(self, parent: QWidget, size: int, point: int):
|
||||
def __init__(self, parent: QWidget, size: int, point: int) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self._text = None
|
||||
self._point = point
|
||||
@@ -60,10 +60,8 @@ class NProgressCircle(QProgressBar):
|
||||
self.setFixedHeight(size)
|
||||
return
|
||||
|
||||
def setColours(
|
||||
self, back: QColor | None = None, track: QColor | None = None,
|
||||
bar: QColor | None = None, text: QColor | None = None
|
||||
):
|
||||
def setColours(self, back: QColor | None = None, track: QColor | None = None,
|
||||
bar: QColor | None = None, text: QColor | None = None) -> None:
|
||||
"""Set the colours of the widget."""
|
||||
if isinstance(back, QColor):
|
||||
self._dPen = QPen(back)
|
||||
@@ -76,13 +74,13 @@ class NProgressCircle(QProgressBar):
|
||||
self._tColor = text
|
||||
return
|
||||
|
||||
def setCentreText(self, text: str | None):
|
||||
def setCentreText(self, text: str | None) -> None:
|
||||
"""Replace the progress text with a custom string."""
|
||||
self._text = text
|
||||
self.setValue(self.value()) # Triggers a redraw
|
||||
return
|
||||
|
||||
def paintEvent(self, event: QPaintEvent):
|
||||
def paintEvent(self, event: QPaintEvent) -> None:
|
||||
"""Custom painter for the progress bar."""
|
||||
progress = 100.0*self.value()/self.maximum()
|
||||
angle = ceil(16*3.6*progress)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – Custom Widget: Config Layout
|
||||
==========================================
|
||||
A custom grid layout for config pages
|
||||
|
||||
File History:
|
||||
Created: 2020-05-03 [0.4.5]
|
||||
@@ -38,7 +37,7 @@ FONT_SCALE = 0.9
|
||||
|
||||
class NConfigLayout(QGridLayout):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
self._nextRow = 0
|
||||
@@ -57,7 +56,8 @@ class NConfigLayout(QGridLayout):
|
||||
# Getters and Setters
|
||||
##
|
||||
|
||||
def setHelpTextStyle(self, color: QColor | list | tuple, fontScale: float = FONT_SCALE):
|
||||
def setHelpTextStyle(self, color: QColor | list | tuple,
|
||||
fontScale: float = FONT_SCALE) -> None:
|
||||
"""Set the text color for the help text."""
|
||||
if isinstance(color, QColor):
|
||||
self._helpCol = color
|
||||
@@ -66,7 +66,7 @@ class NConfigLayout(QGridLayout):
|
||||
self._fontScale = fontScale
|
||||
return
|
||||
|
||||
def setHelpText(self, row: int, text: str):
|
||||
def setHelpText(self, row: int, text: str) -> None:
|
||||
"""Set the text for the help label."""
|
||||
if row in self._itemMap:
|
||||
qHelp = self._itemMap[row][1]
|
||||
@@ -74,7 +74,7 @@ class NConfigLayout(QGridLayout):
|
||||
qHelp.setText(text)
|
||||
return
|
||||
|
||||
def setLabelText(self, row: int, text: str):
|
||||
def setLabelText(self, row: int, text: str) -> None:
|
||||
"""Set the text for the main label."""
|
||||
if row in self._itemMap:
|
||||
self._itemMap[row](0).setText(text)
|
||||
@@ -84,7 +84,7 @@ class NConfigLayout(QGridLayout):
|
||||
# Class Methods
|
||||
##
|
||||
|
||||
def addGroupLabel(self, label: str):
|
||||
def addGroupLabel(self, label: str) -> None:
|
||||
"""Add a text label to separate groups of settings."""
|
||||
hM = CONFIG.pxInt(4)
|
||||
qLabel = QLabel("<b>%s</b>" % label)
|
||||
@@ -95,10 +95,8 @@ class NConfigLayout(QGridLayout):
|
||||
self._nextRow += 1
|
||||
return
|
||||
|
||||
def addRow(
|
||||
self, label: str, widget: QWidget, helpText: str | None = None,
|
||||
unit: str | None = None, button: QWidget | None = None
|
||||
) -> int:
|
||||
def addRow(self, label: str, widget: QWidget, helpText: str | None = None,
|
||||
unit: str | None = None, button: QWidget | None = None) -> int:
|
||||
"""Add a label and a widget as a new row of the grid."""
|
||||
wSp = CONFIG.pxInt(8)
|
||||
qLabel = QLabel(label)
|
||||
@@ -156,7 +154,7 @@ class NSimpleLayout(QGridLayout):
|
||||
column layout.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._nextRow = 0
|
||||
|
||||
@@ -171,7 +169,7 @@ class NSimpleLayout(QGridLayout):
|
||||
# Methods
|
||||
##
|
||||
|
||||
def addGroupLabel(self, label: str):
|
||||
def addGroupLabel(self, label: str) -> None:
|
||||
"""Add a text label to separate groups of settings."""
|
||||
hM = CONFIG.pxInt(4)
|
||||
qLabel = QLabel("<b>%s</b>" % label)
|
||||
@@ -182,7 +180,7 @@ class NSimpleLayout(QGridLayout):
|
||||
self._nextRow += 1
|
||||
return
|
||||
|
||||
def addRow(self, label: str, widget: QWidget):
|
||||
def addRow(self, label: str, widget: QWidget) -> None:
|
||||
"""Add a label and a widget as a new row of the grid."""
|
||||
wSp = CONFIG.pxInt(8)
|
||||
qLabel = QLabel(label)
|
||||
@@ -209,7 +207,8 @@ class NSimpleLayout(QGridLayout):
|
||||
|
||||
class NHelpLabel(QLabel):
|
||||
|
||||
def __init__(self, text: str, color: QColor | list | tuple, fontSize: float = FONT_SCALE):
|
||||
def __init__(self, text: str, color: QColor | list | tuple,
|
||||
fontSize: float = FONT_SCALE) -> None:
|
||||
super().__init__(text)
|
||||
|
||||
if isinstance(color, QColor):
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
"""
|
||||
novelWriter – GUI Components Module
|
||||
===================================
|
||||
A module of various small GUI components
|
||||
novelWriter – Custom Widget: Novel Selector
|
||||
===========================================
|
||||
|
||||
File History:
|
||||
Created: 2020-05-17 [0.5.1] StatusLED
|
||||
Created: 2022-11-17 [2.0] NovelSelector
|
||||
Created: 2022-11-17 [2.0]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2023, Veronica Berglyd Olsen
|
||||
@@ -23,16 +21,22 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from PyQt5.QtGui import QPainter
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtWidgets import QAbstractButton, QComboBox
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtWidgets import QComboBox, QWidget
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.enum import nwItemClass
|
||||
from novelwriter.constants import nwLabels
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.guimain import GuiMain
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -40,17 +44,12 @@ class NovelSelector(QComboBox):
|
||||
|
||||
novelSelectionChanged = pyqtSignal(str)
|
||||
|
||||
def __init__(self, parent, project, mainGui):
|
||||
def __init__(self, parent: QWidget, mainGui: GuiMain) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self._mainGui = mainGui
|
||||
self._project = project
|
||||
self._theme = mainGui.mainTheme
|
||||
self._blockSignal = False
|
||||
self._firstHandle = None
|
||||
|
||||
self.currentIndexChanged.connect(self._indexChanged)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
@@ -58,20 +57,19 @@ class NovelSelector(QComboBox):
|
||||
##
|
||||
|
||||
@property
|
||||
def handle(self):
|
||||
def handle(self) -> str:
|
||||
return self.currentData()
|
||||
|
||||
@property
|
||||
def firstHandle(self):
|
||||
def firstHandle(self) -> str | None:
|
||||
return self._firstHandle
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
|
||||
def setHandle(self, tHandle, blockSignal=True):
|
||||
"""Set the currently selected handle.
|
||||
"""
|
||||
def setHandle(self, tHandle: str, blockSignal: bool = True) -> None:
|
||||
"""Set the currently selected handle."""
|
||||
self._blockSignal = blockSignal
|
||||
if tHandle is None:
|
||||
index = self.count() - 1
|
||||
@@ -82,16 +80,15 @@ class NovelSelector(QComboBox):
|
||||
self._blockSignal = False
|
||||
return
|
||||
|
||||
def updateList(self, includeAll=False, prefix=None):
|
||||
"""Rebuild the list of novel items.
|
||||
"""
|
||||
def updateList(self, includeAll: bool = False, prefix: str | None = None) -> None:
|
||||
"""Rebuild the list of novel items."""
|
||||
self._blockSignal = True
|
||||
self._firstHandle = None
|
||||
self.clear()
|
||||
|
||||
icon = self._theme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL])
|
||||
icon = CONFIG.theme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL])
|
||||
handle = self.currentData()
|
||||
for tHandle, nwItem in self._project.tree.iterRoots(nwItemClass.NOVEL):
|
||||
for tHandle, nwItem in self._mainGui.project.tree.iterRoots(nwItemClass.NOVEL):
|
||||
if prefix:
|
||||
name = prefix.format(nwItem.itemName)
|
||||
self.addItem(name, tHandle)
|
||||
@@ -116,67 +113,10 @@ class NovelSelector(QComboBox):
|
||||
##
|
||||
|
||||
@pyqtSlot(int)
|
||||
def _indexChanged(self, index):
|
||||
"""Re-emit the change of selected novel signal, unless blocked.
|
||||
"""
|
||||
def _indexChanged(self, index: int) -> None:
|
||||
"""Re-emit the change of selection signal, unless blocked."""
|
||||
if not self._blockSignal:
|
||||
self.novelSelectionChanged.emit(self.currentData())
|
||||
return
|
||||
|
||||
# END Class NovelSelector
|
||||
|
||||
|
||||
class StatusLED(QAbstractButton):
|
||||
|
||||
S_NONE = 0
|
||||
S_BAD = 1
|
||||
S_GOOD = 2
|
||||
|
||||
def __init__(self, colNone, colGood, colBad, sW, sH, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self._colNone = colNone
|
||||
self._colGood = colGood
|
||||
self._colBad = colBad
|
||||
self._theCol = colNone
|
||||
|
||||
self.setFixedWidth(sW)
|
||||
self.setFixedHeight(sH)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setState(self, theState):
|
||||
"""Set the colour state.
|
||||
"""
|
||||
if theState == self.S_GOOD:
|
||||
self._theCol = self._colGood
|
||||
elif theState == self.S_BAD:
|
||||
self._theCol = self._colBad
|
||||
else:
|
||||
self._theCol = self._colNone
|
||||
|
||||
self.update()
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Events
|
||||
##
|
||||
|
||||
def paintEvent(self, _):
|
||||
"""Drawing the LED.
|
||||
"""
|
||||
qPalette = self.palette()
|
||||
qPaint = QPainter(self)
|
||||
qPaint.setRenderHint(QPainter.Antialiasing, True)
|
||||
qPaint.setPen(qPalette.dark().color())
|
||||
qPaint.setBrush(self._theCol)
|
||||
qPaint.setOpacity(1.0)
|
||||
qPaint.drawEllipse(1, 1, self.width() - 2, self.height() - 2)
|
||||
return
|
||||
|
||||
# END Class StatusLED
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – Custom Widget: Paged Dialog
|
||||
=========================================
|
||||
A custom dialog with tabs and a vertical tab bar
|
||||
|
||||
File History:
|
||||
Created: 2020-05-17 [0.5.1]
|
||||
@@ -22,11 +21,13 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtCore import QRect, QPoint
|
||||
from PyQt5.QtGui import QPaintEvent
|
||||
from PyQt5.QtCore import QRect, QPoint, QSize
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QHBoxLayout, QStyle, QStyleOptionTab, QStylePainter, QTabBar,
|
||||
QTabWidget, QVBoxLayout
|
||||
QTabWidget, QVBoxLayout, QWidget
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG
|
||||
@@ -34,7 +35,7 @@ from novelwriter import CONFIG
|
||||
|
||||
class NPagedDialog(QDialog):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self._tabBar = NVerticalTabBar(self)
|
||||
@@ -67,21 +68,18 @@ class NPagedDialog(QDialog):
|
||||
|
||||
return
|
||||
|
||||
def addTab(self, widget, label):
|
||||
"""Forward the adding of tabs to the QTabWidget.
|
||||
"""
|
||||
def addTab(self, widget: QWidget, label: str) -> None:
|
||||
"""Forward the adding of tabs to the QTabWidget."""
|
||||
self._tabBox.addTab(widget, label)
|
||||
return
|
||||
|
||||
def addControls(self, buttonBar):
|
||||
"""Add a button bar to the dialog.
|
||||
"""
|
||||
def addControls(self, buttonBar: QWidget) -> None:
|
||||
"""Add a button bar to the dialog."""
|
||||
self._buttonBox.addWidget(buttonBar)
|
||||
return
|
||||
|
||||
def setCurrentWidget(self, widget):
|
||||
"""Forward the changing of tab to the QTabWidget.
|
||||
"""
|
||||
def setCurrentWidget(self, widget: QWidget) -> None:
|
||||
"""Forward the changing of tab to the QTabWidget."""
|
||||
self._tabBox.setCurrentWidget(widget)
|
||||
return
|
||||
|
||||
@@ -90,20 +88,19 @@ class NPagedDialog(QDialog):
|
||||
|
||||
class NVerticalTabBar(QTabBar):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self._mW = CONFIG.pxInt(150)
|
||||
return
|
||||
|
||||
def tabSizeHint(self, index):
|
||||
"""Return a transposed size hint for the rotated bar.
|
||||
"""
|
||||
def tabSizeHint(self, index: int) -> QSize:
|
||||
"""Return a transposed size hint for the rotated bar."""
|
||||
tSize = super().tabSizeHint(index)
|
||||
tSize.transpose()
|
||||
tSize.setWidth(min(tSize.width(), self._mW))
|
||||
return tSize
|
||||
|
||||
def paintEvent(self, event):
|
||||
def paintEvent(self, event: QPaintEvent) -> None:
|
||||
"""Custom implementation of the label painter that rotates the
|
||||
label 90 degrees.
|
||||
"""
|
||||
|
||||
@@ -35,11 +35,11 @@ class NProgressSimple(QProgressBar):
|
||||
A custom widget that paints a plain bar with no other styling.
|
||||
"""
|
||||
|
||||
def __init__(self, parent: QWidget):
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
return
|
||||
|
||||
def paintEvent(self, event: QPaintEvent):
|
||||
def paintEvent(self, event: QPaintEvent) -> None:
|
||||
"""Custom painter for the progress bar."""
|
||||
if self.value() == 0:
|
||||
return
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
"""
|
||||
novelWriter – Custom Widget: Status LED
|
||||
=======================================
|
||||
|
||||
File History:
|
||||
Created: 2020-05-17 [0.5.1]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2023, Veronica Berglyd Olsen
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Literal
|
||||
|
||||
from PyQt5.QtGui import QColor, QPaintEvent, QPainter
|
||||
from PyQt5.QtWidgets import QAbstractButton, QWidget
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class StatusLED(QAbstractButton):
|
||||
|
||||
S_NONE = 0
|
||||
S_BAD = 1
|
||||
S_GOOD = 2
|
||||
|
||||
def __init__(self, colNone: QColor, colGood: QColor, colBad: QColor,
|
||||
sW: int, sH: int, parent: QWidget | None = None) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self._colNone = colNone
|
||||
self._colGood = colGood
|
||||
self._colBad = colBad
|
||||
self._theCol = colNone
|
||||
|
||||
self.setFixedWidth(sW)
|
||||
self.setFixedHeight(sH)
|
||||
|
||||
return
|
||||
|
||||
def setState(self, state: Literal[0, 1, 2]) -> None:
|
||||
"""Set the colour state."""
|
||||
if state == self.S_GOOD:
|
||||
self._theCol = self._colGood
|
||||
elif state == self.S_BAD:
|
||||
self._theCol = self._colBad
|
||||
else:
|
||||
self._theCol = self._colNone
|
||||
self.update()
|
||||
return
|
||||
|
||||
def paintEvent(self, event: QPaintEvent) -> None:
|
||||
"""Drawing the LED."""
|
||||
qPalette = self.palette()
|
||||
qPaint = QPainter(self)
|
||||
qPaint.setRenderHint(QPainter.Antialiasing, True)
|
||||
qPaint.setPen(qPalette.dark().color())
|
||||
qPaint.setBrush(self._theCol)
|
||||
qPaint.setOpacity(1.0)
|
||||
qPaint.drawEllipse(1, 1, self.width() - 2, self.height() - 2)
|
||||
return
|
||||
|
||||
# END Class StatusLED
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – Custom Widget: Switch
|
||||
===================================
|
||||
A custom switch widget
|
||||
|
||||
File History:
|
||||
Created: 2020-05-03 [0.4.5]
|
||||
@@ -22,10 +21,11 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtGui import QPainter
|
||||
from PyQt5.QtCore import Qt, QRectF, QPropertyAnimation, pyqtProperty
|
||||
from PyQt5.QtWidgets import QSizePolicy, QAbstractButton
|
||||
from PyQt5.QtGui import QMouseEvent, QPainter, QPaintEvent, QResizeEvent
|
||||
from PyQt5.QtCore import QEvent, QPropertyAnimation, QRectF, Qt, pyqtProperty
|
||||
from PyQt5.QtWidgets import QAbstractButton, QSizePolicy, QWidget
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.constants import nwUnicode
|
||||
@@ -33,7 +33,8 @@ from novelwriter.constants import nwUnicode
|
||||
|
||||
class NSwitch(QAbstractButton):
|
||||
|
||||
def __init__(self, parent=None, width=None, height=None):
|
||||
def __init__(self, parent: QWidget | None = None,
|
||||
width: int | None = None, height: int | None = None) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
if width is None:
|
||||
@@ -64,12 +65,12 @@ class NSwitch(QAbstractButton):
|
||||
# Properties
|
||||
##
|
||||
|
||||
@pyqtProperty(int)
|
||||
def offset(self):
|
||||
@pyqtProperty(int) # type: ignore
|
||||
def offset(self) -> int: # type: ignore
|
||||
return self._offset
|
||||
|
||||
@offset.setter
|
||||
def offset(self, offset):
|
||||
@offset.setter # type: ignore
|
||||
def offset(self, offset: int):
|
||||
self._offset = offset
|
||||
self.update()
|
||||
return
|
||||
@@ -78,33 +79,30 @@ class NSwitch(QAbstractButton):
|
||||
# Getters and Setters
|
||||
##
|
||||
|
||||
def setChecked(self, checked):
|
||||
"""Overload setChecked to also alter the offset.
|
||||
"""
|
||||
def setChecked(self, checked: bool) -> None:
|
||||
"""Overload setChecked to also alter the offset."""
|
||||
super().setChecked(checked)
|
||||
if checked:
|
||||
self.offset = self._xW - self._xR
|
||||
self._offset = self._xW - self._xR
|
||||
else:
|
||||
self.offset = self._xR
|
||||
self._offset = self._xR
|
||||
return
|
||||
|
||||
##
|
||||
# Events
|
||||
##
|
||||
|
||||
def resizeEvent(self, event):
|
||||
"""Overload resize to ensure correct offset.
|
||||
"""
|
||||
def resizeEvent(self, event: QResizeEvent) -> None:
|
||||
"""Overload resize to ensure correct offset."""
|
||||
super().resizeEvent(event)
|
||||
if self.isChecked():
|
||||
self.offset = self._xW - self._xR
|
||||
self._offset = self._xW - self._xR
|
||||
else:
|
||||
self.offset = self._xR
|
||||
self._offset = self._xR
|
||||
return
|
||||
|
||||
def paintEvent(self, event):
|
||||
"""Drawing the switch itself.
|
||||
"""
|
||||
def paintEvent(self, event: QPaintEvent) -> None:
|
||||
"""Drawing the switch itself."""
|
||||
qPaint = QPainter(self)
|
||||
qPaint.setRenderHint(QPainter.Antialiasing, True)
|
||||
qPaint.setPen(Qt.NoPen)
|
||||
@@ -134,27 +132,26 @@ class NSwitch(QAbstractButton):
|
||||
qPaint.drawRoundedRect(0, 0, self._xW, self._xH, self._xR, self._xR)
|
||||
|
||||
qPaint.setBrush(thumbBrush)
|
||||
qPaint.drawEllipse(self.offset - self._rR, self._rB, self._rH, self._rH)
|
||||
qPaint.drawEllipse(self._offset - self._rR, self._rB, self._rH, self._rH)
|
||||
|
||||
theFont = qPaint.font()
|
||||
theFont.setPixelSize(self._xT)
|
||||
qPaint.setPen(textColor)
|
||||
qPaint.setFont(theFont)
|
||||
qPaint.drawText(
|
||||
QRectF(self.offset - self._rR, self._rB, self._rH, self._rH),
|
||||
QRectF(self._offset - self._rR, self._rB, self._rH, self._rH),
|
||||
Qt.AlignCenter, thumbText
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
"""Animate the switch on mouse release.
|
||||
"""
|
||||
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
|
||||
"""Animate the switch on mouse release."""
|
||||
super().mouseReleaseEvent(event)
|
||||
if event.button() == Qt.LeftButton:
|
||||
doAnim = QPropertyAnimation(self, b"offset", self)
|
||||
doAnim.setDuration(120)
|
||||
doAnim.setStartValue(self.offset)
|
||||
doAnim.setStartValue(self._offset)
|
||||
if self.isChecked():
|
||||
doAnim.setEndValue(self._xW - self._xR)
|
||||
else:
|
||||
@@ -162,9 +159,8 @@ class NSwitch(QAbstractButton):
|
||||
doAnim.start()
|
||||
return
|
||||
|
||||
def enterEvent(self, event):
|
||||
"""Change the cursor when hovering the button.
|
||||
"""
|
||||
def enterEvent(self, event: QEvent) -> None:
|
||||
"""Change the cursor when hovering the button."""
|
||||
self.setCursor(Qt.PointingHandCursor)
|
||||
super().enterEvent(event)
|
||||
return
|
||||
|
||||
@@ -23,8 +23,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtSignal
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtCore import Qt, pyqtSignal
|
||||
from PyQt5.QtWidgets import QGridLayout, QLabel, QScrollArea, QSizePolicy, QWidget
|
||||
|
||||
from novelwriter.extensions.switch import NSwitch
|
||||
@@ -39,7 +39,7 @@ class NSwitchBox(QScrollArea):
|
||||
|
||||
switchToggled = pyqtSignal(str, bool)
|
||||
|
||||
def __init__(self, parent: QWidget, baseSize: int):
|
||||
def __init__(self, parent: QWidget, baseSize: int) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self._index = 0
|
||||
self._hSwitch = baseSize
|
||||
@@ -49,7 +49,7 @@ class NSwitchBox(QScrollArea):
|
||||
self.clear()
|
||||
return
|
||||
|
||||
def clear(self):
|
||||
def clear(self) -> None:
|
||||
"""Rebuild the content of the core widget."""
|
||||
self._index = 0
|
||||
self._widgets = []
|
||||
@@ -66,7 +66,7 @@ class NSwitchBox(QScrollArea):
|
||||
|
||||
return
|
||||
|
||||
def addLabel(self, text: str):
|
||||
def addLabel(self, text: str) -> None:
|
||||
"""Add a header label to the content box."""
|
||||
label = QLabel(text)
|
||||
font = label.font()
|
||||
@@ -77,7 +77,7 @@ class NSwitchBox(QScrollArea):
|
||||
self._bumpIndex()
|
||||
return
|
||||
|
||||
def addItem(self, qIcon: QIcon, text: str, identifier: str, default: bool = False):
|
||||
def addItem(self, qIcon: QIcon, text: str, identifier: str, default: bool = False) -> None:
|
||||
"""Add an item to the content box."""
|
||||
icon = QLabel("")
|
||||
icon.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
@@ -97,7 +97,7 @@ class NSwitchBox(QScrollArea):
|
||||
|
||||
return
|
||||
|
||||
def addSeparator(self):
|
||||
def addSeparator(self) -> None:
|
||||
"""Add a blank entry in the content box."""
|
||||
spacer = QWidget()
|
||||
spacer.setFixedHeight(int(0.5*self._sIcon))
|
||||
@@ -106,7 +106,7 @@ class NSwitchBox(QScrollArea):
|
||||
self._bumpIndex()
|
||||
return
|
||||
|
||||
def setInnerContentsMargins(self, left: int, top: int, right: int, bottom: int):
|
||||
def setInnerContentsMargins(self, left: int, top: int, right: int, bottom: int) -> None:
|
||||
"""Set the contents margins of the inner layout."""
|
||||
self._content.setContentsMargins(left, top, right, bottom)
|
||||
return
|
||||
@@ -115,12 +115,12 @@ class NSwitchBox(QScrollArea):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _emitSwitchSignal(self, identifier: str, state: bool):
|
||||
def _emitSwitchSignal(self, identifier: str, state: bool) -> None:
|
||||
"""Emit a signal for a switch toggle."""
|
||||
self.switchToggled.emit(identifier, state)
|
||||
return
|
||||
|
||||
def _bumpIndex(self):
|
||||
def _bumpIndex(self) -> None:
|
||||
"""Increase the index counter and make sure only the last
|
||||
columns is stretching.
|
||||
"""
|
||||
|
||||
@@ -84,9 +84,7 @@ class GuiDocEditor(QTextEdit):
|
||||
logger.debug("Create: GuiDocEditor")
|
||||
|
||||
# Class Variables
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
self._nwDocument = None
|
||||
self._nwItem = None
|
||||
@@ -134,7 +132,7 @@ class GuiDocEditor(QTextEdit):
|
||||
self.docSearch = GuiDocEditSearch(self)
|
||||
|
||||
# Syntax
|
||||
self.spEnchant = NWSpellEnchant(self.theProject)
|
||||
self.spEnchant = NWSpellEnchant(self.mainGui.project)
|
||||
self.highLight = GuiDocHighlighter(qDoc, self.mainGui, self.spEnchant)
|
||||
|
||||
# Context Menu
|
||||
@@ -229,14 +227,14 @@ class GuiDocEditor(QTextEdit):
|
||||
"""Update the syntax highlighting theme.
|
||||
"""
|
||||
mainPalette = self.palette()
|
||||
mainPalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
|
||||
mainPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
|
||||
mainPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
mainPalette.setColor(QPalette.Window, QColor(*CONFIG.theme.colBack))
|
||||
mainPalette.setColor(QPalette.Base, QColor(*CONFIG.theme.colBack))
|
||||
mainPalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
|
||||
self.setPalette(mainPalette)
|
||||
|
||||
docPalette = self.viewport().palette()
|
||||
docPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
|
||||
docPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
docPalette.setColor(QPalette.Base, QColor(*CONFIG.theme.colBack))
|
||||
docPalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
|
||||
self.viewport().setPalette(docPalette)
|
||||
|
||||
self.docHeader.matchColours()
|
||||
@@ -342,7 +340,7 @@ class GuiDocEditor(QTextEdit):
|
||||
document is new (empty string), we set up the editor for editing
|
||||
the file.
|
||||
"""
|
||||
self._nwDocument = self.theProject.storage.getDocument(tHandle)
|
||||
self._nwDocument = self.mainGui.project.storage.getDocument(tHandle)
|
||||
self._nwItem = self._nwDocument.getCurrentItem()
|
||||
|
||||
theDoc = self._nwDocument.readDocument()
|
||||
@@ -518,10 +516,10 @@ class GuiDocEditor(QTextEdit):
|
||||
self.setDocumentChanged(False)
|
||||
|
||||
oldHeader = self._nwItem.mainHeading
|
||||
oldCount = self.theProject.index.getHandleHeaderCount(tHandle)
|
||||
self.theProject.index.scanText(tHandle, docText)
|
||||
oldCount = self.mainGui.project.index.getHandleHeaderCount(tHandle)
|
||||
self.mainGui.project.index.scanText(tHandle, docText)
|
||||
newHeader = self._nwItem.mainHeading
|
||||
newCount = self.theProject.index.getHandleHeaderCount(tHandle)
|
||||
newCount = self.mainGui.project.index.getHandleHeaderCount(tHandle)
|
||||
|
||||
if self._nwItem.itemClass == nwItemClass.NOVEL:
|
||||
if oldCount == newCount:
|
||||
@@ -700,10 +698,10 @@ class GuiDocEditor(QTextEdit):
|
||||
"""Set the spell checker dictionary language, and emit the
|
||||
dictionary changed signal.
|
||||
"""
|
||||
if self.theProject.data.spellLang is None:
|
||||
if self.mainGui.project.data.spellLang is None:
|
||||
theLang = CONFIG.spellLanguage
|
||||
else:
|
||||
theLang = self.theProject.data.spellLang
|
||||
theLang = self.mainGui.project.data.spellLang
|
||||
|
||||
self.spEnchant.setLanguage(theLang)
|
||||
_, theProvider = self.spEnchant.describeDict()
|
||||
@@ -736,7 +734,7 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
self._spellCheck = theMode
|
||||
self.mainGui.mainMenu.setSpellCheck(theMode)
|
||||
self.theProject.data.setSpellCheck(theMode)
|
||||
self.mainGui.project.data.setSpellCheck(theMode)
|
||||
self.highLight.setSpellCheck(theMode)
|
||||
if not self._bigDoc or theMode is False:
|
||||
# We don't run the spell checker automatically on big docs
|
||||
@@ -1918,7 +1916,7 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
if theText.startswith("@"):
|
||||
|
||||
isGood, tBits, tPos = self.theProject.index.scanThis(theText)
|
||||
isGood, tBits, tPos = self.mainGui.project.index.scanThis(theText)
|
||||
if not isGood:
|
||||
return False
|
||||
|
||||
@@ -2223,10 +2221,8 @@ class GuiDocEditSearch(QFrame):
|
||||
|
||||
logger.debug("Create: GuiDocEditSearch")
|
||||
|
||||
self.docEditor = docEditor
|
||||
self.mainGui = docEditor.mainGui
|
||||
self.theProject = docEditor.theProject
|
||||
self.mainTheme = docEditor.mainTheme
|
||||
self.docEditor = docEditor
|
||||
self.mainGui = docEditor.mainGui
|
||||
|
||||
self.repVisible = False
|
||||
self.isCaseSense = CONFIG.searchCase
|
||||
@@ -2237,9 +2233,9 @@ class GuiDocEditSearch(QFrame):
|
||||
self.doMatchCap = CONFIG.searchMatchCap
|
||||
|
||||
mPx = CONFIG.pxInt(6)
|
||||
tPx = int(0.8*self.mainTheme.fontPixelSize)
|
||||
self.boxFont = self.mainTheme.guiFont
|
||||
self.boxFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
|
||||
tPx = int(0.8*CONFIG.theme.fontPixelSize)
|
||||
self.boxFont = CONFIG.theme.guiFont
|
||||
self.boxFont.setPointSizeF(0.9*CONFIG.theme.fontPointSize)
|
||||
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
self.setAutoFillBackground(True)
|
||||
@@ -2272,7 +2268,7 @@ class GuiDocEditSearch(QFrame):
|
||||
|
||||
self.resultLabel = QLabel("?/?")
|
||||
self.resultLabel.setFont(self.boxFont)
|
||||
self.resultLabel.setMinimumWidth(self.mainTheme.getTextWidth("?/?", self.boxFont))
|
||||
self.resultLabel.setMinimumWidth(CONFIG.theme.getTextWidth("?/?", self.boxFont))
|
||||
|
||||
self.toggleCase = QAction(self.tr("Case Sensitive"), self)
|
||||
self.toggleCase.setCheckable(True)
|
||||
@@ -2378,15 +2374,15 @@ class GuiDocEditSearch(QFrame):
|
||||
self.replaceBox.setPalette(qPalette)
|
||||
|
||||
# Set icons
|
||||
self.toggleCase.setIcon(self.mainTheme.getIcon("search_case"))
|
||||
self.toggleWord.setIcon(self.mainTheme.getIcon("search_word"))
|
||||
self.toggleRegEx.setIcon(self.mainTheme.getIcon("search_regex"))
|
||||
self.toggleLoop.setIcon(self.mainTheme.getIcon("search_loop"))
|
||||
self.toggleProject.setIcon(self.mainTheme.getIcon("search_project"))
|
||||
self.toggleMatchCap.setIcon(self.mainTheme.getIcon("search_preserve"))
|
||||
self.cancelSearch.setIcon(self.mainTheme.getIcon("search_cancel"))
|
||||
self.searchButton.setIcon(self.mainTheme.getIcon("search"))
|
||||
self.replaceButton.setIcon(self.mainTheme.getIcon("search_replace"))
|
||||
self.toggleCase.setIcon(CONFIG.theme.getIcon("search_case"))
|
||||
self.toggleWord.setIcon(CONFIG.theme.getIcon("search_word"))
|
||||
self.toggleRegEx.setIcon(CONFIG.theme.getIcon("search_regex"))
|
||||
self.toggleLoop.setIcon(CONFIG.theme.getIcon("search_loop"))
|
||||
self.toggleProject.setIcon(CONFIG.theme.getIcon("search_project"))
|
||||
self.toggleMatchCap.setIcon(CONFIG.theme.getIcon("search_preserve"))
|
||||
self.cancelSearch.setIcon(CONFIG.theme.getIcon("search_cancel"))
|
||||
self.searchButton.setIcon(CONFIG.theme.getIcon("search"))
|
||||
self.replaceButton.setIcon(CONFIG.theme.getIcon("search_replace"))
|
||||
|
||||
# Set stylesheets
|
||||
self.searchOpt.setStyleSheet("QToolBar {padding: 0;}")
|
||||
@@ -2478,7 +2474,7 @@ class GuiDocEditSearch(QFrame):
|
||||
"""
|
||||
currRes = "?" if currRes is None else currRes
|
||||
resCount = "?" if resCount is None else "1000+" if resCount > 1000 else resCount
|
||||
minWidth = self.mainTheme.getTextWidth(f"{resCount}//{resCount}", self.boxFont)
|
||||
minWidth = CONFIG.theme.getTextWidth(f"{resCount}//{resCount}", self.boxFont)
|
||||
self.resultLabel.setText(f"{currRes}/{resCount}")
|
||||
self.resultLabel.setMinimumWidth(minWidth)
|
||||
self.adjustSize()
|
||||
@@ -2638,14 +2634,12 @@ class GuiDocEditHeader(QWidget):
|
||||
|
||||
logger.debug("Create: GuiDocEditHeader")
|
||||
|
||||
self.docEditor = docEditor
|
||||
self.mainGui = docEditor.mainGui
|
||||
self.theProject = docEditor.theProject
|
||||
self.mainTheme = docEditor.mainTheme
|
||||
self.docEditor = docEditor
|
||||
self.mainGui = docEditor.mainGui
|
||||
|
||||
self._docHandle = None
|
||||
|
||||
fPx = int(0.9*self.mainTheme.fontPixelSize)
|
||||
fPx = int(0.9*CONFIG.theme.fontPixelSize)
|
||||
hSp = CONFIG.pxInt(6)
|
||||
|
||||
# Main Widget Settings
|
||||
@@ -2662,7 +2656,7 @@ class GuiDocEditHeader(QWidget):
|
||||
self.theTitle.setFixedHeight(fPx)
|
||||
|
||||
lblFont = self.theTitle.font()
|
||||
lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
|
||||
lblFont.setPointSizeF(0.9*CONFIG.theme.fontPointSize)
|
||||
self.theTitle.setFont(lblFont)
|
||||
|
||||
# Buttons
|
||||
@@ -2732,15 +2726,15 @@ class GuiDocEditHeader(QWidget):
|
||||
def updateTheme(self):
|
||||
"""Update theme elements.
|
||||
"""
|
||||
self.editButton.setIcon(self.mainTheme.getIcon("edit"))
|
||||
self.searchButton.setIcon(self.mainTheme.getIcon("search"))
|
||||
self.minmaxButton.setIcon(self.mainTheme.getIcon("maximise"))
|
||||
self.closeButton.setIcon(self.mainTheme.getIcon("close"))
|
||||
self.editButton.setIcon(CONFIG.theme.getIcon("edit"))
|
||||
self.searchButton.setIcon(CONFIG.theme.getIcon("search"))
|
||||
self.minmaxButton.setIcon(CONFIG.theme.getIcon("maximise"))
|
||||
self.closeButton.setIcon(CONFIG.theme.getIcon("close"))
|
||||
|
||||
buttonStyle = (
|
||||
"QToolButton {{border: none; background: transparent;}} "
|
||||
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
|
||||
).format(*self.mainTheme.colText)
|
||||
).format(*CONFIG.theme.colText)
|
||||
|
||||
self.editButton.setStyleSheet(buttonStyle)
|
||||
self.searchButton.setStyleSheet(buttonStyle)
|
||||
@@ -2756,9 +2750,9 @@ class GuiDocEditHeader(QWidget):
|
||||
theme rather than the main GUI.
|
||||
"""
|
||||
thePalette = QPalette()
|
||||
thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
thePalette.setColor(QPalette.Window, QColor(*CONFIG.theme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*CONFIG.theme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
|
||||
|
||||
self.setPalette(thePalette)
|
||||
self.theTitle.setPalette(thePalette)
|
||||
@@ -2778,17 +2772,18 @@ class GuiDocEditHeader(QWidget):
|
||||
self.minmaxButton.setVisible(False)
|
||||
return True
|
||||
|
||||
pTree = self.mainGui.project.tree
|
||||
if CONFIG.showFullPath:
|
||||
tTitle = []
|
||||
tTree = self.theProject.tree.getItemPath(tHandle)
|
||||
tTree = pTree.getItemPath(tHandle)
|
||||
for aHandle in reversed(tTree):
|
||||
nwItem = self.theProject.tree[aHandle]
|
||||
nwItem = pTree[aHandle]
|
||||
if nwItem is not None:
|
||||
tTitle.append(nwItem.itemName)
|
||||
sSep = " %s " % nwUnicode.U_RSAQUO
|
||||
self.theTitle.setText(sSep.join(tTitle))
|
||||
else:
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
nwItem = pTree[tHandle]
|
||||
if nwItem is None:
|
||||
return False
|
||||
self.theTitle.setText(nwItem.itemName)
|
||||
@@ -2806,9 +2801,9 @@ class GuiDocEditHeader(QWidget):
|
||||
toggleFocusMode function and should not be activated directly.
|
||||
"""
|
||||
if self.mainGui.isFocusMode:
|
||||
self.minmaxButton.setIcon(self.mainTheme.getIcon("minimise"))
|
||||
self.minmaxButton.setIcon(CONFIG.theme.getIcon("minimise"))
|
||||
else:
|
||||
self.minmaxButton.setIcon(self.mainTheme.getIcon("maximise"))
|
||||
self.minmaxButton.setIcon(CONFIG.theme.getIcon("maximise"))
|
||||
return
|
||||
|
||||
##
|
||||
@@ -2873,23 +2868,21 @@ class GuiDocEditFooter(QWidget):
|
||||
|
||||
logger.debug("Create: GuiDocEditFooter")
|
||||
|
||||
self.docEditor = docEditor
|
||||
self.mainGui = docEditor.mainGui
|
||||
self.theProject = docEditor.theProject
|
||||
self.mainTheme = docEditor.mainTheme
|
||||
self.docEditor = docEditor
|
||||
self.mainGui = docEditor.mainGui
|
||||
|
||||
self._theItem = None
|
||||
self._docHandle = None
|
||||
|
||||
self._docSelection = False
|
||||
|
||||
self.sPx = int(round(0.9*self.mainTheme.baseIconSize))
|
||||
fPx = int(0.9*self.mainTheme.fontPixelSize)
|
||||
self.sPx = int(round(0.9*CONFIG.theme.baseIconSize))
|
||||
fPx = int(0.9*CONFIG.theme.fontPixelSize)
|
||||
bSp = CONFIG.pxInt(4)
|
||||
hSp = CONFIG.pxInt(6)
|
||||
|
||||
lblFont = self.font()
|
||||
lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
|
||||
lblFont.setPointSizeF(0.9*CONFIG.theme.fontPointSize)
|
||||
|
||||
# Main Widget Settings
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
@@ -2976,8 +2969,8 @@ class GuiDocEditFooter(QWidget):
|
||||
def updateTheme(self):
|
||||
"""Update theme elements.
|
||||
"""
|
||||
self.linesIcon.setPixmap(self.mainTheme.getPixmap("status_lines", (self.sPx, self.sPx)))
|
||||
self.wordsIcon.setPixmap(self.mainTheme.getPixmap("status_stats", (self.sPx, self.sPx)))
|
||||
self.linesIcon.setPixmap(CONFIG.theme.getPixmap("status_lines", (self.sPx, self.sPx)))
|
||||
self.wordsIcon.setPixmap(CONFIG.theme.getPixmap("status_stats", (self.sPx, self.sPx)))
|
||||
|
||||
self.matchColours()
|
||||
|
||||
@@ -2988,9 +2981,9 @@ class GuiDocEditFooter(QWidget):
|
||||
theme rather than the main GUI.
|
||||
"""
|
||||
thePalette = QPalette()
|
||||
thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
thePalette.setColor(QPalette.Window, QColor(*CONFIG.theme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*CONFIG.theme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
|
||||
|
||||
self.setPalette(thePalette)
|
||||
self.statusText.setPalette(thePalette)
|
||||
@@ -3007,7 +3000,7 @@ class GuiDocEditFooter(QWidget):
|
||||
logger.debug("No handle set, so clearing the editor footer")
|
||||
self._theItem = None
|
||||
else:
|
||||
self._theItem = self.theProject.tree[self._docHandle]
|
||||
self._theItem = self.mainGui.project.tree[self._docHandle]
|
||||
|
||||
self.setHasSelection(False)
|
||||
self.updateInfo()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Syntax Highlighter
|
||||
====================================
|
||||
Class for the main document editor syntax highlighter
|
||||
|
||||
File History:
|
||||
Created: 2019-04-06 [0.0.1]
|
||||
@@ -22,6 +21,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
@@ -54,8 +54,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
self.theDoc = theDoc
|
||||
self.spEnchant = spEnchant
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
self.theHandle = None
|
||||
self.spellCheck = False
|
||||
self.spellRx = None
|
||||
@@ -87,24 +85,24 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
"""
|
||||
logger.debug("Setting up highlighting rules")
|
||||
|
||||
self.colHead = QColor(*self.mainTheme.colHead)
|
||||
self.colHeadH = QColor(*self.mainTheme.colHeadH)
|
||||
self.colDialN = QColor(*self.mainTheme.colDialN)
|
||||
self.colDialD = QColor(*self.mainTheme.colDialD)
|
||||
self.colDialS = QColor(*self.mainTheme.colDialS)
|
||||
self.colHidden = QColor(*self.mainTheme.colHidden)
|
||||
self.colKey = QColor(*self.mainTheme.colKey)
|
||||
self.colVal = QColor(*self.mainTheme.colVal)
|
||||
self.colSpell = QColor(*self.mainTheme.colSpell)
|
||||
self.colError = QColor(*self.mainTheme.colError)
|
||||
self.colRepTag = QColor(*self.mainTheme.colRepTag)
|
||||
self.colMod = QColor(*self.mainTheme.colMod)
|
||||
self.colBreak = QColor(*self.mainTheme.colEmph)
|
||||
self.colHead = QColor(*CONFIG.theme.colHead)
|
||||
self.colHeadH = QColor(*CONFIG.theme.colHeadH)
|
||||
self.colDialN = QColor(*CONFIG.theme.colDialN)
|
||||
self.colDialD = QColor(*CONFIG.theme.colDialD)
|
||||
self.colDialS = QColor(*CONFIG.theme.colDialS)
|
||||
self.colHidden = QColor(*CONFIG.theme.colHidden)
|
||||
self.colKey = QColor(*CONFIG.theme.colKey)
|
||||
self.colVal = QColor(*CONFIG.theme.colVal)
|
||||
self.colSpell = QColor(*CONFIG.theme.colSpell)
|
||||
self.colError = QColor(*CONFIG.theme.colError)
|
||||
self.colRepTag = QColor(*CONFIG.theme.colRepTag)
|
||||
self.colMod = QColor(*CONFIG.theme.colMod)
|
||||
self.colBreak = QColor(*CONFIG.theme.colEmph)
|
||||
self.colBreak.setAlpha(64)
|
||||
|
||||
self.colEmph = None
|
||||
if CONFIG.highlightEmph:
|
||||
self.colEmph = QColor(*self.mainTheme.colEmph)
|
||||
self.colEmph = QColor(*CONFIG.theme.colEmph)
|
||||
|
||||
self.hStyles = {
|
||||
"header1": self._makeFormat(self.colHead, "bold", 1.8),
|
||||
@@ -287,8 +285,8 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
|
||||
if theText.startswith("@"): # Keywords and commands
|
||||
self.setCurrentBlockState(self.BLOCK_META)
|
||||
pIndex = self.theProject.index
|
||||
tItem = self.mainGui.theProject.tree[self.theHandle]
|
||||
pIndex = self.mainGui.project.index
|
||||
tItem = self.mainGui.project.tree[self.theHandle]
|
||||
isValid, theBits, thePos = pIndex.scanThis(theText)
|
||||
isGood = pIndex.checkThese(theBits, tItem)
|
||||
if isValid:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Document Viewer
|
||||
=================================
|
||||
GUI classes for the main document viewer
|
||||
|
||||
File History:
|
||||
Created: 2019-05-10 [0.0.1] GuiDocViewer
|
||||
@@ -26,6 +25,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
@@ -59,9 +59,7 @@ class GuiDocViewer(QTextBrowser):
|
||||
logger.debug("Create: GuiDocViewer")
|
||||
|
||||
# Class Variables
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
# Internal Variables
|
||||
self._docHandle = None
|
||||
@@ -121,14 +119,14 @@ class GuiDocViewer(QTextBrowser):
|
||||
|
||||
# Set the widget colours to match syntax theme
|
||||
mainPalette = self.palette()
|
||||
mainPalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
|
||||
mainPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
|
||||
mainPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
mainPalette.setColor(QPalette.Window, QColor(*CONFIG.theme.colBack))
|
||||
mainPalette.setColor(QPalette.Base, QColor(*CONFIG.theme.colBack))
|
||||
mainPalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
|
||||
self.setPalette(mainPalette)
|
||||
|
||||
docPalette = self.viewport().palette()
|
||||
docPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
|
||||
docPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
docPalette.setColor(QPalette.Base, QColor(*CONFIG.theme.colBack))
|
||||
docPalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
|
||||
self.viewport().setPalette(docPalette)
|
||||
|
||||
self.docHeader.matchColours()
|
||||
@@ -164,7 +162,7 @@ class GuiDocViewer(QTextBrowser):
|
||||
def loadText(self, tHandle, updateHistory=True):
|
||||
"""Load text into the viewer from an item handle.
|
||||
"""
|
||||
if not self.theProject.tree.checkType(tHandle, nwItemType.FILE):
|
||||
if not self.mainGui.project.tree.checkType(tHandle, nwItemType.FILE):
|
||||
logger.warning("Item not found")
|
||||
return False
|
||||
|
||||
@@ -172,7 +170,7 @@ class GuiDocViewer(QTextBrowser):
|
||||
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||
|
||||
sPos = self.verticalScrollBar().value()
|
||||
aDoc = ToHtml(self.theProject)
|
||||
aDoc = ToHtml(self.mainGui.project)
|
||||
aDoc.setPreview(CONFIG.viewComments, CONFIG.viewSynopsis)
|
||||
aDoc.setLinkHeaders(True)
|
||||
|
||||
@@ -212,7 +210,7 @@ class GuiDocViewer(QTextBrowser):
|
||||
self.verticalScrollBar().setValue(sPos)
|
||||
|
||||
self._docHandle = tHandle
|
||||
self.theProject._data.setLastHandle(tHandle, "viewer")
|
||||
self.mainGui.project.data.setLastHandle(tHandle, "viewer")
|
||||
self.docHeader.setTitleFromHandle(self._docHandle)
|
||||
self.updateDocMargins()
|
||||
|
||||
@@ -508,27 +506,27 @@ class GuiDocViewer(QTextBrowser):
|
||||
" text-align: center;"
|
||||
"}}\n"
|
||||
).format(
|
||||
tColR=self.mainTheme.colText[0],
|
||||
tColG=self.mainTheme.colText[1],
|
||||
tColB=self.mainTheme.colText[2],
|
||||
hColR=self.mainTheme.colHead[0],
|
||||
hColG=self.mainTheme.colHead[1],
|
||||
hColB=self.mainTheme.colHead[2],
|
||||
aColR=self.mainTheme.colVal[0],
|
||||
aColG=self.mainTheme.colVal[1],
|
||||
aColB=self.mainTheme.colVal[2],
|
||||
eColR=self.mainTheme.colEmph[0],
|
||||
eColG=self.mainTheme.colEmph[1],
|
||||
eColB=self.mainTheme.colEmph[2],
|
||||
kColR=self.mainTheme.colKey[0],
|
||||
kColG=self.mainTheme.colKey[1],
|
||||
kColB=self.mainTheme.colKey[2],
|
||||
cColR=self.mainTheme.colHidden[0],
|
||||
cColG=self.mainTheme.colHidden[1],
|
||||
cColB=self.mainTheme.colHidden[2],
|
||||
mColR=self.mainTheme.colMod[0],
|
||||
mColG=self.mainTheme.colMod[1],
|
||||
mColB=self.mainTheme.colMod[2],
|
||||
tColR=CONFIG.theme.colText[0],
|
||||
tColG=CONFIG.theme.colText[1],
|
||||
tColB=CONFIG.theme.colText[2],
|
||||
hColR=CONFIG.theme.colHead[0],
|
||||
hColG=CONFIG.theme.colHead[1],
|
||||
hColB=CONFIG.theme.colHead[2],
|
||||
aColR=CONFIG.theme.colVal[0],
|
||||
aColG=CONFIG.theme.colVal[1],
|
||||
aColB=CONFIG.theme.colVal[2],
|
||||
eColR=CONFIG.theme.colEmph[0],
|
||||
eColG=CONFIG.theme.colEmph[1],
|
||||
eColB=CONFIG.theme.colEmph[2],
|
||||
kColR=CONFIG.theme.colKey[0],
|
||||
kColG=CONFIG.theme.colKey[1],
|
||||
kColB=CONFIG.theme.colKey[2],
|
||||
cColR=CONFIG.theme.colHidden[0],
|
||||
cColG=CONFIG.theme.colHidden[1],
|
||||
cColB=CONFIG.theme.colHidden[2],
|
||||
mColR=CONFIG.theme.colMod[0],
|
||||
mColG=CONFIG.theme.colMod[1],
|
||||
mColB=CONFIG.theme.colMod[2],
|
||||
)
|
||||
self.document().setDefaultStyleSheet(styleSheet)
|
||||
|
||||
@@ -681,15 +679,13 @@ class GuiDocViewHeader(QWidget):
|
||||
|
||||
logger.debug("Create: GuiDocViewHeader")
|
||||
|
||||
self.docViewer = docViewer
|
||||
self.mainGui = docViewer.mainGui
|
||||
self.theProject = docViewer.theProject
|
||||
self.mainTheme = docViewer.mainTheme
|
||||
self.docViewer = docViewer
|
||||
self.mainGui = docViewer.mainGui
|
||||
|
||||
# Internal Variables
|
||||
self._docHandle = None
|
||||
|
||||
fPx = int(0.9*self.mainTheme.fontPixelSize)
|
||||
fPx = int(0.9*CONFIG.theme.fontPixelSize)
|
||||
hSp = CONFIG.pxInt(6)
|
||||
|
||||
# Main Widget Settings
|
||||
@@ -706,7 +702,7 @@ class GuiDocViewHeader(QWidget):
|
||||
self.theTitle.setFixedHeight(fPx)
|
||||
|
||||
lblFont = self.theTitle.font()
|
||||
lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
|
||||
lblFont.setPointSizeF(0.9*CONFIG.theme.fontPointSize)
|
||||
self.theTitle.setFont(lblFont)
|
||||
|
||||
# Buttons
|
||||
@@ -777,15 +773,15 @@ class GuiDocViewHeader(QWidget):
|
||||
def updateTheme(self):
|
||||
"""Update theme elements.
|
||||
"""
|
||||
self.backButton.setIcon(self.mainTheme.getIcon("backward"))
|
||||
self.forwardButton.setIcon(self.mainTheme.getIcon("forward"))
|
||||
self.refreshButton.setIcon(self.mainTheme.getIcon("refresh"))
|
||||
self.closeButton.setIcon(self.mainTheme.getIcon("close"))
|
||||
self.backButton.setIcon(CONFIG.theme.getIcon("backward"))
|
||||
self.forwardButton.setIcon(CONFIG.theme.getIcon("forward"))
|
||||
self.refreshButton.setIcon(CONFIG.theme.getIcon("refresh"))
|
||||
self.closeButton.setIcon(CONFIG.theme.getIcon("close"))
|
||||
|
||||
buttonStyle = (
|
||||
"QToolButton {{border: none; background: transparent;}} "
|
||||
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
|
||||
).format(*self.mainTheme.colText)
|
||||
).format(*CONFIG.theme.colText)
|
||||
|
||||
self.backButton.setStyleSheet(buttonStyle)
|
||||
self.forwardButton.setStyleSheet(buttonStyle)
|
||||
@@ -801,9 +797,9 @@ class GuiDocViewHeader(QWidget):
|
||||
theme rather than the main GUI.
|
||||
"""
|
||||
thePalette = QPalette()
|
||||
thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
thePalette.setColor(QPalette.Window, QColor(*CONFIG.theme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*CONFIG.theme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
|
||||
|
||||
self.setPalette(thePalette)
|
||||
self.theTitle.setPalette(thePalette)
|
||||
@@ -823,17 +819,18 @@ class GuiDocViewHeader(QWidget):
|
||||
self.refreshButton.setVisible(False)
|
||||
return True
|
||||
|
||||
pTree = self.mainGui.project.tree
|
||||
if CONFIG.showFullPath:
|
||||
tTitle = []
|
||||
tTree = self.theProject.tree.getItemPath(tHandle)
|
||||
tTree = pTree.getItemPath(tHandle)
|
||||
for aHandle in reversed(tTree):
|
||||
nwItem = self.theProject.tree[aHandle]
|
||||
nwItem = pTree[aHandle]
|
||||
if nwItem is not None:
|
||||
tTitle.append(nwItem.itemName)
|
||||
sSep = " %s " % nwUnicode.U_RSAQUO
|
||||
self.theTitle.setText(sSep.join(tTitle))
|
||||
else:
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
nwItem = pTree[tHandle]
|
||||
if nwItem is None:
|
||||
return False
|
||||
self.theTitle.setText(nwItem.itemName)
|
||||
@@ -900,13 +897,12 @@ class GuiDocViewFooter(QWidget):
|
||||
|
||||
self.docViewer = docViewer
|
||||
self.mainGui = docViewer.mainGui
|
||||
self.mainTheme = docViewer.mainTheme
|
||||
self.viewMeta = docViewer.mainGui.viewMeta
|
||||
|
||||
# Internal Variables
|
||||
self._docHandle = None
|
||||
|
||||
fPx = int(0.9*self.mainTheme.fontPixelSize)
|
||||
fPx = int(0.9*CONFIG.theme.fontPixelSize)
|
||||
bSp = CONFIG.pxInt(2)
|
||||
hSp = CONFIG.pxInt(8)
|
||||
|
||||
@@ -991,7 +987,7 @@ class GuiDocViewFooter(QWidget):
|
||||
self.lblSynopsis.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
||||
|
||||
lblFont = self.font()
|
||||
lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
|
||||
lblFont.setPointSizeF(0.9*CONFIG.theme.fontPointSize)
|
||||
self.lblRefs.setFont(lblFont)
|
||||
self.lblSticky.setFont(lblFont)
|
||||
self.lblComments.setFont(lblFont)
|
||||
@@ -1036,21 +1032,21 @@ class GuiDocViewFooter(QWidget):
|
||||
"""
|
||||
# Icons
|
||||
|
||||
fPx = int(0.9*self.mainTheme.fontPixelSize)
|
||||
fPx = int(0.9*CONFIG.theme.fontPixelSize)
|
||||
|
||||
stickyOn = self.mainTheme.getPixmap("sticky-on", (fPx, fPx))
|
||||
stickyOff = self.mainTheme.getPixmap("sticky-off", (fPx, fPx))
|
||||
stickyOn = CONFIG.theme.getPixmap("sticky-on", (fPx, fPx))
|
||||
stickyOff = CONFIG.theme.getPixmap("sticky-off", (fPx, fPx))
|
||||
stickyIcon = QIcon()
|
||||
stickyIcon.addPixmap(stickyOn, QIcon.Normal, QIcon.On)
|
||||
stickyIcon.addPixmap(stickyOff, QIcon.Normal, QIcon.Off)
|
||||
|
||||
bulletOn = self.mainTheme.getPixmap("bullet-on", (fPx, fPx))
|
||||
bulletOff = self.mainTheme.getPixmap("bullet-off", (fPx, fPx))
|
||||
bulletOn = CONFIG.theme.getPixmap("bullet-on", (fPx, fPx))
|
||||
bulletOff = CONFIG.theme.getPixmap("bullet-off", (fPx, fPx))
|
||||
bulletIcon = QIcon()
|
||||
bulletIcon.addPixmap(bulletOn, QIcon.Normal, QIcon.On)
|
||||
bulletIcon.addPixmap(bulletOff, QIcon.Normal, QIcon.Off)
|
||||
|
||||
self.showHide.setIcon(self.mainTheme.getIcon("reference"))
|
||||
self.showHide.setIcon(CONFIG.theme.getIcon("reference"))
|
||||
self.stickyRefs.setIcon(stickyIcon)
|
||||
self.showComments.setIcon(bulletIcon)
|
||||
self.showSynopsis.setIcon(bulletIcon)
|
||||
@@ -1060,7 +1056,7 @@ class GuiDocViewFooter(QWidget):
|
||||
buttonStyle = (
|
||||
"QToolButton {{border: none; background: transparent;}} "
|
||||
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
|
||||
).format(*self.mainTheme.colText)
|
||||
).format(*CONFIG.theme.colText)
|
||||
|
||||
self.showHide.setStyleSheet(buttonStyle)
|
||||
self.stickyRefs.setStyleSheet(buttonStyle)
|
||||
@@ -1076,9 +1072,9 @@ class GuiDocViewFooter(QWidget):
|
||||
theme rather than the main GUI.
|
||||
"""
|
||||
thePalette = QPalette()
|
||||
thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
|
||||
thePalette.setColor(QPalette.Window, QColor(*CONFIG.theme.colBack))
|
||||
thePalette.setColor(QPalette.WindowText, QColor(*CONFIG.theme.colText))
|
||||
thePalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
|
||||
|
||||
self.setPalette(thePalette)
|
||||
self.lblRefs.setPalette(thePalette)
|
||||
@@ -1141,9 +1137,7 @@ class GuiDocViewDetails(QScrollArea):
|
||||
|
||||
logger.debug("Create: GuiDocViewDetails")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = mainGui
|
||||
|
||||
self.refList = QLabel("")
|
||||
self.refList.setWordWrap(True)
|
||||
@@ -1151,9 +1145,7 @@ class GuiDocViewDetails(QScrollArea):
|
||||
self.refList.setScaledContents(True)
|
||||
self.refList.linkActivated.connect(self._linkClicked)
|
||||
|
||||
self.linkStyle = "style='color: rgb({0},{1},{2})'".format(
|
||||
*self.mainTheme.colLink
|
||||
)
|
||||
self.linkStyle = "style='color: rgb({0},{1},{2})'".format(*CONFIG.theme.colLink)
|
||||
|
||||
# Assemble
|
||||
self.outerWidget = QWidget()
|
||||
@@ -1180,10 +1172,10 @@ class GuiDocViewDetails(QScrollArea):
|
||||
if self.mainGui.docViewer.stickyRef:
|
||||
return
|
||||
|
||||
theRefs = self.theProject.index.getBackReferenceList(tHandle)
|
||||
theRefs = self.mainGui.project.index.getBackReferenceList(tHandle)
|
||||
theList = []
|
||||
for tHandle in theRefs:
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
tItem = self.mainGui.project.tree[tHandle]
|
||||
if tItem is not None:
|
||||
theList.append("<a href='%s#%s' %s>%s</a>" % (
|
||||
tHandle, theRefs[tHandle], self.linkStyle, tItem.itemName
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Item Details Panel
|
||||
====================================
|
||||
GUI class for the project tree item details panel
|
||||
|
||||
File History:
|
||||
Created: 2019-04-24 [0.0.1]
|
||||
@@ -22,6 +21,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
@@ -42,9 +42,7 @@ class GuiItemDetails(QWidget):
|
||||
|
||||
logger.debug("Create: GuiItemDetails")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = mainGui
|
||||
|
||||
# Internal Variables
|
||||
self._itemHandle = None
|
||||
@@ -53,7 +51,7 @@ class GuiItemDetails(QWidget):
|
||||
hSp = CONFIG.pxInt(6)
|
||||
vSp = CONFIG.pxInt(1)
|
||||
mPx = CONFIG.pxInt(6)
|
||||
fPt = self.mainTheme.fontPointSize
|
||||
fPt = CONFIG.theme.fontPointSize
|
||||
|
||||
fntLabel = QFont()
|
||||
fntLabel.setBold(True)
|
||||
@@ -178,8 +176,8 @@ class GuiItemDetails(QWidget):
|
||||
self.updateTheme()
|
||||
|
||||
# Make sure the columns for flags and counts don't resize too often
|
||||
flagWidth = self.mainTheme.getTextWidth("Mm", fntValue)
|
||||
countWidth = self.mainTheme.getTextWidth("99,999", fntValue)
|
||||
flagWidth = CONFIG.theme.getTextWidth("Mm", fntValue)
|
||||
countWidth = CONFIG.theme.getTextWidth("99,999", fntValue)
|
||||
self.mainBox.setColumnMinimumWidth(1, flagWidth)
|
||||
self.mainBox.setColumnMinimumWidth(4, countWidth)
|
||||
|
||||
@@ -235,13 +233,13 @@ class GuiItemDetails(QWidget):
|
||||
self.clearDetails()
|
||||
return
|
||||
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
nwItem = self.mainGui.project.tree[tHandle]
|
||||
if nwItem is None:
|
||||
self.clearDetails()
|
||||
return
|
||||
|
||||
self._itemHandle = tHandle
|
||||
iPx = int(round(0.8*self.mainTheme.baseIconSize))
|
||||
iPx = int(round(0.8*CONFIG.theme.baseIconSize))
|
||||
|
||||
# Label
|
||||
# =====
|
||||
@@ -252,11 +250,11 @@ class GuiItemDetails(QWidget):
|
||||
|
||||
if nwItem.isFileType():
|
||||
if nwItem.isActive:
|
||||
self.labelIcon.setPixmap(self.mainTheme.getPixmap("checked", (iPx, iPx)))
|
||||
self.labelIcon.setPixmap(CONFIG.theme.getPixmap("checked", (iPx, iPx)))
|
||||
else:
|
||||
self.labelIcon.setPixmap(self.mainTheme.getPixmap("unchecked", (iPx, iPx)))
|
||||
self.labelIcon.setPixmap(CONFIG.theme.getPixmap("unchecked", (iPx, iPx)))
|
||||
else:
|
||||
self.labelIcon.setPixmap(self.mainTheme.getPixmap("noncheckable", (iPx, iPx)))
|
||||
self.labelIcon.setPixmap(CONFIG.theme.getPixmap("noncheckable", (iPx, iPx)))
|
||||
|
||||
self.labelData.setText(theLabel)
|
||||
|
||||
@@ -270,14 +268,14 @@ class GuiItemDetails(QWidget):
|
||||
# Class
|
||||
# =====
|
||||
|
||||
classIcon = self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass])
|
||||
classIcon = CONFIG.theme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass])
|
||||
self.classIcon.setPixmap(classIcon.pixmap(iPx, iPx))
|
||||
self.classData.setText(trConst(nwLabels.CLASS_NAME[nwItem.itemClass]))
|
||||
|
||||
# Layout
|
||||
# ======
|
||||
|
||||
usageIcon = self.mainTheme.getItemIcon(
|
||||
usageIcon = CONFIG.theme.getItemIcon(
|
||||
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, nwItem.mainHeading
|
||||
)
|
||||
self.usageIcon.setPixmap(usageIcon.pixmap(iPx, iPx))
|
||||
|
||||
+14
-15
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Main Menu
|
||||
===========================
|
||||
GUI class for the main window menu
|
||||
|
||||
File History:
|
||||
Created: 2019-04-27 [0.0.1]
|
||||
@@ -22,6 +21,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
@@ -51,8 +51,7 @@ class GuiMainMenu(QMenuBar):
|
||||
|
||||
logger.debug("Create: GuiMainMenu")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
# Build Menu
|
||||
self._buildProjectMenu()
|
||||
@@ -380,10 +379,10 @@ class GuiMainMenu(QMenuBar):
|
||||
"""Assemble the Insert menu.
|
||||
"""
|
||||
# Insert
|
||||
self.insertMenu = self.addMenu(self.tr("&Insert"))
|
||||
self.insMenu = self.addMenu(self.tr("&Insert"))
|
||||
|
||||
# Insert > Dashes and Dots
|
||||
self.mInsDashes = self.insertMenu.addMenu(self.tr("Dashes"))
|
||||
self.mInsDashes = self.insMenu.addMenu(self.tr("Dashes"))
|
||||
|
||||
# Insert > Short Dash
|
||||
self.aInsENDash = QAction(self.tr("Short Dash"), self)
|
||||
@@ -410,7 +409,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.mInsDashes.addAction(self.aInsFigDash)
|
||||
|
||||
# Insert > Quote Marks
|
||||
self.mInsQuotes = self.insertMenu.addMenu(self.tr("Quote Marks"))
|
||||
self.mInsQuotes = self.insMenu.addMenu(self.tr("Quote Marks"))
|
||||
|
||||
# Insert > Left Single Quote
|
||||
self.aInsQuoteLS = QAction(self.tr("Left Single Quote"), self)
|
||||
@@ -443,7 +442,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.mInsQuotes.addAction(self.aInsMSApos)
|
||||
|
||||
# Insert > Symbols
|
||||
self.mInsPunct = self.insertMenu.addMenu(self.tr("General Punctuation"))
|
||||
self.mInsPunct = self.insMenu.addMenu(self.tr("General Punctuation"))
|
||||
|
||||
# Insert > Ellipsis
|
||||
self.aInsEllipsis = QAction(self.tr("Ellipsis"), self)
|
||||
@@ -464,7 +463,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.mInsPunct.addAction(self.aInsDPrime)
|
||||
|
||||
# Insert > White Spaces
|
||||
self.mInsSpace = self.insertMenu.addMenu(self.tr("White Spaces"))
|
||||
self.mInsSpace = self.insMenu.addMenu(self.tr("White Spaces"))
|
||||
|
||||
# Insert > Non-Breaking Space
|
||||
self.aInsNBSpace = QAction(self.tr("Non-Breaking Space"), self)
|
||||
@@ -485,7 +484,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.mInsSpace.addAction(self.aInsThinNBSpace)
|
||||
|
||||
# Insert > Symbols
|
||||
self.mInsSymbol = self.insertMenu.addMenu(self.tr("Other Symbols"))
|
||||
self.mInsSymbol = self.insMenu.addMenu(self.tr("Other Symbols"))
|
||||
|
||||
# Insert > List Bullet
|
||||
self.aInsBullet = QAction(self.tr("List Bullet"), self)
|
||||
@@ -536,7 +535,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.mInsSymbol.addAction(self.aInsDivide)
|
||||
|
||||
# Insert > Tags and References
|
||||
self.mInsKeywords = self.insertMenu.addMenu(self.tr("Tags and References"))
|
||||
self.mInsKeywords = self.insMenu.addMenu(self.tr("Tags and References"))
|
||||
self.mInsKWItems = {}
|
||||
self.mInsKWItems[nwKeyWords.TAG_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, G")
|
||||
self.mInsKWItems[nwKeyWords.POV_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, V")
|
||||
@@ -557,7 +556,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.mInsKeywords.addAction(self.mInsKWItems[keyWord][0])
|
||||
|
||||
# Insert > Special Comments
|
||||
self.mInsComments = self.insertMenu.addMenu(self.tr("Special Comments"))
|
||||
self.mInsComments = self.insMenu.addMenu(self.tr("Special Comments"))
|
||||
|
||||
# Insert > Synopsis Comment
|
||||
self.aInsSynopsis = QAction(self.tr("Synopsis Comment"), self)
|
||||
@@ -566,7 +565,7 @@ class GuiMainMenu(QMenuBar):
|
||||
self.mInsComments.addAction(self.aInsSynopsis)
|
||||
|
||||
# Insert > Symbols
|
||||
self.mInsBreaks = self.insertMenu.addMenu(self.tr("Page Break and Space"))
|
||||
self.mInsBreaks = self.insMenu.addMenu(self.tr("Page Break and Space"))
|
||||
|
||||
# Insert > New Page
|
||||
self.aInsNewPage = QAction(self.tr("Page Break"), self)
|
||||
@@ -586,7 +585,7 @@ class GuiMainMenu(QMenuBar):
|
||||
# Insert > Placeholder Text
|
||||
self.aLipsumText = QAction(self.tr("Placeholder Text"), self)
|
||||
self.aLipsumText.triggered.connect(lambda: self.mainGui.showLoremIpsumDialog())
|
||||
self.insertMenu.addAction(self.aLipsumText)
|
||||
self.insMenu.addAction(self.aLipsumText)
|
||||
|
||||
return
|
||||
|
||||
@@ -796,7 +795,7 @@ class GuiMainMenu(QMenuBar):
|
||||
# Tools > Check Spelling
|
||||
self.aSpellCheck = QAction(self.tr("Check Spelling"), self)
|
||||
self.aSpellCheck.setCheckable(True)
|
||||
self.aSpellCheck.setChecked(self.theProject.data.spellCheck)
|
||||
self.aSpellCheck.setChecked(self.mainGui.project.data.spellCheck)
|
||||
self.aSpellCheck.triggered.connect(self._toggleSpellCheck) # triggered, not toggled!
|
||||
self.aSpellCheck.setShortcut("Ctrl+F7")
|
||||
self.toolsMenu.addAction(self.aSpellCheck)
|
||||
@@ -826,7 +825,7 @@ class GuiMainMenu(QMenuBar):
|
||||
|
||||
# Tools > Backup Project
|
||||
self.aBackupProject = QAction(self.tr("Backup Project"), self)
|
||||
self.aBackupProject.triggered.connect(lambda: self.theProject.backupProject(True))
|
||||
self.aBackupProject.triggered.connect(lambda: self.mainGui.project.backupProject(True))
|
||||
self.toolsMenu.addAction(self.aBackupProject)
|
||||
|
||||
# Tools > Build Manuscript
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Novel Tree
|
||||
============================
|
||||
GUI class for the main window novel tree
|
||||
|
||||
File History:
|
||||
Created: 2020-12-20 [1.1rc1] GuiNovelTree
|
||||
@@ -24,6 +23,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
@@ -42,7 +42,7 @@ from novelwriter import CONFIG
|
||||
from novelwriter.enum import nwDocMode, nwItemClass, nwOutline
|
||||
from novelwriter.common import minmax
|
||||
from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst
|
||||
from novelwriter.gui.components import NovelSelector
|
||||
from novelwriter.extensions.novelselector import NovelSelector
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -66,8 +66,7 @@ class GuiNovelView(QWidget):
|
||||
def __init__(self, mainGui):
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
# Build GUI
|
||||
self.novelTree = GuiNovelTree(self)
|
||||
@@ -118,16 +117,16 @@ class GuiNovelView(QWidget):
|
||||
def openProjectTasks(self):
|
||||
"""Run open project tasks.
|
||||
"""
|
||||
lastNovel = self.theProject.data.getLastHandle("novelTree")
|
||||
if lastNovel not in self.theProject.tree:
|
||||
lastNovel = self.theProject.tree.findRoot(nwItemClass.NOVEL)
|
||||
lastNovel = self.mainGui.project.data.getLastHandle("novelTree")
|
||||
if lastNovel not in self.mainGui.project.tree:
|
||||
lastNovel = self.mainGui.project.tree.findRoot(nwItemClass.NOVEL)
|
||||
|
||||
logger.debug("Setting novel tree to root item '%s'", lastNovel)
|
||||
|
||||
lastCol = self.theProject.options.getEnum(
|
||||
lastCol = self.mainGui.project.options.getEnum(
|
||||
"GuiNovelView", "lastCol", NovelTreeColumn, NovelTreeColumn.HIDDEN
|
||||
)
|
||||
lastColSize = self.theProject.options.getInt(
|
||||
lastColSize = self.mainGui.project.options.getInt(
|
||||
"GuiNovelView", "lastColSize", 25
|
||||
)
|
||||
|
||||
@@ -147,8 +146,9 @@ class GuiNovelView(QWidget):
|
||||
"""
|
||||
lastColType = self.novelTree.lastColType
|
||||
lastColSize = self.novelTree.lastColSize
|
||||
self.theProject.options.setValue("GuiNovelView", "lastCol", lastColType)
|
||||
self.theProject.options.setValue("GuiNovelView", "lastColSize", lastColSize)
|
||||
pOptions = self.mainGui.project.options
|
||||
pOptions.setValue("GuiNovelView", "lastCol", lastColType)
|
||||
pOptions.setValue("GuiNovelView", "lastColSize", lastColSize)
|
||||
return
|
||||
|
||||
def setTreeFocus(self):
|
||||
@@ -170,7 +170,7 @@ class GuiNovelView(QWidget):
|
||||
def refreshTree(self):
|
||||
"""Refresh the current tree.
|
||||
"""
|
||||
self.novelTree.refreshTree(rootHandle=self.theProject.data.getLastHandle("novelTree"))
|
||||
self.novelTree.refreshTree(rootHandle=self.mainGui.project.data.getLastHandle("novelTree"))
|
||||
return
|
||||
|
||||
@pyqtSlot(str)
|
||||
@@ -198,12 +198,10 @@ class GuiNovelToolBar(QWidget):
|
||||
|
||||
logger.debug("Create: GuiNovelToolBar")
|
||||
|
||||
self.novelView = novelView
|
||||
self.mainGui = novelView.mainGui
|
||||
self.theProject = novelView.mainGui.theProject
|
||||
self.mainTheme = novelView.mainGui.mainTheme
|
||||
self.novelView = novelView
|
||||
self.mainGui = novelView.mainGui
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
mPx = CONFIG.pxInt(2)
|
||||
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
@@ -213,7 +211,7 @@ class GuiNovelToolBar(QWidget):
|
||||
selFont = self.font()
|
||||
selFont.setWeight(QFont.Bold)
|
||||
self.novelPrefix = self.tr("Outline of {0}")
|
||||
self.novelValue = NovelSelector(self, self.theProject, self.mainGui)
|
||||
self.novelValue = NovelSelector(self, self.mainGui)
|
||||
self.novelValue.setFont(selFont)
|
||||
self.novelValue.setMinimumWidth(CONFIG.pxInt(150))
|
||||
self.novelValue.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
@@ -276,9 +274,9 @@ class GuiNovelToolBar(QWidget):
|
||||
"""Update theme elements.
|
||||
"""
|
||||
# Icons
|
||||
self.tbNovel.setIcon(self.mainTheme.getIcon("cls_novel"))
|
||||
self.tbRefresh.setIcon(self.mainTheme.getIcon("refresh"))
|
||||
self.tbMore.setIcon(self.mainTheme.getIcon("menu"))
|
||||
self.tbNovel.setIcon(CONFIG.theme.getIcon("cls_novel"))
|
||||
self.tbRefresh.setIcon(CONFIG.theme.getIcon("refresh"))
|
||||
self.tbMore.setIcon(CONFIG.theme.getIcon("menu"))
|
||||
|
||||
qPalette = self.palette()
|
||||
qPalette.setBrush(QPalette.Window, qPalette.base())
|
||||
@@ -347,7 +345,7 @@ class GuiNovelToolBar(QWidget):
|
||||
def _refreshNovelTree(self):
|
||||
"""Rebuild the current tree.
|
||||
"""
|
||||
rootHandle = self.theProject.data.getLastHandle("novelTree")
|
||||
rootHandle = self.mainGui.project.data.getLastHandle("novelTree")
|
||||
self.novelView.novelTree.refreshTree(rootHandle=rootHandle, overRide=True)
|
||||
return
|
||||
|
||||
@@ -399,10 +397,8 @@ class GuiNovelTree(QTreeWidget):
|
||||
|
||||
logger.debug("Create: GuiNovelTree")
|
||||
|
||||
self.novelView = novelView
|
||||
self.mainGui = novelView.mainGui
|
||||
self.mainTheme = novelView.mainGui.mainTheme
|
||||
self.theProject = novelView.mainGui.theProject
|
||||
self.novelView = novelView
|
||||
self.mainGui = novelView.mainGui
|
||||
|
||||
# Internal Variables
|
||||
self._treeMap = {}
|
||||
@@ -419,7 +415,7 @@ class GuiNovelTree(QTreeWidget):
|
||||
# Build GUI
|
||||
# =========
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
cMg = CONFIG.pxInt(6)
|
||||
|
||||
self.setIconSize(QSize(iPx, iPx))
|
||||
@@ -485,8 +481,8 @@ class GuiNovelTree(QTreeWidget):
|
||||
def updateTheme(self):
|
||||
"""Update theme elements.
|
||||
"""
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
self._pMore = self.mainTheme.loadDecoration("deco_doc_more", pxH=iPx)
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
self._pMore = CONFIG.theme.loadDecoration("deco_doc_more", pxH=iPx)
|
||||
return
|
||||
|
||||
##
|
||||
@@ -518,10 +514,10 @@ class GuiNovelTree(QTreeWidget):
|
||||
"""
|
||||
logger.debug("Requesting refresh of the novel tree")
|
||||
if rootHandle is None:
|
||||
rootHandle = self.theProject.tree.findRoot(nwItemClass.NOVEL)
|
||||
rootHandle = self.mainGui.project.tree.findRoot(nwItemClass.NOVEL)
|
||||
|
||||
treeChanged = self.mainGui.projView.changedSince(self._lastBuild)
|
||||
indexChanged = self.theProject.index.rootChangedSince(rootHandle, self._lastBuild)
|
||||
indexChanged = self.mainGui.project.index.rootChangedSince(rootHandle, self._lastBuild)
|
||||
if not (treeChanged or indexChanged or overRide):
|
||||
logger.debug("No changes have been made to the novel index")
|
||||
return
|
||||
@@ -532,7 +528,7 @@ class GuiNovelTree(QTreeWidget):
|
||||
titleKey = selItem[0].data(self.C_DATA, self.D_KEY)
|
||||
|
||||
self._populateTree(rootHandle)
|
||||
self.theProject.data.setLastHandle(rootHandle, "novelTree")
|
||||
self.mainGui.project.data.setLastHandle(rootHandle, "novelTree")
|
||||
|
||||
if titleKey is not None and titleKey in self._treeMap:
|
||||
self._treeMap[titleKey].setSelected(True)
|
||||
@@ -542,7 +538,7 @@ class GuiNovelTree(QTreeWidget):
|
||||
def refreshHandle(self, tHandle):
|
||||
"""Refresh the data for a given handle.
|
||||
"""
|
||||
idxData = self.theProject.index.getItemData(tHandle)
|
||||
idxData = self.mainGui.project.index.getItemData(tHandle)
|
||||
if idxData is None:
|
||||
return
|
||||
|
||||
@@ -579,7 +575,7 @@ class GuiNovelTree(QTreeWidget):
|
||||
self._lastCol = colType
|
||||
self.setColumnHidden(self.C_EXTRA, colType == NovelTreeColumn.HIDDEN)
|
||||
if doRefresh:
|
||||
lastNovel = self.theProject.data.getLastHandle("novelTree")
|
||||
lastNovel = self.mainGui.project.data.getLastHandle("novelTree")
|
||||
self.refreshTree(rootHandle=lastNovel, overRide=True)
|
||||
return
|
||||
|
||||
@@ -711,7 +707,7 @@ class GuiNovelTree(QTreeWidget):
|
||||
tStart = time()
|
||||
logger.debug("Building novel tree for root item '%s'", rootHandle)
|
||||
|
||||
novStruct = self.theProject.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
|
||||
novStruct = self.mainGui.project.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
|
||||
for tKey, tHandle, sTitle, novIdx in novStruct:
|
||||
if novIdx.level == "H0":
|
||||
continue
|
||||
@@ -737,7 +733,7 @@ class GuiNovelTree(QTreeWidget):
|
||||
"""Set the tree item values from the index entry.
|
||||
"""
|
||||
iLevel = nwHeaders.H_LEVEL.get(idxItem.level, 0)
|
||||
hDec = self.mainTheme.getHeaderDecoration(iLevel)
|
||||
hDec = CONFIG.theme.getHeaderDecoration(iLevel)
|
||||
|
||||
trItem.setData(self.C_TITLE, Qt.DecorationRole, hDec)
|
||||
trItem.setText(self.C_TITLE, idxItem.title)
|
||||
@@ -763,7 +759,7 @@ class GuiNovelTree(QTreeWidget):
|
||||
|
||||
refData = []
|
||||
refName = ""
|
||||
theRefs = self.theProject.index.getReferences(tHandle, sTitle)
|
||||
theRefs = self.mainGui.project.index.getReferences(tHandle, sTitle)
|
||||
if self._lastCol == NovelTreeColumn.POV:
|
||||
refData = theRefs[nwKeyWords.POV_KEY]
|
||||
refName = self._povLabel
|
||||
@@ -787,7 +783,7 @@ class GuiNovelTree(QTreeWidget):
|
||||
"""
|
||||
logger.debug("Generating meta data tooltip for '%s:%s'", tHandle, sTitle)
|
||||
|
||||
pIndex = self.theProject.index
|
||||
pIndex = self.mainGui.project.index
|
||||
novIdx = pIndex.getItemHeader(tHandle, sTitle)
|
||||
refTags = pIndex.getReferences(tHandle, sTitle)
|
||||
|
||||
|
||||
+31
-38
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Project Outline
|
||||
=================================
|
||||
GUI class for the project outline view
|
||||
|
||||
File History:
|
||||
Created: 2022-05-15 [2.0rc1] GuiOutlineView
|
||||
@@ -26,6 +25,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
@@ -48,7 +48,7 @@ from novelwriter.enum import (
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.common import checkInt
|
||||
from novelwriter.constants import nwHeaders, trConst, nwKeyWords, nwLabels
|
||||
from novelwriter.gui.components import NovelSelector
|
||||
from novelwriter.extensions.novelselector import NovelSelector
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -62,8 +62,7 @@ class GuiOutlineView(QWidget):
|
||||
def __init__(self, mainGui):
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
# Build GUI
|
||||
self.outlineTree = GuiOutlineTree(self)
|
||||
@@ -118,7 +117,7 @@ class GuiOutlineView(QWidget):
|
||||
def refreshTree(self):
|
||||
"""Refresh the current tree.
|
||||
"""
|
||||
self.outlineTree.refreshTree(rootHandle=self.theProject.data.getLastHandle("outline"))
|
||||
self.outlineTree.refreshTree(rootHandle=self.mainGui.project.data.getLastHandle("outline"))
|
||||
return
|
||||
|
||||
def clearProject(self):
|
||||
@@ -131,9 +130,9 @@ class GuiOutlineView(QWidget):
|
||||
def openProjectTasks(self):
|
||||
"""Run open project tasks.
|
||||
"""
|
||||
lastOutline = self.theProject.data.getLastHandle("outline")
|
||||
if not (lastOutline in self.theProject.tree or lastOutline is None):
|
||||
lastOutline = self.theProject.tree.findRoot(nwItemClass.NOVEL)
|
||||
lastOutline = self.mainGui.project.data.getLastHandle("outline")
|
||||
if not (lastOutline in self.mainGui.project.tree or lastOutline is None):
|
||||
lastOutline = self.mainGui.project.tree.findRoot(nwItemClass.NOVEL)
|
||||
|
||||
logger.debug("Setting outline tree to root item '%s'", lastOutline)
|
||||
|
||||
@@ -215,9 +214,7 @@ class GuiOutlineToolBar(QToolBar):
|
||||
|
||||
logger.debug("Create: GuiOutlineToolBar")
|
||||
|
||||
self.mainGui = theOutline.mainGui
|
||||
self.theProject = theOutline.mainGui.theProject
|
||||
self.mainTheme = theOutline.mainGui.mainTheme
|
||||
self.mainGui = theOutline.mainGui
|
||||
|
||||
iPx = CONFIG.pxInt(22)
|
||||
mPx = CONFIG.pxInt(12)
|
||||
@@ -233,7 +230,7 @@ class GuiOutlineToolBar(QToolBar):
|
||||
self.novelLabel = QLabel(self.tr("Outline of"))
|
||||
self.novelLabel.setContentsMargins(0, 0, mPx, 0)
|
||||
|
||||
self.novelValue = NovelSelector(self, self.theProject, self.mainGui)
|
||||
self.novelValue = NovelSelector(self, self.mainGui)
|
||||
self.novelValue.setMinimumWidth(CONFIG.pxInt(200))
|
||||
self.novelValue.novelSelectionChanged.connect(self._novelValueChanged)
|
||||
|
||||
@@ -275,8 +272,8 @@ class GuiOutlineToolBar(QToolBar):
|
||||
self.setStyleSheet("QToolBar {border: 0px;}")
|
||||
|
||||
self.novelValue.updateList(includeAll=True)
|
||||
self.aRefresh.setIcon(self.mainTheme.getIcon("refresh"))
|
||||
self.tbColumns.setIcon(self.mainTheme.getIcon("menu"))
|
||||
self.aRefresh.setIcon(CONFIG.theme.getIcon("refresh"))
|
||||
self.tbColumns.setIcon(CONFIG.theme.getIcon("menu"))
|
||||
|
||||
return
|
||||
|
||||
@@ -374,8 +371,6 @@ class GuiOutlineTree(QTreeWidget):
|
||||
|
||||
self.outlineView = outlineView
|
||||
self.mainGui = outlineView.mainGui
|
||||
self.theProject = outlineView.mainGui.theProject
|
||||
self.mainTheme = outlineView.mainGui.mainTheme
|
||||
|
||||
self.setUniformRowHeights(True)
|
||||
self.setFrameStyle(QFrame.NoFrame)
|
||||
@@ -386,7 +381,7 @@ class GuiOutlineTree(QTreeWidget):
|
||||
self.itemDoubleClicked.connect(self._treeDoubleClick)
|
||||
self.itemSelectionChanged.connect(self._itemSelected)
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
self.setIconSize(QSize(iPx, iPx))
|
||||
self.setIndentation(0)
|
||||
|
||||
@@ -403,11 +398,11 @@ class GuiOutlineTree(QTreeWidget):
|
||||
|
||||
self._hFonts = [self.font(), fH1, fH2, self.font(), self.font()]
|
||||
self._dIcon = {
|
||||
"H0": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H0"),
|
||||
"H1": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H1"),
|
||||
"H2": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H2"),
|
||||
"H3": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H3"),
|
||||
"H4": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H4"),
|
||||
"H0": CONFIG.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H0"),
|
||||
"H1": CONFIG.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H1"),
|
||||
"H2": CONFIG.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H2"),
|
||||
"H3": CONFIG.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H3"),
|
||||
"H4": CONFIG.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H4"),
|
||||
}
|
||||
|
||||
# Internals
|
||||
@@ -493,13 +488,13 @@ class GuiOutlineTree(QTreeWidget):
|
||||
|
||||
# If the novel index or novel tree has changed since the tree
|
||||
# was last built, we rebuild the tree from the updated index.
|
||||
indexChanged = self.theProject.index.rootChangedSince(rootHandle, self._lastBuild)
|
||||
indexChanged = self.mainGui.project.index.rootChangedSince(rootHandle, self._lastBuild)
|
||||
if not (novelChanged or indexChanged or overRide):
|
||||
logger.debug("No changes have been made to the novel index")
|
||||
return
|
||||
|
||||
self._populateTree(rootHandle)
|
||||
self.theProject.data.setLastHandle(rootHandle or None, "outline")
|
||||
self.mainGui.project.data.setLastHandle(rootHandle or None, "outline")
|
||||
|
||||
return
|
||||
|
||||
@@ -579,7 +574,7 @@ class GuiOutlineTree(QTreeWidget):
|
||||
"""
|
||||
# Load whatever we saved last time, regardless of wether it
|
||||
# contains the correct names or number of columns.
|
||||
colState = self.theProject.options.getValue("GuiOutline", "columnState", {})
|
||||
colState = self.mainGui.project.options.getValue("GuiOutline", "columnState", {})
|
||||
|
||||
tmpOrder = []
|
||||
tmpHidden = {}
|
||||
@@ -630,7 +625,7 @@ class GuiOutlineTree(QTreeWidget):
|
||||
logHidden, orgWidth if logHidden and logWidth == 0 else logWidth
|
||||
]
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
pOptions.setValue("GuiOutline", "columnState", colState)
|
||||
pOptions.saveSettings()
|
||||
|
||||
@@ -666,7 +661,7 @@ class GuiOutlineTree(QTreeWidget):
|
||||
headItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], Qt.AlignRight)
|
||||
headItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], Qt.AlignRight)
|
||||
|
||||
novStruct = self.theProject.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
|
||||
novStruct = self.mainGui.project.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
|
||||
for _, tHandle, sTitle, novIdx in novStruct:
|
||||
|
||||
iLevel = nwHeaders.H_LEVEL.get(novIdx.level, 0)
|
||||
@@ -674,8 +669,8 @@ class GuiOutlineTree(QTreeWidget):
|
||||
continue
|
||||
|
||||
trItem = QTreeWidgetItem()
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
hDec = self.mainTheme.getHeaderDecoration(iLevel)
|
||||
nwItem = self.mainGui.project.tree[tHandle]
|
||||
hDec = CONFIG.theme.getHeaderDecoration(iLevel)
|
||||
|
||||
trItem.setData(self._colIdx[nwOutline.TITLE], Qt.DecorationRole, hDec)
|
||||
trItem.setText(self._colIdx[nwOutline.TITLE], novIdx.title)
|
||||
@@ -694,7 +689,7 @@ class GuiOutlineTree(QTreeWidget):
|
||||
trItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], Qt.AlignRight)
|
||||
trItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], Qt.AlignRight)
|
||||
|
||||
refs = self.theProject.index.getReferences(tHandle, sTitle)
|
||||
refs = self.mainGui.project.index.getReferences(tHandle, sTitle)
|
||||
trItem.setText(self._colIdx[nwOutline.POV], ", ".join(refs[nwKeyWords.POV_KEY]))
|
||||
trItem.setText(self._colIdx[nwOutline.FOCUS], ", ".join(refs[nwKeyWords.FOCUS_KEY]))
|
||||
trItem.setText(self._colIdx[nwOutline.CHAR], ", ".join(refs[nwKeyWords.CHAR_KEY]))
|
||||
@@ -776,13 +771,11 @@ class GuiOutlineDetails(QScrollArea):
|
||||
|
||||
self.theOutline = theOutline
|
||||
self.mainGui = theOutline.mainGui
|
||||
self.theProject = theOutline.mainGui.theProject
|
||||
self.mainTheme = theOutline.mainGui.mainTheme
|
||||
|
||||
# Sizes
|
||||
minTitle = 30*self.mainTheme.textNWidth
|
||||
maxTitle = 40*self.mainTheme.textNWidth
|
||||
wCount = self.mainTheme.getTextWidth("999,999")
|
||||
minTitle = 30*CONFIG.theme.textNWidth
|
||||
maxTitle = 40*CONFIG.theme.textNWidth
|
||||
wCount = CONFIG.theme.getTextWidth("999,999")
|
||||
hSpace = int(CONFIG.pxInt(10))
|
||||
vSpace = int(CONFIG.pxInt(4))
|
||||
|
||||
@@ -1012,8 +1005,8 @@ class GuiOutlineDetails(QScrollArea):
|
||||
"""Update the content of the tree with the given handle and line
|
||||
number pointing to a header.
|
||||
"""
|
||||
pIndex = self.theProject.index
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
pIndex = self.mainGui.project.index
|
||||
nwItem = self.mainGui.project.tree[tHandle]
|
||||
novIdx = pIndex.getItemHeader(tHandle, sTitle)
|
||||
theRefs = pIndex.getReferences(tHandle, sTitle)
|
||||
if nwItem is None or novIdx is None:
|
||||
@@ -1056,7 +1049,7 @@ class GuiOutlineDetails(QScrollArea):
|
||||
def updateClasses(self):
|
||||
"""Update the visibility status of class details.
|
||||
"""
|
||||
usedClasses = self.theProject.tree.rootClasses()
|
||||
usedClasses = self.mainGui.project.tree.rootClasses()
|
||||
|
||||
pltVisible = nwItemClass.PLOT in usedClasses
|
||||
timVisible = nwItemClass.TIMELINE in usedClasses
|
||||
|
||||
+76
-81
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Project Tree
|
||||
==============================
|
||||
GUI classes for the main window project tree
|
||||
|
||||
File History:
|
||||
Created: 2018-09-29 [0.0.1] GuiProjectTree
|
||||
@@ -233,13 +232,11 @@ class GuiProjectToolBar(QWidget):
|
||||
|
||||
logger.debug("Create: GuiProjectToolBar")
|
||||
|
||||
self.projView = projView
|
||||
self.projTree = projView.projTree
|
||||
self.mainGui = projView.mainGui
|
||||
self.theProject = projView.mainGui.theProject
|
||||
self.mainTheme = projView.mainGui.mainTheme
|
||||
self.projView = projView
|
||||
self.projTree = projView.projTree
|
||||
self.mainGui = projView.mainGui
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
mPx = CONFIG.pxInt(2)
|
||||
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
@@ -370,16 +367,16 @@ class GuiProjectToolBar(QWidget):
|
||||
self.tbAdd.setStyleSheet(buttonStyle)
|
||||
self.tbMore.setStyleSheet(buttonStyle)
|
||||
|
||||
self.tbQuick.setIcon(self.mainTheme.getIcon("bookmark"))
|
||||
self.tbMoveU.setIcon(self.mainTheme.getIcon("up"))
|
||||
self.tbMoveD.setIcon(self.mainTheme.getIcon("down"))
|
||||
self.aAddEmpty.setIcon(self.mainTheme.getIcon("proj_document"))
|
||||
self.aAddChap.setIcon(self.mainTheme.getIcon("proj_chapter"))
|
||||
self.aAddScene.setIcon(self.mainTheme.getIcon("proj_scene"))
|
||||
self.aAddNote.setIcon(self.mainTheme.getIcon("proj_note"))
|
||||
self.aAddFolder.setIcon(self.mainTheme.getIcon("proj_folder"))
|
||||
self.tbAdd.setIcon(self.mainTheme.getIcon("add"))
|
||||
self.tbMore.setIcon(self.mainTheme.getIcon("menu"))
|
||||
self.tbQuick.setIcon(CONFIG.theme.getIcon("bookmark"))
|
||||
self.tbMoveU.setIcon(CONFIG.theme.getIcon("up"))
|
||||
self.tbMoveD.setIcon(CONFIG.theme.getIcon("down"))
|
||||
self.aAddEmpty.setIcon(CONFIG.theme.getIcon("proj_document"))
|
||||
self.aAddChap.setIcon(CONFIG.theme.getIcon("proj_chapter"))
|
||||
self.aAddScene.setIcon(CONFIG.theme.getIcon("proj_scene"))
|
||||
self.aAddNote.setIcon(CONFIG.theme.getIcon("proj_note"))
|
||||
self.aAddFolder.setIcon(CONFIG.theme.getIcon("proj_folder"))
|
||||
self.tbAdd.setIcon(CONFIG.theme.getIcon("add"))
|
||||
self.tbMore.setIcon(CONFIG.theme.getIcon("menu"))
|
||||
|
||||
self.buildQuickLinkMenu()
|
||||
self._buildRootMenu()
|
||||
@@ -395,10 +392,10 @@ class GuiProjectToolBar(QWidget):
|
||||
"""Build the quick link menu."""
|
||||
logger.debug("Rebuilding quick links menu")
|
||||
self.mQuick.clear()
|
||||
for n, (tHandle, nwItem) in enumerate(self.theProject.tree.iterRoots(None)):
|
||||
for n, (tHandle, nwItem) in enumerate(self.mainGui.project.tree.iterRoots(None)):
|
||||
aRoot = self.mQuick.addAction(nwItem.itemName)
|
||||
aRoot.setData(tHandle)
|
||||
aRoot.setIcon(self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass]))
|
||||
aRoot.setIcon(CONFIG.theme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass]))
|
||||
aRoot.triggered.connect(
|
||||
lambda n, tHandle=tHandle: self.projView.setSelectedHandle(tHandle, doScroll=True)
|
||||
)
|
||||
@@ -412,7 +409,7 @@ class GuiProjectToolBar(QWidget):
|
||||
"""Build the rood folder menu."""
|
||||
def addClass(itemClass):
|
||||
aNew = self.mAddRoot.addAction(trConst(nwLabels.CLASS_NAME[itemClass]))
|
||||
aNew.setIcon(self.mainTheme.getIcon(nwLabels.CLASS_ICON[itemClass]))
|
||||
aNew.setIcon(CONFIG.theme.getIcon(nwLabels.CLASS_ICON[itemClass]))
|
||||
aNew.triggered.connect(lambda: self.projTree.newTreeItem(nwItemType.ROOT, itemClass))
|
||||
self.mAddRoot.addAction(aNew)
|
||||
return
|
||||
@@ -441,7 +438,7 @@ class GuiProjectToolBar(QWidget):
|
||||
documents. They should only be visible if novel documents can
|
||||
actually be added.
|
||||
"""
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
nwItem = self.mainGui.project.tree[tHandle]
|
||||
allowDoc = isinstance(nwItem, NWItem) and nwItem.documentAllowed()
|
||||
self.aAddEmpty.setVisible(allowDoc)
|
||||
self.aAddChap.setVisible(allowDoc)
|
||||
@@ -467,10 +464,8 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
logger.debug("Create: GuiProjectTree")
|
||||
|
||||
self.projView = projView
|
||||
self.mainGui = projView.mainGui
|
||||
self.mainTheme = projView.mainGui.mainTheme
|
||||
self.theProject = projView.mainGui.theProject
|
||||
self.projView = projView
|
||||
self.mainGui = projView.mainGui
|
||||
|
||||
# Internal Variables
|
||||
self._treeMap = {}
|
||||
@@ -485,7 +480,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
self.customContextMenuRequested.connect(self._openContextMenu)
|
||||
|
||||
# Tree Settings
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
cMg = CONFIG.pxInt(6)
|
||||
|
||||
self.setIconSize(QSize(iPx, iPx))
|
||||
@@ -577,15 +572,15 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
if itemType == nwItemType.ROOT and isinstance(itemClass, nwItemClass):
|
||||
|
||||
tHandle = self.theProject.newRoot(itemClass)
|
||||
tHandle = self.mainGui.project.newRoot(itemClass)
|
||||
sHandle = self.getSelectedHandle()
|
||||
pItem = self.theProject.tree[sHandle] if sHandle else None
|
||||
pItem = self.mainGui.project.tree[sHandle] if sHandle else None
|
||||
nHandle = pItem.itemRoot if pItem else None
|
||||
|
||||
elif itemType in (nwItemType.FILE, nwItemType.FOLDER):
|
||||
|
||||
sHandle = self.getSelectedHandle()
|
||||
pItem = self.theProject.tree[sHandle] if sHandle else None
|
||||
pItem = self.mainGui.project.tree[sHandle] if sHandle else None
|
||||
if sHandle is None or pItem is None:
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Did not find anywhere to add the file or folder!"
|
||||
@@ -597,7 +592,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
sLevel = nwHeaders.H_LEVEL.get(pItem.mainHeading, 0)
|
||||
sIsParent = False if qItem is None else qItem.childCount() > 0
|
||||
|
||||
if self.theProject.tree.isTrash(sHandle):
|
||||
if self.mainGui.project.tree.isTrash(sHandle):
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Cannot add new files or folders to the Trash folder."
|
||||
), level=nwAlert.ERROR)
|
||||
@@ -640,9 +635,9 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
# Add the file or folder
|
||||
if itemType == nwItemType.FILE:
|
||||
tHandle = self.theProject.newFile(newLabel, sHandle)
|
||||
tHandle = self.mainGui.project.newFile(newLabel, sHandle)
|
||||
else:
|
||||
tHandle = self.theProject.newFolder(newLabel, sHandle)
|
||||
tHandle = self.mainGui.project.newFolder(newLabel, sHandle)
|
||||
|
||||
else:
|
||||
logger.error("Failed to add new item")
|
||||
@@ -655,7 +650,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
# Handle new file creation
|
||||
if itemType == nwItemType.FILE and hLevel > 0:
|
||||
self.theProject.writeNewFile(tHandle, hLevel, not isNote)
|
||||
self.mainGui.project.writeNewFile(tHandle, hLevel, not isNote)
|
||||
|
||||
# Add the new item to the project tree
|
||||
self.revealNewTreeItem(tHandle, nHandle=nHandle, wordCount=True)
|
||||
@@ -666,7 +661,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
def revealNewTreeItem(self, tHandle: str | None, nHandle: str | None = None,
|
||||
wordCount: bool = False) -> bool:
|
||||
"""Reveal a newly added project item in the project tree."""
|
||||
nwItem = self.theProject.tree[tHandle] if tHandle else None
|
||||
nwItem = self.mainGui.project.tree[tHandle] if tHandle else None
|
||||
if tHandle is None or nwItem is None:
|
||||
return False
|
||||
|
||||
@@ -675,7 +670,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
return False
|
||||
|
||||
if nwItem.isFileType() and wordCount:
|
||||
wC = self.theProject.index.getCounts(tHandle)[1]
|
||||
wC = self.mainGui.project.index.getCounts(tHandle)[1]
|
||||
self.propagateCount(tHandle, wC)
|
||||
self.projView.wordCountsChanged.emit()
|
||||
|
||||
@@ -750,7 +745,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
def renameTreeItem(self, tHandle: str) -> bool:
|
||||
"""Open a dialog to edit the label of an item."""
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
tItem = self.mainGui.project.tree[tHandle]
|
||||
if tItem is None:
|
||||
return False
|
||||
|
||||
@@ -774,7 +769,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
if isinstance(item, QTreeWidgetItem):
|
||||
theList = self._scanChildren(theList, item, i)
|
||||
logger.debug("Saving project tree item order")
|
||||
self.theProject.setTreeOrder(theList)
|
||||
self.mainGui.project.setTreeOrder(theList)
|
||||
return
|
||||
|
||||
def getTreeFromHandle(self, tHandle: str) -> list[str]:
|
||||
@@ -807,16 +802,16 @@ class GuiProjectTree(QTreeWidget):
|
||||
logger.error("There is no item to delete")
|
||||
return False
|
||||
|
||||
trashHandle = self.theProject.tree.trashRoot()
|
||||
trashHandle = self.mainGui.project.tree.trashRoot()
|
||||
if tHandle == trashHandle:
|
||||
logger.error("Cannot delete the Trash folder")
|
||||
return False
|
||||
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
nwItem = self.mainGui.project.tree[tHandle]
|
||||
if nwItem is None:
|
||||
return False
|
||||
|
||||
if self.theProject.tree.isTrash(tHandle) or nwItem.isRootType():
|
||||
if self.mainGui.project.tree.isTrash(tHandle) or nwItem.isRootType():
|
||||
status = self.permDeleteItem(tHandle)
|
||||
else:
|
||||
status = self.moveItemToTrash(tHandle)
|
||||
@@ -832,7 +827,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
logger.error("No project open")
|
||||
return False
|
||||
|
||||
trashHandle = self.theProject.tree.trashRoot()
|
||||
trashHandle = self.mainGui.project.tree.trashRoot()
|
||||
|
||||
logger.debug("Emptying Trash folder")
|
||||
if trashHandle is None:
|
||||
@@ -875,13 +870,13 @@ class GuiProjectTree(QTreeWidget):
|
||||
so such a request is cancelled.
|
||||
"""
|
||||
trItemS = self._getTreeItem(tHandle)
|
||||
nwItemS = self.theProject.tree[tHandle]
|
||||
nwItemS = self.mainGui.project.tree[tHandle]
|
||||
|
||||
if trItemS is None or nwItemS is None:
|
||||
logger.error("Could not find tree item for deletion")
|
||||
return False
|
||||
|
||||
if self.theProject.tree.isTrash(tHandle):
|
||||
if self.mainGui.project.tree.isTrash(tHandle):
|
||||
logger.error("Item is already in the Trash folder")
|
||||
return False
|
||||
|
||||
@@ -925,7 +920,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
Root items are handled a little different than other items.
|
||||
"""
|
||||
trItemS = self._getTreeItem(tHandle)
|
||||
nwItemS = self.theProject.tree[tHandle]
|
||||
nwItemS = self.mainGui.project.tree[tHandle]
|
||||
if trItemS is None or nwItemS is None:
|
||||
logger.error("Could not find tree item for deletion")
|
||||
return False
|
||||
@@ -942,7 +937,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
tIndex = self.indexOfTopLevelItem(trItemS)
|
||||
self.takeTopLevelItem(tIndex)
|
||||
self.theProject.removeItem(tHandle)
|
||||
self.mainGui.project.removeItem(tHandle)
|
||||
self._treeMap.pop(tHandle, None)
|
||||
self._alertTreeChange(tHandle, flush=True)
|
||||
|
||||
@@ -971,7 +966,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
for dHandle in reversed(self.getTreeFromHandle(tHandle)):
|
||||
if self.mainGui.docEditor.docHandle() == dHandle:
|
||||
self.mainGui.closeDocument()
|
||||
self.theProject.removeItem(dHandle)
|
||||
self.mainGui.project.removeItem(dHandle)
|
||||
self._treeMap.pop(dHandle, None)
|
||||
|
||||
self._alertTreeChange(tHandle, flush=flush)
|
||||
@@ -989,13 +984,13 @@ class GuiProjectTree(QTreeWidget):
|
||||
already coming from the project tree.
|
||||
"""
|
||||
trItem = self._getTreeItem(tHandle)
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
nwItem = self.mainGui.project.tree[tHandle]
|
||||
if trItem is None or nwItem is None:
|
||||
return
|
||||
|
||||
itemStatus, statusIcon = nwItem.getImportStatus(incIcon=True)
|
||||
hLevel = nwItem.mainHeading
|
||||
itemIcon = self.mainTheme.getItemIcon(
|
||||
itemIcon = CONFIG.theme.getItemIcon(
|
||||
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
|
||||
)
|
||||
|
||||
@@ -1011,7 +1006,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
else:
|
||||
iconName = "noncheckable"
|
||||
|
||||
trItem.setIcon(self.C_ACTIVE, self.mainTheme.getIcon(iconName))
|
||||
trItem.setIcon(self.C_ACTIVE, CONFIG.theme.getIcon(iconName))
|
||||
|
||||
if CONFIG.emphLabels and nwItem.isDocumentLayout():
|
||||
trFont = trItem.font(self.C_NAME)
|
||||
@@ -1051,10 +1046,10 @@ class GuiProjectTree(QTreeWidget):
|
||||
pHandle = pItem.data(self.C_DATA, self.D_HANDLE)
|
||||
|
||||
if pHandle:
|
||||
if self.theProject.tree.checkType(pHandle, nwItemType.FILE):
|
||||
if self.mainGui.project.tree.checkType(pHandle, nwItemType.FILE):
|
||||
# A file has an internal word count we need to account
|
||||
# for, but a folder always has 0 words on its own.
|
||||
pCount += self.theProject.index.getCounts(pHandle)[1]
|
||||
pCount += self.mainGui.project.index.getCounts(pHandle)[1]
|
||||
|
||||
self.propagateCount(pHandle, pCount, countChildren=False)
|
||||
|
||||
@@ -1069,7 +1064,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
logger.debug("Building the project tree ...")
|
||||
self.clearTree()
|
||||
count = 0
|
||||
for nwItem in self.theProject.getProjectItems():
|
||||
for nwItem in self.mainGui.project.getProjectItems():
|
||||
count += 1
|
||||
self._addTreeItem(nwItem)
|
||||
if count > 0:
|
||||
@@ -1182,7 +1177,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
if tHandle is None:
|
||||
return
|
||||
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
tItem = self.mainGui.project.tree[tHandle]
|
||||
if tItem is None:
|
||||
return
|
||||
|
||||
@@ -1204,7 +1199,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
selItem = self.itemAt(clickPos)
|
||||
if isinstance(selItem, QTreeWidgetItem):
|
||||
tHandle = selItem.data(self.C_DATA, self.D_HANDLE)
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
tItem = self.mainGui.project.tree[tHandle]
|
||||
hasChild = selItem.childCount() > 0
|
||||
|
||||
if tItem is None or tHandle is None:
|
||||
@@ -1216,7 +1211,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
# Trash Folder
|
||||
# ============
|
||||
|
||||
trashHandle = self.theProject.tree.trashRoot()
|
||||
trashHandle = self.mainGui.project.tree.trashRoot()
|
||||
if tItem.itemHandle == trashHandle and trashHandle is not None:
|
||||
# The trash folder only has one option
|
||||
aEmptyTrash = ctxMenu.addAction(self.tr("Empty Trash"))
|
||||
@@ -1255,7 +1250,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
checkMark = f" ({nwUnicode.U_CHECK})"
|
||||
if tItem.isNovelLike():
|
||||
mStatus = ctxMenu.addMenu(self.tr("Set Status to ..."))
|
||||
for n, (key, entry) in enumerate(self.theProject.data.itemStatus.items()):
|
||||
for n, (key, entry) in enumerate(self.mainGui.project.data.itemStatus.items()):
|
||||
entryName = entry["name"] + (checkMark if tItem.itemStatus == key else "")
|
||||
aStatus = mStatus.addAction(entry["icon"], entryName)
|
||||
aStatus.triggered.connect(
|
||||
@@ -1268,7 +1263,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
)
|
||||
else:
|
||||
mImport = ctxMenu.addMenu(self.tr("Set Importance to ..."))
|
||||
for n, (key, entry) in enumerate(self.theProject.data.itemImport.items()):
|
||||
for n, (key, entry) in enumerate(self.mainGui.project.data.itemImport.items()):
|
||||
entryName = entry["name"] + (checkMark if tItem.itemImport == key else "")
|
||||
aImport = mImport.addAction(entry["icon"], entryName)
|
||||
aImport.triggered.connect(
|
||||
@@ -1380,7 +1375,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
return
|
||||
|
||||
tHandle = selItem.data(self.C_DATA, self.D_HANDLE)
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
tItem = self.mainGui.project.tree[tHandle]
|
||||
if tItem is None:
|
||||
return
|
||||
|
||||
@@ -1424,7 +1419,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
def _postItemMove(self, tHandle: str, wCount: int) -> bool:
|
||||
"""Run various maintenance tasks for a moved item."""
|
||||
trItemS = self._getTreeItem(tHandle)
|
||||
nwItemS = self.theProject.tree[tHandle]
|
||||
nwItemS = self.mainGui.project.tree[tHandle]
|
||||
trItemP = trItemS.parent() if trItemS else None
|
||||
if trItemP is None or nwItemS is None:
|
||||
logger.error("Failed to find new parent item of '%s'", tHandle)
|
||||
@@ -1441,13 +1436,13 @@ class GuiProjectTree(QTreeWidget):
|
||||
logger.debug("A total of %d item(s) were moved", len(mHandles))
|
||||
for mHandle in mHandles:
|
||||
logger.debug("Updating item '%s'", mHandle)
|
||||
self.theProject.tree.updateItemData(mHandle)
|
||||
self.mainGui.project.tree.updateItemData(mHandle)
|
||||
|
||||
# Update the index
|
||||
if nwItemS.isInactiveClass():
|
||||
self.theProject.index.deleteHandle(mHandle)
|
||||
self.mainGui.project.index.deleteHandle(mHandle)
|
||||
else:
|
||||
self.theProject.index.reIndexHandle(mHandle)
|
||||
self.mainGui.project.index.reIndexHandle(mHandle)
|
||||
|
||||
self.setTreeItemValues(mHandle)
|
||||
|
||||
@@ -1467,7 +1462,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
def _toggleItemActive(self, tHandle: str) -> None:
|
||||
"""Toggle the active status of an item."""
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
tItem = self.mainGui.project.tree[tHandle]
|
||||
if tItem is not None:
|
||||
tItem.setActive(not tItem.isActive)
|
||||
self.setTreeItemValues(tItem.itemHandle)
|
||||
@@ -1488,7 +1483,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
def _changeItemStatus(self, tHandle: str, tStatus: str) -> None:
|
||||
"""Set a new status value of an item."""
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
tItem = self.mainGui.project.tree[tHandle]
|
||||
if tItem is not None:
|
||||
tItem.setStatus(tStatus)
|
||||
self.setTreeItemValues(tItem.itemHandle)
|
||||
@@ -1497,7 +1492,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
def _changeItemImport(self, tHandle: str, tImport: str) -> None:
|
||||
"""Set a new importance value of an item."""
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
tItem = self.mainGui.project.tree[tHandle]
|
||||
if tItem is not None:
|
||||
tItem.setImport(tImport)
|
||||
self.setTreeItemValues(tItem.itemHandle)
|
||||
@@ -1506,7 +1501,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
def _changeItemLayout(self, tHandle: str, itemLayout: nwItemLayout) -> None:
|
||||
"""Set a new item layout value of an item."""
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
tItem = self.mainGui.project.tree[tHandle]
|
||||
if tItem is not None:
|
||||
if itemLayout == nwItemLayout.DOCUMENT and tItem.documentAllowed():
|
||||
tItem.setLayout(nwItemLayout.DOCUMENT)
|
||||
@@ -1520,7 +1515,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
def _covertFolderToFile(self, tHandle: str, itemLayout: nwItemLayout) -> None:
|
||||
"""Convert a folder to a note or document."""
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
tItem = self.mainGui.project.tree[tHandle]
|
||||
if tItem is not None and tItem.isFolderType():
|
||||
msgYes = self.mainGui.askQuestion(self.tr(
|
||||
"Do you want to convert the folder to a {0}? "
|
||||
@@ -1545,7 +1540,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
logger.info("Request to merge items under handle '%s'", tHandle)
|
||||
itemList = self.getTreeFromHandle(tHandle)
|
||||
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
tItem = self.mainGui.project.tree[tHandle]
|
||||
if tItem is None:
|
||||
return False
|
||||
|
||||
@@ -1571,7 +1566,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
self.mainGui.saveDocument()
|
||||
|
||||
# Create merge object, and append docs
|
||||
docMerger = DocMerger(self.theProject)
|
||||
docMerger = DocMerger(self.mainGui.project)
|
||||
mLabel = self.tr("Merged")
|
||||
|
||||
if newFile:
|
||||
@@ -1593,7 +1588,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
)
|
||||
return False
|
||||
|
||||
self.theProject.index.reIndexHandle(mHandle)
|
||||
self.mainGui.project.index.reIndexHandle(mHandle)
|
||||
if newFile:
|
||||
self.revealNewTreeItem(mHandle, nHandle=tHandle, wordCount=True)
|
||||
|
||||
@@ -1618,7 +1613,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
"""Split a document into multiple documents."""
|
||||
logger.info("Request to split items with handle '%s'", tHandle)
|
||||
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
tItem = self.mainGui.project.tree[tHandle]
|
||||
if tItem is None:
|
||||
return False
|
||||
|
||||
@@ -1637,7 +1632,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
intoFolder = splitData.get("intoFolder", False)
|
||||
docHierarchy = splitData.get("docHierarchy", False)
|
||||
|
||||
docSplit = DocSplitter(self.theProject, tHandle)
|
||||
docSplit = DocSplitter(self.mainGui.project, tHandle)
|
||||
if intoFolder:
|
||||
fHandle = docSplit.newParentFolder(tItem.itemParent, tItem.itemName)
|
||||
self.revealNewTreeItem(fHandle, nHandle=tHandle)
|
||||
@@ -1647,7 +1642,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
docSplit.splitDocument(headerList, splitText)
|
||||
for writeOk, dHandle, nHandle in docSplit.writeDocuments(docHierarchy):
|
||||
self.theProject.index.reIndexHandle(dHandle)
|
||||
self.mainGui.project.index.reIndexHandle(dHandle)
|
||||
self.revealNewTreeItem(dHandle, nHandle=nHandle, wordCount=True)
|
||||
self._alertTreeChange(dHandle, flush=False)
|
||||
if not writeOk:
|
||||
@@ -1681,10 +1676,10 @@ class GuiProjectTree(QTreeWidget):
|
||||
if not self.mainGui.askQuestion(question):
|
||||
return False
|
||||
|
||||
docDup = DocDuplicator(self.theProject)
|
||||
docDup = DocDuplicator(self.mainGui.project)
|
||||
dupCount = 0
|
||||
for dHandle, nHandle in docDup.duplicate(itemTree):
|
||||
self.theProject.index.reIndexHandle(dHandle)
|
||||
self.mainGui.project.index.reIndexHandle(dHandle)
|
||||
self.revealNewTreeItem(dHandle, nHandle=nHandle, wordCount=True)
|
||||
self._alertTreeChange(dHandle, flush=False)
|
||||
dupCount += 1
|
||||
@@ -1704,7 +1699,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
cCount = tItem.childCount()
|
||||
|
||||
# Update tree-related meta data
|
||||
nwItem = self.theProject.tree[tHandle]
|
||||
nwItem = self.mainGui.project.tree[tHandle]
|
||||
if nwItem is not None:
|
||||
nwItem.setExpanded(tItem.isExpanded() and cCount > 0)
|
||||
nwItem.setOrder(tIndex)
|
||||
@@ -1771,13 +1766,13 @@ class GuiProjectTree(QTreeWidget):
|
||||
"""Adds the trash root folder if it doesn't already exist in the
|
||||
project tree.
|
||||
"""
|
||||
trashHandle = self.theProject.trashFolder()
|
||||
trashHandle = self.mainGui.project.trashFolder()
|
||||
if trashHandle is None:
|
||||
return None
|
||||
|
||||
trItem = self._getTreeItem(trashHandle)
|
||||
if trItem is None:
|
||||
trItem = self._addTreeItem(self.theProject.tree[trashHandle])
|
||||
trItem = self._addTreeItem(self.mainGui.project.tree[trashHandle])
|
||||
if trItem is not None:
|
||||
trItem.setExpanded(True)
|
||||
self._alertTreeChange(trashHandle, flush=True)
|
||||
@@ -1790,14 +1785,14 @@ class GuiProjectTree(QTreeWidget):
|
||||
deleted.
|
||||
"""
|
||||
self._timeChanged = time()
|
||||
self.theProject.setProjectChanged(True)
|
||||
self.mainGui.project.setProjectChanged(True)
|
||||
if flush:
|
||||
self.saveTreeOrder()
|
||||
|
||||
if tHandle is None or tHandle not in self.theProject.tree:
|
||||
if tHandle is None or tHandle not in self.mainGui.project.tree:
|
||||
return
|
||||
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
tItem = self.mainGui.project.tree[tHandle]
|
||||
if tItem and tItem.isRootType():
|
||||
self.projView.rootFolderChanged.emit(tHandle)
|
||||
|
||||
|
||||
+11
-12
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Main Window SideBar
|
||||
=====================================
|
||||
GUI class for the main window side bar
|
||||
|
||||
File History:
|
||||
Created: 2022-05-10 [2.0rc1]
|
||||
@@ -22,6 +21,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
@@ -45,15 +45,14 @@ class GuiSideBar(QToolBar):
|
||||
|
||||
logger.debug("Create: GuiSideBar")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = mainGui
|
||||
|
||||
# Style
|
||||
iPx = CONFIG.pxInt(22)
|
||||
mPx = CONFIG.pxInt(60)
|
||||
|
||||
lblFont = self.mainTheme.guiFont
|
||||
lblFont.setPointSizeF(0.65*self.mainTheme.fontPointSize)
|
||||
lblFont = CONFIG.theme.guiFont
|
||||
lblFont.setPointSizeF(0.65*CONFIG.theme.fontPointSize)
|
||||
|
||||
self.setMovable(False)
|
||||
self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
|
||||
@@ -131,13 +130,13 @@ class GuiSideBar(QToolBar):
|
||||
"""
|
||||
self.setStyleSheet("QToolBar {border: 0px;}")
|
||||
|
||||
self.aProject.setIcon(self.mainTheme.getIcon("view_editor"))
|
||||
self.aNovel.setIcon(self.mainTheme.getIcon("view_novel"))
|
||||
self.aOutline.setIcon(self.mainTheme.getIcon("view_outline"))
|
||||
self.aBuild.setIcon(self.mainTheme.getIcon("view_build"))
|
||||
self.aDetails.setIcon(self.mainTheme.getIcon("proj_details"))
|
||||
self.aStats.setIcon(self.mainTheme.getIcon("proj_stats"))
|
||||
self.tbSettings.setIcon(self.mainTheme.getIcon("settings"))
|
||||
self.aProject.setIcon(CONFIG.theme.getIcon("view_editor"))
|
||||
self.aNovel.setIcon(CONFIG.theme.getIcon("view_novel"))
|
||||
self.aOutline.setIcon(CONFIG.theme.getIcon("view_outline"))
|
||||
self.aBuild.setIcon(CONFIG.theme.getIcon("view_build"))
|
||||
self.aDetails.setIcon(CONFIG.theme.getIcon("proj_details"))
|
||||
self.aStats.setIcon(CONFIG.theme.getIcon("proj_stats"))
|
||||
self.tbSettings.setIcon(CONFIG.theme.getIcon("settings"))
|
||||
|
||||
return
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI Main Window Status Bar
|
||||
========================================
|
||||
GUI class for the main window status bar
|
||||
|
||||
File History:
|
||||
Created: 2019-04-20 [0.0.1] GuiMainStatus
|
||||
@@ -23,6 +22,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
@@ -34,7 +34,7 @@ from PyQt5.QtWidgets import qApp, QStatusBar, QLabel
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.common import formatTime
|
||||
from novelwriter.gui.components import StatusLED
|
||||
from novelwriter.extensions.statusled import StatusLED
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -47,15 +47,14 @@ class GuiMainStatus(QStatusBar):
|
||||
logger.debug("Create: GuiMainStatus")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.refTime = None
|
||||
self.userIdle = False
|
||||
|
||||
colNone = QColor(*self.mainTheme.statNone)
|
||||
colSaved = QColor(*self.mainTheme.statSaved)
|
||||
colUnsaved = QColor(*self.mainTheme.statUnsaved)
|
||||
colNone = QColor(*CONFIG.theme.statNone)
|
||||
colSaved = QColor(*CONFIG.theme.statSaved)
|
||||
colUnsaved = QColor(*CONFIG.theme.statUnsaved)
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
|
||||
# Permanent Widgets
|
||||
# =================
|
||||
@@ -99,7 +98,7 @@ class GuiMainStatus(QStatusBar):
|
||||
self.timeIcon = QLabel()
|
||||
self.timeText = QLabel("")
|
||||
self.timeText.setToolTip(self.tr("Session Time"))
|
||||
self.timeText.setMinimumWidth(self.mainTheme.getTextWidth("00:00:00:"))
|
||||
self.timeText.setMinimumWidth(CONFIG.theme.getTextWidth("00:00:00:"))
|
||||
self.timeIcon.setContentsMargins(0, 0, 0, 0)
|
||||
self.timeText.setContentsMargins(0, 0, 0, 0)
|
||||
self.addPermanentWidget(self.timeIcon)
|
||||
@@ -129,13 +128,13 @@ class GuiMainStatus(QStatusBar):
|
||||
def updateTheme(self):
|
||||
"""Update theme elements.
|
||||
"""
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
|
||||
self.langIcon.setPixmap(self.mainTheme.getPixmap("status_lang", (iPx, iPx)))
|
||||
self.statsIcon.setPixmap(self.mainTheme.getPixmap("status_stats", (iPx, iPx)))
|
||||
self.langIcon.setPixmap(CONFIG.theme.getPixmap("status_lang", (iPx, iPx)))
|
||||
self.statsIcon.setPixmap(CONFIG.theme.getPixmap("status_stats", (iPx, iPx)))
|
||||
|
||||
self.timePixmap = self.mainTheme.getPixmap("status_time", (iPx, iPx))
|
||||
self.idlePixmap = self.mainTheme.getPixmap("status_idle", (iPx, iPx))
|
||||
self.timePixmap = CONFIG.theme.getPixmap("status_time", (iPx, iPx))
|
||||
self.idlePixmap = CONFIG.theme.getPixmap("status_idle", (iPx, iPx))
|
||||
|
||||
self.timeIcon.setPixmap(self.timePixmap)
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – Theme and Icons Classes
|
||||
=====================================
|
||||
Classes managing and caching themes and icons
|
||||
|
||||
File History:
|
||||
Created: 2019-05-18 [0.1.3] GuiTheme
|
||||
|
||||
+52
-43
@@ -113,8 +113,8 @@ class GuiMain(QMainWindow):
|
||||
# ============
|
||||
|
||||
# Core Classes
|
||||
self.mainTheme = GuiTheme()
|
||||
self.theProject = NWProject(self)
|
||||
CONFIG.setThemeInstance(GuiTheme())
|
||||
self._project = NWProject(self)
|
||||
|
||||
# Core Settings
|
||||
self.hasProject = False
|
||||
@@ -135,7 +135,7 @@ class GuiMain(QMainWindow):
|
||||
# =============
|
||||
|
||||
# Sizes
|
||||
iPx = self.mainTheme.fontPixelSize
|
||||
iPx = CONFIG.theme.fontPixelSize
|
||||
mPx = CONFIG.pxInt(4)
|
||||
hWd = CONFIG.pxInt(4)
|
||||
|
||||
@@ -238,7 +238,7 @@ class GuiMain(QMainWindow):
|
||||
# Connect Signals
|
||||
# ===============
|
||||
|
||||
self.theProject.projectStatusChanged.connect(self.mainStatus.doUpdateProjectStatus)
|
||||
self._project.projectStatusChanged.connect(self.mainStatus.doUpdateProjectStatus)
|
||||
|
||||
self.viewsBar.viewChangeRequested.connect(self._changeView)
|
||||
|
||||
@@ -307,10 +307,10 @@ class GuiMain(QMainWindow):
|
||||
# Cache Alert Pixmaps
|
||||
pxSize = (2*iPx, 2*iPx)
|
||||
self.alertPix: dict[nwAlert, QPixmap] = {
|
||||
nwAlert.INFO: self.mainTheme.getPixmap("alert_info", pxSize),
|
||||
nwAlert.WARN: self.mainTheme.getPixmap("alert_warn", pxSize),
|
||||
nwAlert.ERROR: self.mainTheme.getPixmap("alert_error", pxSize),
|
||||
nwAlert.ASK: self.mainTheme.getPixmap("alert_question", pxSize),
|
||||
nwAlert.INFO: CONFIG.theme.getPixmap("alert_info", pxSize),
|
||||
nwAlert.WARN: CONFIG.theme.getPixmap("alert_warn", pxSize),
|
||||
nwAlert.ERROR: CONFIG.theme.getPixmap("alert_error", pxSize),
|
||||
nwAlert.ASK: CONFIG.theme.getPixmap("alert_question", pxSize),
|
||||
}
|
||||
|
||||
# Check that config loaded fine
|
||||
@@ -382,6 +382,15 @@ class GuiMain(QMainWindow):
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
|
||||
@property
|
||||
def project(self) -> NWProject:
|
||||
"""The project instance."""
|
||||
return self._project
|
||||
|
||||
##
|
||||
# Project Actions
|
||||
##
|
||||
@@ -444,7 +453,7 @@ class GuiMain(QMainWindow):
|
||||
|
||||
saveOK = self.saveProject()
|
||||
doBackup = False
|
||||
if self.theProject.data.doBackup and CONFIG.backupOnClose:
|
||||
if self._project.data.doBackup and CONFIG.backupOnClose:
|
||||
doBackup = True
|
||||
if CONFIG.askBeforeBackup:
|
||||
msgYes = self.askQuestion(self.tr("Backup the current project?"))
|
||||
@@ -452,7 +461,7 @@ class GuiMain(QMainWindow):
|
||||
doBackup = False
|
||||
|
||||
if doBackup:
|
||||
self.theProject.backupProject(False)
|
||||
self._project.backupProject(False)
|
||||
|
||||
if saveOK:
|
||||
self.closeDocument()
|
||||
@@ -460,7 +469,7 @@ class GuiMain(QMainWindow):
|
||||
self.outlineView.closeProjectTasks()
|
||||
self.novelView.closeProjectTasks()
|
||||
|
||||
self.theProject.closeProject(self.idleTime)
|
||||
self._project.closeProject(self.idleTime)
|
||||
self.idleRefTime = time()
|
||||
self.idleTime = 0.0
|
||||
|
||||
@@ -484,9 +493,9 @@ class GuiMain(QMainWindow):
|
||||
self._changeView(nwView.PROJECT)
|
||||
|
||||
# Try to open the project
|
||||
if not self.theProject.openProject(projFile):
|
||||
if not self._project.openProject(projFile):
|
||||
# The project open failed.
|
||||
lockStatus = self.theProject.getLockStatus()
|
||||
lockStatus = self._project.getLockStatus()
|
||||
if lockStatus is None:
|
||||
# The project is not locked, so failed for some other
|
||||
# reason handled by the project class.
|
||||
@@ -516,7 +525,7 @@ class GuiMain(QMainWindow):
|
||||
lockDetails = ""
|
||||
|
||||
if self.askQuestion(lockText, info=lockInfo, details=lockDetails, level=nwAlert.WARN):
|
||||
if not self.theProject.openProject(projFile, overrideLock=True):
|
||||
if not self._project.openProject(projFile, overrideLock=True):
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
@@ -527,11 +536,11 @@ class GuiMain(QMainWindow):
|
||||
self.idleTime = 0.0
|
||||
|
||||
# Update GUI
|
||||
self._updateWindowTitle(self.theProject.data.name)
|
||||
self._updateWindowTitle(self._project.data.name)
|
||||
self.rebuildTrees()
|
||||
self.docEditor.setDictionaries()
|
||||
self.docEditor.toggleSpellCheck(self.theProject.data.spellCheck)
|
||||
self.mainStatus.setRefTime(self.theProject.projOpened)
|
||||
self.docEditor.toggleSpellCheck(self._project.data.spellCheck)
|
||||
self.mainStatus.setRefTime(self._project.projOpened)
|
||||
self.projView.openProjectTasks()
|
||||
self.novelView.openProjectTasks()
|
||||
self.outlineView.openProjectTasks()
|
||||
@@ -539,9 +548,9 @@ class GuiMain(QMainWindow):
|
||||
|
||||
# Restore previously open documents, if any
|
||||
# If none was recorded, open the first document found
|
||||
lastEdited = self.theProject.data.getLastHandle("editor")
|
||||
lastEdited = self._project.data.getLastHandle("editor")
|
||||
if lastEdited is None:
|
||||
for nwItem in self.theProject.tree:
|
||||
for nwItem in self._project.tree:
|
||||
if nwItem and nwItem.isFileType():
|
||||
lastEdited = nwItem.itemHandle
|
||||
break
|
||||
@@ -549,19 +558,19 @@ class GuiMain(QMainWindow):
|
||||
if lastEdited is not None:
|
||||
self.openDocument(lastEdited, doScroll=True)
|
||||
|
||||
lastViewed = self.theProject.data.getLastHandle("viewer")
|
||||
lastViewed = self._project.data.getLastHandle("viewer")
|
||||
if lastViewed is not None:
|
||||
self.viewDocument(lastViewed)
|
||||
|
||||
# Check if we need to rebuild the index
|
||||
if self.theProject.index.indexBroken:
|
||||
if self._project.index.indexBroken:
|
||||
self.makeAlert(self.tr("The project index is outdated or broken. Rebuilding index."))
|
||||
self.rebuildIndex()
|
||||
|
||||
# Make sure the changed status is set to false on things opened
|
||||
qApp.processEvents()
|
||||
self.docEditor.setDocumentChanged(False)
|
||||
self.theProject.setProjectChanged(False)
|
||||
self._project.setProjectChanged(False)
|
||||
|
||||
logger.debug("Project load complete")
|
||||
|
||||
@@ -573,7 +582,7 @@ class GuiMain(QMainWindow):
|
||||
logger.error("No project open")
|
||||
return False
|
||||
self.projView.saveProjectTasks()
|
||||
self.theProject.saveProject(autoSave=autoSave)
|
||||
self._project.saveProject(autoSave=autoSave)
|
||||
return True
|
||||
|
||||
##
|
||||
@@ -606,7 +615,7 @@ class GuiMain(QMainWindow):
|
||||
logger.error("No project open")
|
||||
return False
|
||||
|
||||
if not tHandle or not self.theProject.tree.checkType(tHandle, nwItemType.FILE):
|
||||
if not tHandle or not self._project.tree.checkType(tHandle, nwItemType.FILE):
|
||||
logger.debug("Requested item '%s' is not a document", tHandle)
|
||||
return False
|
||||
|
||||
@@ -620,7 +629,7 @@ class GuiMain(QMainWindow):
|
||||
|
||||
self.closeDocument(beforeOpen=True)
|
||||
if self.docEditor.loadText(tHandle, tLine):
|
||||
self.theProject.data.setLastHandle(tHandle, "editor")
|
||||
self._project.data.setLastHandle(tHandle, "editor")
|
||||
self.projView.setSelectedHandle(tHandle, doScroll=doScroll)
|
||||
self.novelView.setActiveHandle(tHandle)
|
||||
if changeFocus:
|
||||
@@ -641,7 +650,7 @@ class GuiMain(QMainWindow):
|
||||
nHandle = None # The next handle after tHandle
|
||||
fHandle = None # The first file handle we encounter
|
||||
foundIt = False # We've found tHandle, pick the next we see
|
||||
for tItem in self.theProject.tree:
|
||||
for tItem in self._project.tree:
|
||||
if not tItem.isFileType():
|
||||
continue
|
||||
if fHandle is None:
|
||||
@@ -687,7 +696,7 @@ class GuiMain(QMainWindow):
|
||||
tHandle = self.projView.getSelectedHandle()
|
||||
|
||||
if tHandle is None:
|
||||
tHandle = self.theProject.data.getLastHandle("viewer")
|
||||
tHandle = self._project.data.getLastHandle("viewer")
|
||||
|
||||
if tHandle is None:
|
||||
logger.debug("No document to view, giving up")
|
||||
@@ -806,7 +815,7 @@ class GuiMain(QMainWindow):
|
||||
return False
|
||||
|
||||
if tHandle is not None and sTitle is not None:
|
||||
hItem = self.theProject.index.getItemHeader(tHandle, sTitle)
|
||||
hItem = self._project.index.getItemHeader(tHandle, sTitle)
|
||||
if hItem is not None:
|
||||
tLine = hItem.line
|
||||
|
||||
@@ -843,7 +852,7 @@ class GuiMain(QMainWindow):
|
||||
tStart = time()
|
||||
|
||||
self.projView.saveProjectTasks()
|
||||
self.theProject.index.rebuildIndex()
|
||||
self._project.index.rebuildIndex()
|
||||
self.projView.populateTree()
|
||||
self.novelView.refreshTree()
|
||||
|
||||
@@ -912,7 +921,7 @@ class GuiMain(QMainWindow):
|
||||
if dlgConf.updateTheme:
|
||||
# We are doing this manually instead of connecting to
|
||||
# qApp.paletteChanged since the processing order matters
|
||||
self.mainTheme.loadTheme()
|
||||
CONFIG.theme.loadTheme()
|
||||
self.docEditor.updateTheme()
|
||||
self.docViewer.updateTheme()
|
||||
self.viewsBar.updateTheme()
|
||||
@@ -923,7 +932,7 @@ class GuiMain(QMainWindow):
|
||||
self.mainStatus.updateTheme()
|
||||
|
||||
if dlgConf.updateSyntax:
|
||||
self.mainTheme.loadSyntax()
|
||||
CONFIG.theme.loadSyntax()
|
||||
self.docEditor.updateSyntaxColours()
|
||||
|
||||
self.docEditor.initEditor()
|
||||
@@ -951,7 +960,7 @@ class GuiMain(QMainWindow):
|
||||
if dlgProj.spellChanged:
|
||||
self.docEditor.setDictionaries()
|
||||
self.itemDetails.refreshDetails()
|
||||
self._updateWindowTitle(self.theProject.data.name)
|
||||
self._updateWindowTitle(self._project.data.name)
|
||||
|
||||
return True
|
||||
|
||||
@@ -1197,7 +1206,7 @@ class GuiMain(QMainWindow):
|
||||
def closeDocEditor(self) -> None:
|
||||
"""Close the document editor. This does not hide the editor."""
|
||||
self.closeDocument()
|
||||
self.theProject.data.setLastHandle(None, "editor")
|
||||
self._project.data.setLastHandle(None, "editor")
|
||||
return
|
||||
|
||||
def closeDocViewer(self, byUser: bool = True) -> bool:
|
||||
@@ -1205,7 +1214,7 @@ class GuiMain(QMainWindow):
|
||||
self.docViewer.clearViewer()
|
||||
if byUser:
|
||||
# Only reset the last handle if the user called this
|
||||
self.theProject.data.setLastHandle(None, "viewer")
|
||||
self._project.data.setLastHandle(None, "viewer")
|
||||
|
||||
# Hide the panel
|
||||
bPos = self.splitMain.sizes()
|
||||
@@ -1391,7 +1400,7 @@ class GuiMain(QMainWindow):
|
||||
"""Handle the index lookup of a tag and display an alert if the
|
||||
tag cannot be found.
|
||||
"""
|
||||
tHandle, sTitle = self.theProject.index.getTagSource(tag)
|
||||
tHandle, sTitle = self._project.index.getTagSource(tag)
|
||||
if tHandle is None:
|
||||
self.makeAlert(self.tr(
|
||||
"Could not find the reference for tag '{0}'. It either doesn't "
|
||||
@@ -1438,7 +1447,7 @@ class GuiMain(QMainWindow):
|
||||
if tHandle is not None:
|
||||
if mode == nwDocMode.EDIT:
|
||||
tLine = None
|
||||
hItem = self.theProject.index.getItemHeader(tHandle, sTitle)
|
||||
hItem = self._project.index.getItemHeader(tHandle, sTitle)
|
||||
if hItem is not None:
|
||||
tLine = hItem.line
|
||||
self.openDocument(tHandle, tLine=tLine, changeFocus=setFocus)
|
||||
@@ -1491,8 +1500,8 @@ class GuiMain(QMainWindow):
|
||||
def _autoSaveProject(self) -> None:
|
||||
"""Autosave of the project. This is a timer-activated slot."""
|
||||
doSave = self.hasProject
|
||||
doSave &= self.theProject.projChanged
|
||||
doSave &= self.theProject.storage.isOpen()
|
||||
doSave &= self._project.projChanged
|
||||
doSave &= self._project.storage.isOpen()
|
||||
if doSave:
|
||||
logger.debug("Autosaving project")
|
||||
self.saveProject(autoSave=True)
|
||||
@@ -1512,14 +1521,14 @@ class GuiMain(QMainWindow):
|
||||
if not self.hasProject:
|
||||
self.mainStatus.setProjectStats(0, 0)
|
||||
|
||||
self.theProject.updateWordCounts()
|
||||
self._project.updateWordCounts()
|
||||
if CONFIG.incNotesWCount:
|
||||
iTotal = sum(self.theProject.data.initCounts)
|
||||
cTotal = sum(self.theProject.data.currCounts)
|
||||
iTotal = sum(self._project.data.initCounts)
|
||||
cTotal = sum(self._project.data.currCounts)
|
||||
self.mainStatus.setProjectStats(cTotal, cTotal - iTotal)
|
||||
else:
|
||||
iNovel, _ = self.theProject.data.initCounts
|
||||
cNovel, _ = self.theProject.data.currCounts
|
||||
iNovel, _ = self._project.data.initCounts
|
||||
cNovel, _ = self._project.data.currCounts
|
||||
self.mainStatus.setProjectStats(cNovel, cNovel - iNovel)
|
||||
|
||||
return
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – Lorem Ipsum Tool
|
||||
==============================
|
||||
Simple tool for inserting placeholder text in a document
|
||||
|
||||
File History:
|
||||
Created: 2022-04-02 [2.0rc1]
|
||||
@@ -22,6 +21,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import logging
|
||||
@@ -49,8 +49,7 @@ class GuiLipsum(QDialog):
|
||||
if CONFIG.osDarwin:
|
||||
self.setWindowFlag(Qt.WindowType.Tool)
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = mainGui
|
||||
|
||||
self.setWindowTitle(self.tr("Insert Placeholder Text"))
|
||||
|
||||
@@ -61,7 +60,7 @@ class GuiLipsum(QDialog):
|
||||
nPx = CONFIG.pxInt(64)
|
||||
vSp = CONFIG.pxInt(4)
|
||||
self.docIcon = QLabel()
|
||||
self.docIcon.setPixmap(self.mainTheme.getPixmap("proj_document", (nPx, nPx)))
|
||||
self.docIcon.setPixmap(CONFIG.theme.getPixmap("proj_document", (nPx, nPx)))
|
||||
|
||||
self.leftBox = QVBoxLayout()
|
||||
self.leftBox.setSpacing(vSp)
|
||||
|
||||
@@ -65,9 +65,7 @@ class GuiManuscriptBuild(QDialog):
|
||||
logger.debug("Create: GuiManuscriptBuild")
|
||||
self.setObjectName("GuiManuscriptBuild")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
self._parent = parent
|
||||
self._build = build
|
||||
@@ -76,14 +74,14 @@ class GuiManuscriptBuild(QDialog):
|
||||
self.setMinimumWidth(CONFIG.pxInt(500))
|
||||
self.setMinimumHeight(CONFIG.pxInt(300))
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
sp4 = CONFIG.pxInt(4)
|
||||
sp8 = CONFIG.pxInt(8)
|
||||
sp16 = CONFIG.pxInt(16)
|
||||
wWin = CONFIG.pxInt(620)
|
||||
hWin = CONFIG.pxInt(360)
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
self.resize(
|
||||
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "winWidth", wWin)),
|
||||
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "winHeight", hWin))
|
||||
@@ -148,7 +146,7 @@ class GuiManuscriptBuild(QDialog):
|
||||
# Build Path
|
||||
self.lblPath = QLabel(self.tr("Path"))
|
||||
self.buildPath = QLineEdit(self)
|
||||
self.btnBrowse = QPushButton(self.mainTheme.getIcon("browse"), "")
|
||||
self.btnBrowse = QPushButton(CONFIG.theme.getIcon("browse"), "")
|
||||
|
||||
self.pathBox = QHBoxLayout()
|
||||
self.pathBox.addWidget(self.buildPath)
|
||||
@@ -158,7 +156,7 @@ class GuiManuscriptBuild(QDialog):
|
||||
# Build Name
|
||||
self.lblName = QLabel(self.tr("File Name"))
|
||||
self.buildName = QLineEdit(self)
|
||||
self.btnReset = QPushButton(self.mainTheme.getIcon("revert"), "")
|
||||
self.btnReset = QPushButton(CONFIG.theme.getIcon("revert"), "")
|
||||
self.btnReset.setToolTip(self.tr("Reset file name to default"))
|
||||
|
||||
self.nameBox = QHBoxLayout()
|
||||
@@ -183,7 +181,7 @@ class GuiManuscriptBuild(QDialog):
|
||||
self.buildBox.setVerticalSpacing(sp4)
|
||||
|
||||
# Dialog Buttons
|
||||
self.btnBuild = QPushButton(self.mainTheme.getIcon("export"), self.tr("&Build"))
|
||||
self.btnBuild = QPushButton(CONFIG.theme.getIcon("export"), self.tr("&Build"))
|
||||
self.dlgButtons = QDialogButtonBox(QDialogButtonBox.Close)
|
||||
self.dlgButtons.addButton(self.btnBuild, QDialogButtonBox.ActionRole)
|
||||
|
||||
@@ -281,7 +279,7 @@ class GuiManuscriptBuild(QDialog):
|
||||
@pyqtSlot()
|
||||
def _doResetBuildName(self):
|
||||
"""Generate a default build name."""
|
||||
bName = f"{self.theProject.data.name} - {self._build.name}"
|
||||
bName = f"{self.mainGui.project.data.name} - {self._build.name}"
|
||||
self.buildName.setText(bName)
|
||||
self._build.setLastBuildName(bName)
|
||||
return
|
||||
@@ -322,7 +320,7 @@ class GuiManuscriptBuild(QDialog):
|
||||
):
|
||||
return False
|
||||
|
||||
docBuild = NWBuildDocument(self.theProject, self._build)
|
||||
docBuild = NWBuildDocument(self.mainGui.project, self._build)
|
||||
docBuild.queueAll()
|
||||
|
||||
self.buildProgress.setMaximum(len(docBuild))
|
||||
@@ -355,7 +353,7 @@ class GuiManuscriptBuild(QDialog):
|
||||
fmtWidth = CONFIG.rpxInt(mainSplit[0])
|
||||
sumWidth = CONFIG.rpxInt(mainSplit[1])
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
pOptions.setValue("GuiManuscriptBuild", "winWidth", winWidth)
|
||||
pOptions.setValue("GuiManuscriptBuild", "winHeight", winHeight)
|
||||
pOptions.setValue("GuiManuscriptBuild", "fmtWidth", fmtWidth)
|
||||
@@ -367,9 +365,9 @@ class GuiManuscriptBuild(QDialog):
|
||||
def _populateContentList(self):
|
||||
"""Build the content list."""
|
||||
rootMap = {}
|
||||
filtered = self._build.buildItemFilter(self.theProject)
|
||||
filtered = self._build.buildItemFilter(self.mainGui.project)
|
||||
self.listContent.clear()
|
||||
for nwItem in self.theProject.tree:
|
||||
for nwItem in self.mainGui.project.tree:
|
||||
tHandle = nwItem.itemHandle
|
||||
rHandle = nwItem.itemRoot
|
||||
|
||||
@@ -378,11 +376,11 @@ class GuiManuscriptBuild(QDialog):
|
||||
|
||||
if filtered.get(tHandle, (False, 0))[0]:
|
||||
if rHandle not in rootMap:
|
||||
rItem = self.theProject.tree[rHandle]
|
||||
rItem = self.mainGui.project.tree[rHandle]
|
||||
if isinstance(rItem, NWItem):
|
||||
rootMap[rHandle] = rItem.itemName
|
||||
|
||||
itemIcon = self.mainTheme.getItemIcon(
|
||||
itemIcon = CONFIG.theme.getItemIcon(
|
||||
nwItem.itemType, nwItem.itemClass,
|
||||
nwItem.itemLayout, nwItem.mainHeading
|
||||
)
|
||||
|
||||
@@ -72,22 +72,20 @@ class GuiManuscript(QDialog):
|
||||
if CONFIG.osDarwin:
|
||||
self.setWindowFlag(Qt.WindowType.Tool)
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
self._builds = BuildCollection(self.theProject)
|
||||
self._builds = BuildCollection(self.mainGui.project)
|
||||
self._buildMap: dict[str, QListWidgetItem] = {}
|
||||
|
||||
self.setWindowTitle(self.tr("Build Manuscript"))
|
||||
self.setMinimumWidth(CONFIG.pxInt(600))
|
||||
self.setMinimumHeight(CONFIG.pxInt(500))
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
wWin = CONFIG.pxInt(900)
|
||||
hWin = CONFIG.pxInt(600)
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
self.resize(
|
||||
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "winWidth", wWin)),
|
||||
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "winHeight", hWin))
|
||||
@@ -107,21 +105,21 @@ class GuiManuscript(QDialog):
|
||||
).format(CONFIG.pxInt(2), fadeCol.red(), fadeCol.green(), fadeCol.blue())
|
||||
|
||||
self.tbAdd = QToolButton(self)
|
||||
self.tbAdd.setIcon(self.mainTheme.getIcon("add"))
|
||||
self.tbAdd.setIcon(CONFIG.theme.getIcon("add"))
|
||||
self.tbAdd.setIconSize(QSize(iPx, iPx))
|
||||
self.tbAdd.setToolTip(self.tr("Add New Build"))
|
||||
self.tbAdd.setStyleSheet(buttonStyle)
|
||||
self.tbAdd.clicked.connect(self._createNewBuild)
|
||||
|
||||
self.tbDel = QToolButton(self)
|
||||
self.tbDel.setIcon(self.mainTheme.getIcon("remove"))
|
||||
self.tbDel.setIcon(CONFIG.theme.getIcon("remove"))
|
||||
self.tbDel.setIconSize(QSize(iPx, iPx))
|
||||
self.tbDel.setToolTip(self.tr("Delete Selected Build"))
|
||||
self.tbDel.setStyleSheet(buttonStyle)
|
||||
self.tbDel.clicked.connect(self._deleteSelectedBuild)
|
||||
|
||||
self.tbEdit = QToolButton(self)
|
||||
self.tbEdit.setIcon(self.mainTheme.getIcon("edit"))
|
||||
self.tbEdit.setIcon(CONFIG.theme.getIcon("edit"))
|
||||
self.tbEdit.setIconSize(QSize(iPx, iPx))
|
||||
self.tbEdit.setToolTip(self.tr("Edit Selected Build"))
|
||||
self.tbEdit.setStyleSheet(buttonStyle)
|
||||
@@ -212,7 +210,7 @@ class GuiManuscript(QDialog):
|
||||
self._updateBuildsList()
|
||||
|
||||
logger.debug("Loading build cache")
|
||||
cache = CONFIG.dataPath("cache") / f"build_{self.theProject.data.uuid}.json"
|
||||
cache = CONFIG.dataPath("cache") / f"build_{self.mainGui.project.data.uuid}.json"
|
||||
if cache.is_file():
|
||||
try:
|
||||
with open(cache, mode="r", encoding="utf-8") as fObj:
|
||||
@@ -291,7 +289,7 @@ class GuiManuscript(QDialog):
|
||||
if build is None:
|
||||
return
|
||||
|
||||
docBuild = NWBuildDocument(self.theProject, build)
|
||||
docBuild = NWBuildDocument(self.mainGui.project, build)
|
||||
docBuild.queueAll()
|
||||
|
||||
self.docPreview.beginNewBuild(len(docBuild))
|
||||
@@ -311,7 +309,7 @@ class GuiManuscript(QDialog):
|
||||
self._updatePreview(result, build)
|
||||
|
||||
logger.debug("Saving build cache")
|
||||
cache = CONFIG.dataPath("cache") / f"build_{self.theProject.data.uuid}.json"
|
||||
cache = CONFIG.dataPath("cache") / f"build_{self.mainGui.project.data.uuid}.json"
|
||||
try:
|
||||
with open(cache, mode="w+", encoding="utf-8") as outFile:
|
||||
outFile.write(json.dumps(result, indent=2))
|
||||
@@ -392,7 +390,7 @@ class GuiManuscript(QDialog):
|
||||
optsWidth = CONFIG.rpxInt(mainSplit[0])
|
||||
viewWidth = CONFIG.rpxInt(mainSplit[1])
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
pOptions.setValue("GuiManuscript", "winWidth", winWidth)
|
||||
pOptions.setValue("GuiManuscript", "winHeight", winHeight)
|
||||
pOptions.setValue("GuiManuscript", "optsWidth", optsWidth)
|
||||
@@ -428,7 +426,7 @@ class GuiManuscript(QDialog):
|
||||
for key, name in self._builds.builds():
|
||||
bItem = QListWidgetItem()
|
||||
bItem.setText(name)
|
||||
bItem.setIcon(self.mainTheme.getIcon("export"))
|
||||
bItem.setIcon(CONFIG.theme.getIcon("export"))
|
||||
bItem.setData(self.D_KEY, key)
|
||||
self.buildList.addItem(bItem)
|
||||
self._buildMap[key] = bItem
|
||||
@@ -451,9 +449,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
def __init__(self, mainGui: GuiMain):
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
self._docTime = 0
|
||||
self._buildName = ""
|
||||
@@ -464,7 +460,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
dPalette.setColor(QPalette.Text, QColor(0, 0, 0))
|
||||
self.setPalette(dPalette)
|
||||
|
||||
self.setMinimumWidth(40*self.mainGui.mainTheme.textNWidth)
|
||||
self.setMinimumWidth(40*CONFIG.theme.textNWidth)
|
||||
self.setTextFont(CONFIG.textFont, CONFIG.textSize)
|
||||
self.setTabStopDistance(CONFIG.getTabWidth())
|
||||
self.setOpenExternalLinks(False)
|
||||
@@ -482,7 +478,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
aPalette.setColor(QPalette.Foreground, aPalette.toolTipText().color())
|
||||
|
||||
aFont = self.font()
|
||||
aFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
|
||||
aFont.setPointSizeF(0.9*CONFIG.theme.fontPointSize)
|
||||
|
||||
self.ageLabel = QLabel("", self)
|
||||
self.ageLabel.setIndent(0)
|
||||
@@ -490,7 +486,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
self.ageLabel.setPalette(aPalette)
|
||||
self.ageLabel.setAutoFillBackground(True)
|
||||
self.ageLabel.setAlignment(Qt.AlignCenter)
|
||||
self.ageLabel.setFixedHeight(int(2.1*self.mainTheme.fontPixelSize))
|
||||
self.ageLabel.setFixedHeight(int(2.1*CONFIG.theme.fontPixelSize))
|
||||
|
||||
# Progress
|
||||
self.buildProgress = NProgressCircle(self, CONFIG.pxInt(160), CONFIG.pxInt(16))
|
||||
@@ -526,12 +522,12 @@ class _PreviewWidget(QTextBrowser):
|
||||
|
||||
def setJustify(self, state: bool):
|
||||
"""Enable/disable the justify text option."""
|
||||
options = self.document().defaultTextOption()
|
||||
pOptions = self.document().defaultTextOption()
|
||||
if state:
|
||||
options.setAlignment(Qt.AlignJustify)
|
||||
pOptions.setAlignment(Qt.AlignJustify)
|
||||
else:
|
||||
options.setAlignment(Qt.AlignAbsolute)
|
||||
self.document().setDefaultTextOption(options)
|
||||
pOptions.setAlignment(Qt.AlignAbsolute)
|
||||
self.document().setDefaultTextOption(pOptions)
|
||||
return
|
||||
|
||||
def setTextFont(self, family: str, size: int):
|
||||
|
||||
@@ -49,7 +49,6 @@ from novelwriter.extensions.pagedsidebar import NPagedSideBar
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.guimain import GuiMain
|
||||
from novelwriter.gui.theme import GuiTheme
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -77,9 +76,7 @@ class GuiBuildSettings(QDialog):
|
||||
if CONFIG.osDarwin:
|
||||
self.setWindowFlag(Qt.WindowType.Tool)
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
self._build = build
|
||||
|
||||
@@ -91,7 +88,7 @@ class GuiBuildSettings(QDialog):
|
||||
wWin = CONFIG.pxInt(750)
|
||||
hWin = CONFIG.pxInt(550)
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
self.resize(
|
||||
CONFIG.pxInt(pOptions.getInt("GuiBuildSettings", "winWidth", wWin)),
|
||||
CONFIG.pxInt(pOptions.getInt("GuiBuildSettings", "winHeight", hWin))
|
||||
@@ -103,7 +100,7 @@ class GuiBuildSettings(QDialog):
|
||||
self.optSideBar = NPagedSideBar(self)
|
||||
self.optSideBar.setMinimumWidth(mPx)
|
||||
self.optSideBar.setMaximumWidth(mPx)
|
||||
self.optSideBar.setLabelColor(self.mainTheme.helpText)
|
||||
self.optSideBar.setLabelColor(CONFIG.theme.helpText)
|
||||
|
||||
self.optSideBar.addLabel(self.tr("Options"))
|
||||
self.optSideBar.addButton(self.tr("Selection"), self.OPT_FILTERS)
|
||||
@@ -265,7 +262,7 @@ class GuiBuildSettings(QDialog):
|
||||
|
||||
treeWidth, filterWidth = self.optTabSelect.mainSplitSizes()
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
pOptions.setValue("GuiBuildSettings", "winWidth", winWidth)
|
||||
pOptions.setValue("GuiBuildSettings", "winHeight", winHeight)
|
||||
pOptions.setValue("GuiBuildSettings", "treeWidth", treeWidth)
|
||||
@@ -306,18 +303,16 @@ class _FilterTab(QWidget):
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
|
||||
super().__init__(parent=buildMain)
|
||||
|
||||
self.mainGui = buildMain.mainGui
|
||||
self.mainTheme = buildMain.mainGui.mainTheme
|
||||
self.theProject = buildMain.mainGui.theProject
|
||||
self.mainGui = buildMain.mainGui
|
||||
|
||||
self._treeMap: dict[str, QTreeWidgetItem] = {}
|
||||
self._build = build
|
||||
|
||||
self._statusFlags: dict[int, QIcon] = {
|
||||
self.F_NONE: QIcon(),
|
||||
self.F_FILTERED: self.mainTheme.getIcon("build_filtered"),
|
||||
self.F_INCLUDED: self.mainTheme.getIcon("build_included"),
|
||||
self.F_EXCLUDED: self.mainTheme.getIcon("build_excluded"),
|
||||
self.F_FILTERED: CONFIG.theme.getIcon("build_filtered"),
|
||||
self.F_INCLUDED: CONFIG.theme.getIcon("build_included"),
|
||||
self.F_EXCLUDED: CONFIG.theme.getIcon("build_excluded"),
|
||||
}
|
||||
|
||||
self._trIncluded = self.tr("Included in manuscript")
|
||||
@@ -327,7 +322,7 @@ class _FilterTab(QWidget):
|
||||
# ============
|
||||
|
||||
# Tree Settings
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
cMg = CONFIG.pxInt(6)
|
||||
|
||||
# Tree Widget
|
||||
@@ -365,7 +360,7 @@ class _FilterTab(QWidget):
|
||||
|
||||
self.resetButton = QToolButton(self)
|
||||
self.resetButton.setToolTip(self.tr("Reset to default"))
|
||||
self.resetButton.setIcon(self.mainTheme.getIcon("revert"))
|
||||
self.resetButton.setIcon(CONFIG.theme.getIcon("revert"))
|
||||
self.resetButton.clicked.connect(lambda: self._setSelectedMode(self.F_FILTERED))
|
||||
|
||||
self.modeBox = QHBoxLayout()
|
||||
@@ -384,7 +379,7 @@ class _FilterTab(QWidget):
|
||||
# Assemble GUI
|
||||
# ============
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
|
||||
self.selectionBox = QVBoxLayout()
|
||||
self.selectionBox.addWidget(self.optTree)
|
||||
@@ -450,7 +445,7 @@ class _FilterTab(QWidget):
|
||||
logger.debug("Building project tree")
|
||||
self._treeMap = {}
|
||||
self.optTree.clear()
|
||||
for nwItem in self.theProject.getProjectItems():
|
||||
for nwItem in self.mainGui.project.getProjectItems():
|
||||
|
||||
tHandle = nwItem.itemHandle
|
||||
pHandle = nwItem.itemParent
|
||||
@@ -466,7 +461,7 @@ class _FilterTab(QWidget):
|
||||
continue
|
||||
|
||||
hLevel = nwItem.mainHeading
|
||||
itemIcon = self.mainTheme.getItemIcon(
|
||||
itemIcon = CONFIG.theme.getItemIcon(
|
||||
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
|
||||
)
|
||||
|
||||
@@ -480,7 +475,7 @@ class _FilterTab(QWidget):
|
||||
trItem.setText(self.C_NAME, nwItem.itemName)
|
||||
trItem.setData(self.C_DATA, self.D_HANDLE, tHandle)
|
||||
trItem.setData(self.C_DATA, self.D_FILE, isFile)
|
||||
trItem.setIcon(self.C_ACTIVE, self.mainTheme.getIcon(iconName))
|
||||
trItem.setIcon(self.C_ACTIVE, CONFIG.theme.getIcon(iconName))
|
||||
|
||||
trItem.setTextAlignment(self.C_NAME, Qt.AlignLeft)
|
||||
|
||||
@@ -504,19 +499,19 @@ class _FilterTab(QWidget):
|
||||
self.filterOpt.clear()
|
||||
self.filterOpt.addLabel(self._build.getLabel("filter"))
|
||||
self.filterOpt.addItem(
|
||||
self.mainTheme.getIcon("proj_scene"),
|
||||
CONFIG.theme.getIcon("proj_scene"),
|
||||
self._build.getLabel("filter.includeNovel"),
|
||||
"doc:filter.includeNovel",
|
||||
default=self._build.getBool("filter.includeNovel")
|
||||
)
|
||||
self.filterOpt.addItem(
|
||||
self.mainTheme.getIcon("proj_note"),
|
||||
CONFIG.theme.getIcon("proj_note"),
|
||||
self._build.getLabel("filter.includeNotes"),
|
||||
"doc:filter.includeNotes",
|
||||
default=self._build.getBool("filter.includeNotes")
|
||||
)
|
||||
self.filterOpt.addItem(
|
||||
self.mainTheme.getIcon("unchecked"),
|
||||
CONFIG.theme.getIcon("unchecked"),
|
||||
self._build.getLabel("filter.includeInactive"),
|
||||
"doc:filter.includeInactive",
|
||||
default=self._build.getBool("filter.includeInactive")
|
||||
@@ -526,9 +521,9 @@ class _FilterTab(QWidget):
|
||||
|
||||
# Root Classes
|
||||
self.filterOpt.addLabel(self.tr("Select Root Folders"))
|
||||
for tHandle, nwItem in self.theProject.tree.iterRoots(None):
|
||||
for tHandle, nwItem in self.mainGui.project.tree.iterRoots(None):
|
||||
if not nwItem.isInactiveClass():
|
||||
itemIcon = self.mainTheme.getItemIcon(
|
||||
itemIcon = CONFIG.theme.getItemIcon(
|
||||
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout
|
||||
)
|
||||
self.filterOpt.addItem(
|
||||
@@ -562,7 +557,7 @@ class _FilterTab(QWidget):
|
||||
|
||||
def _setTreeItemMode(self) -> None:
|
||||
"""Update the filtered mode icon on all items."""
|
||||
filtered = self._build.buildItemFilter(self.theProject)
|
||||
filtered = self._build.buildItemFilter(self.mainGui.project)
|
||||
for tHandle, item in self._treeMap.items():
|
||||
allow, mode = filtered.get(tHandle, (False, FilterMode.UNKNOWN))
|
||||
if mode == FilterMode.INCLUDED:
|
||||
@@ -602,14 +597,12 @@ class _HeadingsTab(QWidget):
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
|
||||
super().__init__(parent=buildMain)
|
||||
|
||||
self.mainGui = buildMain.mainGui
|
||||
self.mainTheme = buildMain.mainGui.mainTheme
|
||||
self.theProject = buildMain.mainGui.theProject
|
||||
self.mainGui = buildMain.mainGui
|
||||
|
||||
self._build = build
|
||||
self._editing = 0
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
vSp = CONFIG.pxInt(12)
|
||||
bSp = CONFIG.pxInt(6)
|
||||
|
||||
@@ -623,7 +616,7 @@ class _HeadingsTab(QWidget):
|
||||
self.fmtTitle = QLineEdit("")
|
||||
self.fmtTitle.setReadOnly(True)
|
||||
self.btnTitle = QToolButton()
|
||||
self.btnTitle.setIcon(self.mainTheme.getIcon("edit"))
|
||||
self.btnTitle.setIcon(CONFIG.theme.getIcon("edit"))
|
||||
self.btnTitle.clicked.connect(lambda: self._editHeading(self.EDIT_TITLE))
|
||||
|
||||
wrapTitle = QHBoxLayout()
|
||||
@@ -639,7 +632,7 @@ class _HeadingsTab(QWidget):
|
||||
self.fmtChapter = QLineEdit("")
|
||||
self.fmtChapter.setReadOnly(True)
|
||||
self.btnChapter = QToolButton()
|
||||
self.btnChapter.setIcon(self.mainTheme.getIcon("edit"))
|
||||
self.btnChapter.setIcon(CONFIG.theme.getIcon("edit"))
|
||||
self.btnChapter.clicked.connect(lambda: self._editHeading(self.EDIT_CHAPTER))
|
||||
|
||||
wrapChapter = QHBoxLayout()
|
||||
@@ -655,7 +648,7 @@ class _HeadingsTab(QWidget):
|
||||
self.fmtUnnumbered = QLineEdit("")
|
||||
self.fmtUnnumbered.setReadOnly(True)
|
||||
self.btnUnnumbered = QToolButton()
|
||||
self.btnUnnumbered.setIcon(self.mainTheme.getIcon("edit"))
|
||||
self.btnUnnumbered.setIcon(CONFIG.theme.getIcon("edit"))
|
||||
self.btnUnnumbered.clicked.connect(lambda: self._editHeading(self.EDIT_UNNUM))
|
||||
|
||||
wrapUnnumbered = QHBoxLayout()
|
||||
@@ -672,7 +665,7 @@ class _HeadingsTab(QWidget):
|
||||
self.fmtScene = QLineEdit("")
|
||||
self.fmtScene.setReadOnly(True)
|
||||
self.btnScene = QToolButton()
|
||||
self.btnScene.setIcon(self.mainTheme.getIcon("edit"))
|
||||
self.btnScene.setIcon(CONFIG.theme.getIcon("edit"))
|
||||
self.btnScene.clicked.connect(lambda: self._editHeading(self.EDIT_SCENE))
|
||||
self.hdeScene = QLabel(self.tr("Hide"))
|
||||
self.hdeScene.setToolTip(sceneHideTip)
|
||||
@@ -699,7 +692,7 @@ class _HeadingsTab(QWidget):
|
||||
self.fmtSection = QLineEdit("")
|
||||
self.fmtSection.setReadOnly(True)
|
||||
self.btnSection = QToolButton()
|
||||
self.btnSection.setIcon(self.mainTheme.getIcon("edit"))
|
||||
self.btnSection.setIcon(CONFIG.theme.getIcon("edit"))
|
||||
self.btnSection.clicked.connect(lambda: self._editHeading(self.EDIT_SECTION))
|
||||
self.hdeSection = QLabel(self.tr("Hide"))
|
||||
self.hdeSection.setToolTip(sectionHideTip)
|
||||
@@ -729,7 +722,7 @@ class _HeadingsTab(QWidget):
|
||||
self.editTextBox.setFixedHeight(5*iPx)
|
||||
self.editTextBox.setEnabled(False)
|
||||
|
||||
self.formSyntax = _HeadingSyntaxHighlighter(self.editTextBox.document(), self.mainTheme)
|
||||
self.formSyntax = _HeadingSyntaxHighlighter(self.editTextBox.document())
|
||||
|
||||
self.menuInsert = QMenu()
|
||||
self.aInsTitle = self.menuInsert.addAction(self.tr("Title"))
|
||||
@@ -872,12 +865,12 @@ class _HeadingsTab(QWidget):
|
||||
|
||||
class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
|
||||
|
||||
def __init__(self, document: QTextDocument, mainTheme: GuiTheme) -> None:
|
||||
def __init__(self, document: QTextDocument) -> None:
|
||||
super().__init__(document)
|
||||
self._fmtSymbol = QTextCharFormat()
|
||||
self._fmtSymbol.setForeground(QColor(*mainTheme.colHead))
|
||||
self._fmtSymbol.setForeground(QColor(*CONFIG.theme.colHead))
|
||||
self._fmtFormat = QTextCharFormat()
|
||||
self._fmtFormat.setForeground(QColor(*mainTheme.colEmph))
|
||||
self._fmtFormat.setForeground(QColor(*CONFIG.theme.colEmph))
|
||||
return
|
||||
|
||||
def highlightBlock(self, text: str) -> None:
|
||||
@@ -901,12 +894,9 @@ class _ContentTab(QWidget):
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
|
||||
super().__init__(parent=buildMain)
|
||||
|
||||
self.mainGui = buildMain.mainGui
|
||||
self.mainTheme = buildMain.mainGui.mainTheme
|
||||
|
||||
self._build = build
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
|
||||
# Left Form
|
||||
# =========
|
||||
@@ -973,16 +963,15 @@ class _FormatTab(QWidget):
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
|
||||
super().__init__(parent=buildMain)
|
||||
|
||||
self.buildMain = buildMain
|
||||
self.mainGui = buildMain.mainGui
|
||||
self.mainTheme = buildMain.mainGui.mainTheme
|
||||
self.buildMain = buildMain
|
||||
self.mainGui = buildMain.mainGui
|
||||
|
||||
self._build = build
|
||||
self._unitScale = 1.0
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
spW = 6*self.mainTheme.textNWidth
|
||||
dbW = 8*self.mainTheme.textNWidth
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
spW = 6*CONFIG.theme.textNWidth
|
||||
dbW = 8*CONFIG.theme.textNWidth
|
||||
|
||||
# Text Format Form
|
||||
# ================
|
||||
@@ -1003,7 +992,7 @@ class _FormatTab(QWidget):
|
||||
self.textFont = QLineEdit()
|
||||
self.textFont.setReadOnly(True)
|
||||
self.btnTextFont = QPushButton("...")
|
||||
self.btnTextFont.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
|
||||
self.btnTextFont.setMaximumWidth(int(2.5*CONFIG.theme.getTextWidth("...")))
|
||||
self.btnTextFont.clicked.connect(self._selectFont)
|
||||
self.formFormat.addRow(
|
||||
self._build.getLabel("format.textFont"), self.textFont, button=self.btnTextFont
|
||||
@@ -1287,12 +1276,9 @@ class _OutputTab(QWidget):
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
|
||||
super().__init__(parent=buildMain)
|
||||
|
||||
self.mainGui = buildMain.mainGui
|
||||
self.mainTheme = buildMain.mainGui.mainTheme
|
||||
|
||||
self._build = build
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
iPx = CONFIG.theme.baseIconSize
|
||||
|
||||
# Left Form
|
||||
# =========
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – GUI New Project Wizard
|
||||
====================================
|
||||
GUI classes for the new project wizard dialog
|
||||
|
||||
File History:
|
||||
Created: 2020-07-11 [0.10.1]
|
||||
@@ -22,6 +21,7 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import logging
|
||||
@@ -53,10 +53,9 @@ class GuiProjectWizard(QWizard):
|
||||
logger.debug("Create: GuiProjectWizard")
|
||||
self.setObjectName("GuiProjectWizard")
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.mainGui = mainGui
|
||||
|
||||
self.sideImage = self.mainTheme.loadDecoration(
|
||||
self.sideImage = CONFIG.theme.loadDecoration(
|
||||
"wiz-back", None, CONFIG.pxInt(370)
|
||||
)
|
||||
self.setWizardStyle(QWizard.ModernStyle)
|
||||
@@ -92,9 +91,6 @@ class ProjWizardIntroPage(QWizardPage):
|
||||
def __init__(self, theWizard):
|
||||
super().__init__()
|
||||
|
||||
self.theWizard = theWizard
|
||||
self.mainTheme = theWizard.mainTheme
|
||||
|
||||
self.setTitle(self.tr("Create New Project"))
|
||||
self.theText = QLabel(self.tr(
|
||||
"Provide at least a project name. The project name should not "
|
||||
@@ -108,7 +104,7 @@ class ProjWizardIntroPage(QWizardPage):
|
||||
"Peter Mitterhofer", "CC BY-SA 4.0"
|
||||
))
|
||||
lblFont = self.imgCredit.font()
|
||||
lblFont.setPointSizeF(0.6*self.mainTheme.fontPointSize)
|
||||
lblFont.setPointSizeF(0.6*CONFIG.theme.fontPointSize)
|
||||
self.imgCredit.setFont(lblFont)
|
||||
|
||||
xW = CONFIG.pxInt(300)
|
||||
@@ -160,9 +156,6 @@ class ProjWizardFolderPage(QWizardPage):
|
||||
def __init__(self, theWizard):
|
||||
super().__init__()
|
||||
|
||||
self.theWizard = theWizard
|
||||
self.mainTheme = theWizard.mainTheme
|
||||
|
||||
self.setTitle(self.tr("Select Project Folder"))
|
||||
self.theText = QLabel(self.tr(
|
||||
"Select a location to store the project. A new project folder "
|
||||
@@ -179,7 +172,7 @@ class ProjWizardFolderPage(QWizardPage):
|
||||
self.projPath.setPlaceholderText(self.tr("Required"))
|
||||
|
||||
self.browseButton = QPushButton("...")
|
||||
self.browseButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
|
||||
self.browseButton.setMaximumWidth(int(2.5*CONFIG.theme.getTextWidth("...")))
|
||||
self.browseButton.clicked.connect(self._doBrowse)
|
||||
|
||||
self.errLabel = QLabel("")
|
||||
@@ -257,8 +250,6 @@ class ProjWizardPopulatePage(QWizardPage):
|
||||
def __init__(self, theWizard):
|
||||
super().__init__()
|
||||
|
||||
self.theWizard = theWizard
|
||||
|
||||
self.setTitle(self.tr("Populate Project"))
|
||||
self.theText = QLabel(self.tr(
|
||||
"Choose how to pre-fill the project. Either with a minimal set of "
|
||||
@@ -312,8 +303,6 @@ class ProjWizardCustomPage(QWizardPage):
|
||||
def __init__(self, theWizard):
|
||||
super().__init__()
|
||||
|
||||
self.theWizard = theWizard
|
||||
|
||||
self.setTitle(self.tr("Custom Project Options"))
|
||||
self.theText = QLabel(self.tr(
|
||||
"Select which additional elements to populate the project with. "
|
||||
@@ -412,8 +401,6 @@ class ProjWizardFinalPage(QWizardPage):
|
||||
def __init__(self, theWizard):
|
||||
super().__init__()
|
||||
|
||||
self.theWizard = theWizard
|
||||
|
||||
self.setTitle(self.tr("Summary"))
|
||||
self.theText = QLabel("")
|
||||
self.theText.setWordWrap(True)
|
||||
|
||||
@@ -72,16 +72,14 @@ class GuiWritingStats(QDialog):
|
||||
if CONFIG.osDarwin:
|
||||
self.setWindowFlag(Qt.WindowType.Tool)
|
||||
|
||||
self.mainGui = mainGui
|
||||
self.mainTheme = mainGui.mainTheme
|
||||
self.theProject = mainGui.theProject
|
||||
self.mainGui = mainGui
|
||||
|
||||
self.logData = []
|
||||
self.filterData = []
|
||||
self.timeFilter = 0.0
|
||||
self.wordOffset = 0
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
|
||||
self.setWindowTitle(self.tr("Writing Statistics"))
|
||||
self.setMinimumWidth(CONFIG.pxInt(420))
|
||||
@@ -134,7 +132,7 @@ class GuiWritingStats(QDialog):
|
||||
self.listBox.setSortingEnabled(True)
|
||||
|
||||
# Word Bar
|
||||
self.barHeight = int(round(0.5*self.mainTheme.fontPixelSize))
|
||||
self.barHeight = int(round(0.5*CONFIG.theme.fontPixelSize))
|
||||
self.barWidth = CONFIG.pxInt(200)
|
||||
self.barImage = QPixmap(self.barHeight, self.barHeight)
|
||||
self.barImage.fill(self.palette().highlight().color())
|
||||
@@ -145,27 +143,27 @@ class GuiWritingStats(QDialog):
|
||||
self.infoBox.setLayout(self.infoForm)
|
||||
|
||||
self.labelTotal = QLabel(formatTime(0))
|
||||
self.labelTotal.setFont(self.mainTheme.guiFontFixed)
|
||||
self.labelTotal.setFont(CONFIG.theme.guiFontFixed)
|
||||
self.labelTotal.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
|
||||
|
||||
self.labelIdleT = QLabel(formatTime(0))
|
||||
self.labelIdleT.setFont(self.mainTheme.guiFontFixed)
|
||||
self.labelIdleT.setFont(CONFIG.theme.guiFontFixed)
|
||||
self.labelIdleT.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
|
||||
|
||||
self.labelFilter = QLabel(formatTime(0))
|
||||
self.labelFilter.setFont(self.mainTheme.guiFontFixed)
|
||||
self.labelFilter.setFont(CONFIG.theme.guiFontFixed)
|
||||
self.labelFilter.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
|
||||
|
||||
self.novelWords = QLabel("0")
|
||||
self.novelWords.setFont(self.mainTheme.guiFontFixed)
|
||||
self.novelWords.setFont(CONFIG.theme.guiFontFixed)
|
||||
self.novelWords.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
|
||||
|
||||
self.notesWords = QLabel("0")
|
||||
self.notesWords.setFont(self.mainTheme.guiFontFixed)
|
||||
self.notesWords.setFont(CONFIG.theme.guiFontFixed)
|
||||
self.notesWords.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
|
||||
|
||||
self.totalWords = QLabel("0")
|
||||
self.totalWords.setFont(self.mainTheme.guiFontFixed)
|
||||
self.totalWords.setFont(CONFIG.theme.guiFontFixed)
|
||||
self.totalWords.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
|
||||
|
||||
lblTTime = QLabel(self.tr("Total Time:"))
|
||||
@@ -192,7 +190,7 @@ class GuiWritingStats(QDialog):
|
||||
self.infoForm.setRowStretch(6, 1)
|
||||
|
||||
# Filter Options
|
||||
sPx = self.mainTheme.baseIconSize
|
||||
sPx = CONFIG.theme.baseIconSize
|
||||
|
||||
self.filterBox = QGroupBox(self.tr("Filters"), self)
|
||||
self.filterForm = QGridLayout(self)
|
||||
@@ -335,7 +333,7 @@ class GuiWritingStats(QDialog):
|
||||
showIdleTime = self.showIdleTime.isChecked()
|
||||
histMax = self.histMax.value()
|
||||
|
||||
pOptions = self.theProject.options
|
||||
pOptions = self.mainGui.project.options
|
||||
pOptions.setValue("GuiWritingStats", "winWidth", winWidth)
|
||||
pOptions.setValue("GuiWritingStats", "winHeight", winHeight)
|
||||
pOptions.setValue("GuiWritingStats", "widthCol0", widthCol0)
|
||||
@@ -443,7 +441,7 @@ class GuiWritingStats(QDialog):
|
||||
ttTime = 0
|
||||
ttIdle = 0
|
||||
|
||||
for record in self.theProject.session.iterRecords():
|
||||
for record in self.mainGui.project.session.iterRecords():
|
||||
rType = record.get("type")
|
||||
if rType == "initial":
|
||||
self.wordOffset = checkInt(record.get("offset"), 0)
|
||||
@@ -589,13 +587,13 @@ class GuiWritingStats(QDialog):
|
||||
newItem.setTextAlignment(self.C_COUNT, Qt.AlignRight)
|
||||
newItem.setTextAlignment(self.C_BAR, Qt.AlignLeft | Qt.AlignVCenter)
|
||||
|
||||
newItem.setFont(self.C_TIME, self.mainTheme.guiFontFixed)
|
||||
newItem.setFont(self.C_LENGTH, self.mainTheme.guiFontFixed)
|
||||
newItem.setFont(self.C_COUNT, self.mainTheme.guiFontFixed)
|
||||
newItem.setFont(self.C_TIME, CONFIG.theme.guiFontFixed)
|
||||
newItem.setFont(self.C_LENGTH, CONFIG.theme.guiFontFixed)
|
||||
newItem.setFont(self.C_COUNT, CONFIG.theme.guiFontFixed)
|
||||
if showIdleTime:
|
||||
newItem.setFont(self.C_IDLE, self.mainTheme.guiFontFixed)
|
||||
newItem.setFont(self.C_IDLE, CONFIG.theme.guiFontFixed)
|
||||
else:
|
||||
newItem.setFont(self.C_IDLE, self.mainTheme.guiFont)
|
||||
newItem.setFont(self.C_IDLE, CONFIG.theme.guiFont)
|
||||
|
||||
self.listBox.addTopLevelItem(newItem)
|
||||
self.timeFilter += sDiff
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.1-beta1" hexVersion="0x020100b1" fileVersion="1.5" fileRevision="1" timeStamp="2023-07-30 14:08:40">
|
||||
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1514" autoCount="237" editTime="75228">
|
||||
<novelWriterXML appVersion="2.1-beta1" hexVersion="0x020100b1" fileVersion="1.5" fileRevision="1" timeStamp="2023-08-08 22:19:23">
|
||||
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1517" autoCount="237" editTime="75241">
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
<author>Jane Smith</author>
|
||||
|
||||
+6
-1
@@ -31,8 +31,9 @@ class MockGuiMain(QObject):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self._project = None
|
||||
|
||||
self.hasProject = True
|
||||
self.theProject = None
|
||||
self.mainStatus = MockStatusBar()
|
||||
self.projPath = ""
|
||||
|
||||
@@ -43,6 +44,10 @@ class MockGuiMain(QObject):
|
||||
|
||||
return
|
||||
|
||||
@property
|
||||
def project(self):
|
||||
return self._project
|
||||
|
||||
def postLaunchTasks(self, cmdOpen):
|
||||
return
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[Meta]
|
||||
timestamp = 2023-08-02 14:53:36
|
||||
timestamp = 2023-08-08 19:01:25
|
||||
|
||||
[Main]
|
||||
theme = default
|
||||
@@ -10,7 +10,7 @@ localisation = en_GB
|
||||
hidevscroll = False
|
||||
hidehscroll = False
|
||||
lastnotes = 0x0
|
||||
lastpath = /home/vkbo
|
||||
lastpath =
|
||||
|
||||
[Sizes]
|
||||
mainwindow = 1200, 650
|
||||
|
||||
@@ -111,7 +111,7 @@ def testBaseConfig_InitLoadSave(monkeypatch, fncPath, tstPaths):
|
||||
|
||||
# Check that we have a default file
|
||||
copyfile(confFile, testFile)
|
||||
ignore = ("timestamp", "lastnotes", "localisation", "lastpath")
|
||||
ignore = ("timestamp", "lastnotes", "localisation", "lastpath", "backuppath")
|
||||
assert cmpFiles(testFile, compFile, ignoreStart=ignore)
|
||||
tstConf.errorText() # This clears the error cache
|
||||
|
||||
@@ -366,14 +366,6 @@ def testBaseConfig_Internal(monkeypatch, fncPath):
|
||||
# Function _packList
|
||||
assert tstConf._packList(["A", 1, 2.0, None, False]) == "A, 1, 2.0, None, False"
|
||||
|
||||
# Function _checkNone
|
||||
assert tstConf._checkNone(None) is None
|
||||
assert tstConf._checkNone("None") is None
|
||||
assert tstConf._checkNone("none") is None
|
||||
assert tstConf._checkNone("NONE") is None
|
||||
assert tstConf._checkNone("NoNe") is None
|
||||
assert tstConf._checkNone(123456) == 123456
|
||||
|
||||
# Function _checkOptionalPackages
|
||||
# (Assumes enchant package exists and is importable)
|
||||
tstConf._checkOptionalPackages()
|
||||
|
||||
@@ -590,10 +590,6 @@ def testCoreProject_Backup(monkeypatch, mockGUI, fncPath, tstPaths):
|
||||
# Invalid Settings
|
||||
# ================
|
||||
|
||||
# Invalid path
|
||||
CONFIG._backupPath = None
|
||||
assert theProject.backupProject(doNotify=False) is False
|
||||
|
||||
# Missing project name
|
||||
CONFIG._backupPath = tstPaths.tmpDir
|
||||
theProject.data.setName("")
|
||||
|
||||
@@ -344,7 +344,7 @@ def testCoreStatus_PackUnpack(mockRnd):
|
||||
|
||||
# Unpack
|
||||
theStatus = NWStatus(NWStatus.STATUS)
|
||||
assert theStatus.unpack({
|
||||
theStatus.unpack({
|
||||
statusKeys[0]: {"label": "New0", "colour": (100, 100, 100), "count": countTo[0]},
|
||||
statusKeys[1]: {"label": "New1", "colour": (150, 150, 150), "count": countTo[1]},
|
||||
statusKeys[2]: {"label": "New2", "colour": (200, 200, 200), "count": countTo[2]},
|
||||
|
||||
@@ -34,8 +34,6 @@ from novelwriter.dialogs.about import GuiAbout
|
||||
def testDlgAbout_NWDialog(qtbot, monkeypatch, nwGUI):
|
||||
"""Test the novelWriter about dialogs."""
|
||||
# NW About
|
||||
nwGUI.mainTheme.themeName = "A Theme"
|
||||
nwGUI.mainTheme.themeAuthor = "An Author"
|
||||
assert nwGUI.showAboutNWDialog(showNotes=True) is True
|
||||
|
||||
qtbot.waitUntil(lambda: getGuiItem("GuiAbout") is not None, timeout=1000)
|
||||
|
||||
@@ -35,7 +35,7 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
# Create a new project
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
theProject = nwGUI.theProject
|
||||
theProject = nwGUI.project
|
||||
projTree = nwGUI.projView.projTree
|
||||
|
||||
docText = (
|
||||
|
||||
@@ -54,7 +54,7 @@ def testDlgProjDetails_Dialog(qtbot, nwGUI, prjLipsum):
|
||||
assert projDet.tabMain.wordCountVal.text() == f"{3000:n}"
|
||||
assert projDet.tabMain.chapCountVal.text() == f"{3:n}"
|
||||
assert projDet.tabMain.sceneCountVal.text() == f"{5:n}"
|
||||
assert projDet.tabMain.revCountVal.text() == f"{nwGUI.theProject.data.saveCount:n}"
|
||||
assert projDet.tabMain.revCountVal.text() == f"{nwGUI.project.data.saveCount:n}"
|
||||
|
||||
assert projDet.tabMain.projPathVal.text() == str(prjLipsum)
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI):
|
||||
|
||||
# Pretend we have a project
|
||||
nwGUI.hasProject = True
|
||||
nwGUI.theProject.data.setSpellLang("en")
|
||||
nwGUI.project.data.setSpellLang("en")
|
||||
|
||||
# Get the dialog object
|
||||
nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger)
|
||||
@@ -95,7 +95,7 @@ def testDlgProjSettings_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockR
|
||||
CONFIG.setBackupPath(fncPath)
|
||||
|
||||
# Set some values
|
||||
theProject = nwGUI.theProject
|
||||
theProject = nwGUI.project
|
||||
theProject.data.setSpellLang("en")
|
||||
theProject.data.setAuthor("Jane Smith")
|
||||
theProject.data.setAutoReplace({"A": "B", "C": "D"})
|
||||
@@ -160,7 +160,7 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncPath, projPat
|
||||
CONFIG.setBackupPath(fncPath)
|
||||
|
||||
# Set some values
|
||||
theProject = nwGUI.theProject
|
||||
theProject = nwGUI.project
|
||||
theProject.tree[C.hTitlePage].setStatus(C.sFinished)
|
||||
theProject.tree[C.hChapterDoc].setStatus(C.sDraft)
|
||||
theProject.tree[C.hSceneDoc].setStatus(C.sDraft)
|
||||
@@ -361,7 +361,7 @@ def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, fncPath, projPath, mo
|
||||
CONFIG.setBackupPath(fncPath)
|
||||
|
||||
# Set some values
|
||||
theProject = nwGUI.theProject
|
||||
theProject = nwGUI.project
|
||||
theProject.data.setAutoReplace({
|
||||
"A": "B", "C": "D"
|
||||
})
|
||||
|
||||
@@ -55,7 +55,7 @@ def testDlgWordList_Dialog(qtbot, monkeypatch, nwGUI, projPath):
|
||||
assert wList.listBox.count() == 0
|
||||
|
||||
# Add words
|
||||
userDict = UserDictionary(nwGUI.theProject)
|
||||
userDict = UserDictionary(nwGUI.project)
|
||||
userDict.add("word_a")
|
||||
userDict.add("word_c")
|
||||
userDict.add("word_g")
|
||||
|
||||
@@ -163,10 +163,10 @@ def testGuiEditor_SaveText(qtbot, monkeypatch, caplog, nwGUI, projPath, ipsumTex
|
||||
assert "Could not save document." in caplog.text
|
||||
|
||||
# Change header level
|
||||
assert nwGUI.theProject.tree[C.hSceneDoc].itemLayout == nwItemLayout.DOCUMENT
|
||||
assert nwGUI.project.tree[C.hSceneDoc].itemLayout == nwItemLayout.DOCUMENT
|
||||
nwGUI.docEditor.replaceText(longText[1:])
|
||||
assert nwGUI.docEditor.saveText() is True
|
||||
assert nwGUI.theProject.tree[C.hSceneDoc].itemLayout == nwItemLayout.DOCUMENT
|
||||
assert nwGUI.project.tree[C.hSceneDoc].itemLayout == nwItemLayout.DOCUMENT
|
||||
|
||||
# Regular save
|
||||
assert nwGUI.docEditor.saveText() is True
|
||||
@@ -203,9 +203,9 @@ def testGuiEditor_MetaData(qtbot, nwGUI, projPath, mockRnd):
|
||||
assert nwGUI.docEditor.setCursorPosition(None) is False
|
||||
assert nwGUI.docEditor.setCursorPosition(10) is True
|
||||
assert nwGUI.docEditor.getCursorPosition() == 10
|
||||
assert nwGUI.theProject.tree[C.hSceneDoc].cursorPos != 10
|
||||
assert nwGUI.project.tree[C.hSceneDoc].cursorPos != 10
|
||||
nwGUI.docEditor.saveCursorPosition()
|
||||
assert nwGUI.theProject.tree[C.hSceneDoc].cursorPos == 10
|
||||
assert nwGUI.project.tree[C.hSceneDoc].cursorPos == 10
|
||||
|
||||
assert nwGUI.docEditor.setCursorLine(None) is False
|
||||
assert nwGUI.docEditor.setCursorLine(3) is True
|
||||
@@ -1067,7 +1067,7 @@ def testGuiEditor_Tags(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
|
||||
# Create Character
|
||||
theText = "### Jane Doe\n\n@tag: Jane\n\n" + ipsumText[1] + "\n\n"
|
||||
cHandle = nwGUI.theProject.newFile("Jane Doe", C.hCharRoot)
|
||||
cHandle = nwGUI.project.newFile("Jane Doe", C.hCharRoot)
|
||||
assert nwGUI.openDocument(cHandle) is True
|
||||
assert nwGUI.docEditor.replaceText(theText) is True
|
||||
assert nwGUI.saveDocument() is True
|
||||
@@ -1145,8 +1145,8 @@ def testGuiEditor_WordCounters(qtbot, monkeypatch, nwGUI, projPath, ipsumText, m
|
||||
assert nwGUI.docEditor.docFooter.wordsText.text() == "Words: 0 (+0)"
|
||||
|
||||
# Open a document and populate it
|
||||
nwGUI.theProject.tree[C.hSceneDoc]._initCount = 0 # Clear item's count
|
||||
nwGUI.theProject.tree[C.hSceneDoc]._wordCount = 0 # Clear item's count
|
||||
nwGUI.project.tree[C.hSceneDoc]._initCount = 0 # Clear item's count
|
||||
nwGUI.project.tree[C.hSceneDoc]._wordCount = 0 # Clear item's count
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
|
||||
theText = "\n\n".join(ipsumText)
|
||||
@@ -1170,9 +1170,9 @@ def testGuiEditor_WordCounters(qtbot, monkeypatch, nwGUI, projPath, ipsumText, m
|
||||
|
||||
nwGUI.docEditor.wCounterDoc.run()
|
||||
# nwGUI.docEditor._updateDocCounts(cC, wC, pC)
|
||||
assert nwGUI.theProject.tree[C.hSceneDoc]._charCount == cC
|
||||
assert nwGUI.theProject.tree[C.hSceneDoc]._wordCount == wC
|
||||
assert nwGUI.theProject.tree[C.hSceneDoc]._paraCount == pC
|
||||
assert nwGUI.project.tree[C.hSceneDoc]._charCount == cC
|
||||
assert nwGUI.project.tree[C.hSceneDoc]._wordCount == wC
|
||||
assert nwGUI.project.tree[C.hSceneDoc]._paraCount == pC
|
||||
assert nwGUI.docEditor.docFooter.wordsText.text() == f"Words: {wC} (+{wC})"
|
||||
|
||||
# Select all text
|
||||
|
||||
@@ -40,8 +40,8 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum):
|
||||
|
||||
# Rebuild the index
|
||||
nwGUI.mainMenu.aRebuildIndex.activate(QAction.Trigger)
|
||||
assert nwGUI.theProject.index._tagsIndex._tags != {}
|
||||
assert nwGUI.theProject.index._itemIndex._items != {}
|
||||
assert nwGUI.project.index._tagsIndex._tags != {}
|
||||
assert nwGUI.project.index._itemIndex._items != {}
|
||||
|
||||
# Select a document in the project tree
|
||||
nwGUI.projView.setSelectedHandle("88243afbe5ed8")
|
||||
@@ -128,7 +128,7 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum):
|
||||
nwGUI.docViewer.reloadText()
|
||||
|
||||
# Change document title
|
||||
nwItem = nwGUI.theProject.tree["4c4f28287af27"]
|
||||
nwItem = nwGUI.project.tree["4c4f28287af27"]
|
||||
nwItem.setName("Test Title")
|
||||
assert nwItem.itemName == "Test Title"
|
||||
nwGUI.docViewer.updateDocInfo("4c4f28287af27")
|
||||
|
||||
@@ -202,14 +202,14 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
|
||||
assert nwGUI.saveProject()
|
||||
assert nwGUI.closeProject()
|
||||
|
||||
assert len(nwGUI.theProject.tree) == 0
|
||||
assert len(nwGUI.theProject.tree._treeOrder) == 0
|
||||
assert len(nwGUI.theProject.tree._treeRoots) == 0
|
||||
assert nwGUI.theProject.tree.trashRoot() is None
|
||||
assert nwGUI.theProject.data.name == ""
|
||||
assert nwGUI.theProject.data.title == ""
|
||||
assert nwGUI.theProject.data.author == ""
|
||||
assert nwGUI.theProject.data.spellCheck is False
|
||||
assert len(nwGUI.project.tree) == 0
|
||||
assert len(nwGUI.project.tree._treeOrder) == 0
|
||||
assert len(nwGUI.project.tree._treeRoots) == 0
|
||||
assert nwGUI.project.tree.trashRoot() is None
|
||||
assert nwGUI.project.data.name == ""
|
||||
assert nwGUI.project.data.title == ""
|
||||
assert nwGUI.project.data.author == ""
|
||||
assert nwGUI.project.data.spellCheck is False
|
||||
|
||||
# Check the files
|
||||
projFile = projPath / "nwProject.nwx"
|
||||
@@ -222,14 +222,14 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
|
||||
assert nwGUI.openProject(projPath)
|
||||
|
||||
# Check that we loaded the data
|
||||
assert len(nwGUI.theProject.tree) == 8
|
||||
assert len(nwGUI.theProject.tree._treeOrder) == 8
|
||||
assert len(nwGUI.theProject.tree._treeRoots) == 4
|
||||
assert nwGUI.theProject.tree.trashRoot() is None
|
||||
assert nwGUI.theProject.data.name == "New Project"
|
||||
assert nwGUI.theProject.data.title == "New Novel"
|
||||
assert nwGUI.theProject.data.author == "Jane Doe"
|
||||
assert nwGUI.theProject.data.spellCheck is False
|
||||
assert len(nwGUI.project.tree) == 8
|
||||
assert len(nwGUI.project.tree._treeOrder) == 8
|
||||
assert len(nwGUI.project.tree._treeRoots) == 4
|
||||
assert nwGUI.project.tree.trashRoot() is None
|
||||
assert nwGUI.project.data.name == "New Project"
|
||||
assert nwGUI.project.data.title == "New Novel"
|
||||
assert nwGUI.project.data.author == "Jane Doe"
|
||||
assert nwGUI.project.data.spellCheck is False
|
||||
|
||||
# Check that tree items have been created
|
||||
assert nwGUI.projView.projTree._getTreeItem(C.hNovelRoot) is not None
|
||||
|
||||
@@ -48,7 +48,7 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
nwGUI.projView.projTree._getTreeItem(C.hCharRoot).setSelected(True)
|
||||
nwGUI.projView.projTree.newTreeItem(nwItemType.FILE)
|
||||
|
||||
contentPath = nwGUI.theProject.storage.contentPath
|
||||
contentPath = nwGUI.project.storage.contentPath
|
||||
assert isinstance(contentPath, Path)
|
||||
|
||||
(contentPath / "0000000000010.nwd").write_text(
|
||||
|
||||
@@ -71,7 +71,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, projPath):
|
||||
|
||||
# Option State
|
||||
# ============
|
||||
pOptions = nwGUI.theProject.options
|
||||
pOptions = nwGUI.project.options
|
||||
colNames = [h.name for h in nwOutline]
|
||||
colItems = [h for h in nwOutline]
|
||||
colWidth = {h: outlineTree.DEF_WIDTH[h] for h in nwOutline}
|
||||
@@ -181,7 +181,7 @@ def testGuiOutline_Content(qtbot, nwGUI, prjLipsum):
|
||||
assert outlineBar.novelValue.itemData(2) == "" # All novels
|
||||
|
||||
# Add a second novel folder
|
||||
newHandle = nwGUI.theProject.newRoot(nwItemClass.NOVEL)
|
||||
newHandle = nwGUI.project.newRoot(nwItemClass.NOVEL)
|
||||
nwGUI.projView.projTree.revealNewTreeItem(newHandle)
|
||||
|
||||
# Check new values in dropdown list
|
||||
@@ -198,7 +198,7 @@ def testGuiOutline_Content(qtbot, nwGUI, prjLipsum):
|
||||
("Section 4", 4),
|
||||
]
|
||||
for dTitle, hLevel in docList:
|
||||
aHandle = nwGUI.theProject.newFile(dTitle, newHandle)
|
||||
aHandle = nwGUI.project.newFile(dTitle, newHandle)
|
||||
hHash = "#"*hLevel
|
||||
writeFile(prjLipsum / "content" / f"{aHandle}.nwd", f"{hHash} {dTitle}\n\n")
|
||||
nwGUI.projView.projTree.revealNewTreeItem(aHandle)
|
||||
|
||||
@@ -46,7 +46,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
|
||||
|
||||
projView = nwGUI.projView
|
||||
projTree = nwGUI.projView.projTree
|
||||
theProject = nwGUI.theProject
|
||||
theProject = nwGUI.project
|
||||
|
||||
# Try to add item with no project
|
||||
assert projView.projTree.newTreeItem(nwItemType.FILE) is False
|
||||
@@ -260,19 +260,19 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
# ===========
|
||||
|
||||
projView.setSelectedHandle(C.hNovelRoot)
|
||||
assert nwGUI.theProject.tree._treeOrder.index(C.hNovelRoot) == 0
|
||||
assert nwGUI.project.tree._treeOrder.index(C.hNovelRoot) == 0
|
||||
|
||||
# Move novel folder up
|
||||
assert projTree.moveTreeItem(-1) is False
|
||||
assert nwGUI.theProject.tree._treeOrder.index(C.hNovelRoot) == 0
|
||||
assert nwGUI.project.tree._treeOrder.index(C.hNovelRoot) == 0
|
||||
|
||||
# Move novel folder down
|
||||
assert projTree.moveTreeItem(1) is True
|
||||
assert nwGUI.theProject.tree._treeOrder.index(C.hNovelRoot) == 1
|
||||
assert nwGUI.project.tree._treeOrder.index(C.hNovelRoot) == 1
|
||||
|
||||
# Move novel folder up again
|
||||
assert projTree.moveTreeItem(-1) is True
|
||||
assert nwGUI.theProject.tree._treeOrder.index(C.hNovelRoot) == 0
|
||||
assert nwGUI.project.tree._treeOrder.index(C.hNovelRoot) == 0
|
||||
|
||||
# Clean up
|
||||
# qtbot.stop()
|
||||
@@ -348,7 +348,7 @@ def testGuiProjTree_RequestDeleteItem(qtbot, caplog, monkeypatch, nwGUI, projPat
|
||||
C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
||||
"0000000000010"
|
||||
]
|
||||
trashHandle = nwGUI.theProject.tree.trashRoot()
|
||||
trashHandle = nwGUI.project.tree.trashRoot()
|
||||
assert projTree.getTreeFromHandle(trashHandle) == [
|
||||
trashHandle, "0000000000012", "0000000000011"
|
||||
]
|
||||
@@ -368,7 +368,7 @@ def testGuiProjTree_MoveItemToTrash(qtbot, caplog, monkeypatch, nwGUI, projPath,
|
||||
"""Test moving items to Trash."""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
|
||||
theProject = nwGUI.theProject
|
||||
theProject = nwGUI.project
|
||||
projTree = nwGUI.projView.projTree
|
||||
|
||||
# Create a project
|
||||
@@ -420,7 +420,7 @@ def testGuiProjTree_PermanentlyDeleteItem(qtbot, caplog, monkeypatch, nwGUI, pro
|
||||
"""Test permanently deleting items."""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
|
||||
theProject = nwGUI.theProject
|
||||
theProject = nwGUI.project
|
||||
projTree = nwGUI.projView.projTree
|
||||
|
||||
# Create a project
|
||||
@@ -471,7 +471,7 @@ def testGuiProjTree_EmptyTrash(qtbot, caplog, monkeypatch, nwGUI, projPath, mock
|
||||
"""Test emptying Trash."""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
|
||||
theProject = nwGUI.theProject
|
||||
theProject = nwGUI.project
|
||||
projTree = nwGUI.projView.projTree
|
||||
|
||||
# No project open
|
||||
@@ -541,16 +541,16 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
projTree.setExpandedFromHandle(None, True)
|
||||
|
||||
projTree._addTrashRoot()
|
||||
hTrashRoot = projTree.theProject.tree.trashRoot()
|
||||
hTrashRoot = nwGUI.project.tree.trashRoot()
|
||||
|
||||
projTree.setSelectedHandle(C.hCharRoot)
|
||||
projTree.newTreeItem(nwItemType.FILE)
|
||||
projTree.setSelectedHandle(C.hNovelRoot)
|
||||
projTree.newTreeItem(nwItemType.FILE, isNote=True)
|
||||
|
||||
nwGUI.theProject.newFile("SubNote", hNovelNote)
|
||||
nwGUI.project.newFile("SubNote", hNovelNote)
|
||||
projTree.revealNewTreeItem(hSubNote)
|
||||
assert nwGUI.theProject.tree[hSubNote].itemParent == hNovelNote
|
||||
assert nwGUI.project.tree[hSubNote].itemParent == hNovelNote
|
||||
|
||||
def itemPos(tHandle):
|
||||
return projTree.visualItemRect(projTree._getTreeItem(tHandle)).center()
|
||||
@@ -578,7 +578,7 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
# Direct Edit Functions
|
||||
# =====================
|
||||
# Trigger the dedicated functions the menu entries connect to
|
||||
nwItem = projTree.theProject.tree[hNovelNote]
|
||||
nwItem = nwGUI.project.tree[hNovelNote]
|
||||
|
||||
# Toggle active flag
|
||||
assert nwItem.isActive is True
|
||||
@@ -619,17 +619,17 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
|
||||
projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT)
|
||||
assert nwGUI.theProject.tree[hNewFolderOne].isFolderType()
|
||||
assert nwGUI.project.tree[hNewFolderOne].isFolderType()
|
||||
|
||||
# Convert the first folder to a document
|
||||
projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT)
|
||||
assert nwGUI.theProject.tree[hNewFolderOne].isFileType()
|
||||
assert nwGUI.theProject.tree[hNewFolderOne].isDocumentLayout()
|
||||
assert nwGUI.project.tree[hNewFolderOne].isFileType()
|
||||
assert nwGUI.project.tree[hNewFolderOne].isDocumentLayout()
|
||||
|
||||
# Convert the second folder to a note
|
||||
projTree._covertFolderToFile(hNewFolderTwo, nwItemLayout.NOTE)
|
||||
assert nwGUI.theProject.tree[hNewFolderTwo].isFileType()
|
||||
assert nwGUI.theProject.tree[hNewFolderTwo].isNoteLayout()
|
||||
assert nwGUI.project.tree[hNewFolderTwo].isFileType()
|
||||
assert nwGUI.project.tree[hNewFolderTwo].isNoteLayout()
|
||||
|
||||
# qtbot.stop()
|
||||
|
||||
@@ -649,7 +649,7 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
|
||||
# Create a project
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
theProject = nwGUI.theProject
|
||||
theProject = nwGUI.project
|
||||
projTree = nwGUI.projView.projTree
|
||||
|
||||
mergedDoc1 = "0000000000014"
|
||||
@@ -751,7 +751,7 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
|
||||
# Create a project
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
theProject = nwGUI.theProject
|
||||
theProject = nwGUI.project
|
||||
projTree = nwGUI.projView.projTree
|
||||
|
||||
docText = (
|
||||
@@ -852,7 +852,7 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
|
||||
"""Test the duplicate items function."""
|
||||
# Create a project
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert len(nwGUI.theProject.tree) == 8
|
||||
assert len(nwGUI.project.tree) == 8
|
||||
|
||||
projTree = nwGUI.projView.projTree
|
||||
projTree._getTreeItem(C.hNovelRoot).setExpanded(True) # type: ignore
|
||||
@@ -860,28 +860,28 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
|
||||
|
||||
# Nothing to do
|
||||
assert projTree._duplicateFromHandle(C.hInvalid) is False
|
||||
assert len(nwGUI.theProject.tree) == 8
|
||||
assert len(nwGUI.project.tree) == 8
|
||||
|
||||
# Duplicate title page, but select no
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
|
||||
assert projTree._duplicateFromHandle(C.hTitlePage) is False
|
||||
assert len(nwGUI.theProject.tree) == 8
|
||||
assert len(nwGUI.project.tree) == 8
|
||||
|
||||
# Duplicate title page
|
||||
assert projTree._duplicateFromHandle(C.hTitlePage) is True
|
||||
assert len(nwGUI.theProject.tree) == 9
|
||||
assert len(nwGUI.project.tree) == 9
|
||||
|
||||
# Duplicate folder
|
||||
assert projTree._duplicateFromHandle(C.hChapterDir) is True
|
||||
assert len(nwGUI.theProject.tree) == 12
|
||||
assert len(nwGUI.project.tree) == 12
|
||||
|
||||
# Duplicate novel root
|
||||
assert projTree._duplicateFromHandle(C.hNovelRoot) is True
|
||||
assert len(nwGUI.theProject.tree) == 21
|
||||
assert len(nwGUI.project.tree) == 21
|
||||
|
||||
# Check tree order that all items are next to eachother
|
||||
assert nwGUI.theProject.tree._treeOrder == [
|
||||
assert nwGUI.project.tree._treeOrder == [
|
||||
C.hNovelRoot, C.hTitlePage, "0000000000010", C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
||||
"0000000000011", "0000000000012", "0000000000013", "0000000000014", "0000000000015",
|
||||
"0000000000016", "0000000000017", "0000000000018", "0000000000019", "000000000001a",
|
||||
@@ -889,7 +889,7 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
|
||||
]
|
||||
|
||||
# Make the duplicator stop early
|
||||
content = nwGUI.theProject.storage.contentPath
|
||||
content = nwGUI.project.storage.contentPath
|
||||
assert isinstance(content, Path)
|
||||
(content / "000000000001e.nwd").touch()
|
||||
assert (content / "000000000001e.nwd").exists()
|
||||
@@ -897,7 +897,7 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
|
||||
# Should only create the folder, and skip the two files because the
|
||||
# next handle is already a file
|
||||
assert projTree._duplicateFromHandle(C.hChapterDir) is True
|
||||
assert len(nwGUI.theProject.tree) == 22
|
||||
assert len(nwGUI.project.tree) == 22
|
||||
|
||||
# qtbot.stop()
|
||||
|
||||
@@ -938,13 +938,13 @@ def testGuiProjTree_Other(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mockRnd)
|
||||
assert projTree.revealNewTreeItem(C.hInvalid) is False
|
||||
|
||||
# Try to add an orphaned file to the tree
|
||||
nHandle = nwGUI.theProject.newFile("Test", C.hNovelRoot)
|
||||
nwGUI.theProject.tree[nHandle].setParent(None) # type: ignore
|
||||
nHandle = nwGUI.project.newFile("Test", C.hNovelRoot)
|
||||
nwGUI.project.tree[nHandle].setParent(None) # type: ignore
|
||||
assert projTree.revealNewTreeItem(nHandle) is False
|
||||
|
||||
# Try to add an item with unknown parent to the tree
|
||||
nHandle = nwGUI.theProject.newFile("Test", C.hNovelRoot)
|
||||
nwGUI.theProject.tree[nHandle].setParent(C.hInvalid) # type: ignore
|
||||
nHandle = nwGUI.project.newFile("Test", C.hNovelRoot)
|
||||
nwGUI.project.tree[nHandle].setParent(C.hInvalid) # type: ignore
|
||||
assert projTree.revealNewTreeItem(nHandle) is False
|
||||
|
||||
# Method: undoLastMove
|
||||
|
||||
@@ -25,7 +25,7 @@ import pytest
|
||||
from tools import C, buildTestProject
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.gui.statusbar import StatusLED
|
||||
from novelwriter.extensions.statusled import StatusLED
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
@@ -33,8 +33,8 @@ def testGuiStatusBar_Main(qtbot, nwGUI, projPath, mockRnd):
|
||||
"""Test the the various features of the status bar.
|
||||
"""
|
||||
buildTestProject(nwGUI, projPath)
|
||||
cHandle = nwGUI.theProject.newFile("A Note", C.hCharRoot)
|
||||
newDoc = nwGUI.theProject.storage.getDocument(cHandle)
|
||||
cHandle = nwGUI.project.newFile("A Note", C.hCharRoot)
|
||||
newDoc = nwGUI.project.storage.getDocument(cHandle)
|
||||
newDoc.writeDocument("# A Note\n\n")
|
||||
nwGUI.projView.projTree.revealNewTreeItem(cHandle)
|
||||
nwGUI.rebuildIndex(beQuiet=True)
|
||||
|
||||
@@ -33,14 +33,12 @@ from PyQt5.QtWidgets import QApplication
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
||||
from novelwriter.constants import nwLabels
|
||||
from novelwriter.gui.theme import GuiIcons, GuiTheme
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiTheme_Main(qtbot, nwGUI, tstPaths):
|
||||
"""Test the theme class init.
|
||||
"""
|
||||
mainTheme: GuiTheme = nwGUI.mainTheme
|
||||
"""Test the theme class init."""
|
||||
mainTheme = CONFIG.theme
|
||||
|
||||
# Methods
|
||||
# =======
|
||||
@@ -123,7 +121,7 @@ def testGuiTheme_Main(qtbot, nwGUI, tstPaths):
|
||||
@pytest.mark.gui
|
||||
def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI):
|
||||
"""Test the theme part of the class."""
|
||||
mainTheme: GuiTheme = nwGUI.mainTheme
|
||||
mainTheme = CONFIG.theme
|
||||
|
||||
# List Themes
|
||||
# ===========
|
||||
@@ -200,9 +198,8 @@ def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI):
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiTheme_Syntax(qtbot, monkeypatch, nwGUI):
|
||||
"""Test the syntax part of the class.
|
||||
"""
|
||||
mainTheme: GuiTheme = nwGUI.mainTheme
|
||||
"""Test the syntax part of the class."""
|
||||
mainTheme = CONFIG.theme
|
||||
|
||||
# List Themes
|
||||
# ===========
|
||||
@@ -266,9 +263,8 @@ def testGuiTheme_Syntax(qtbot, monkeypatch, nwGUI):
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiTheme_Icons(qtbot, caplog, monkeypatch, nwGUI, tstPaths):
|
||||
"""Test the icon cache class.
|
||||
"""
|
||||
iconCache: GuiIcons = nwGUI.mainTheme.iconCache
|
||||
"""Test the icon cache class."""
|
||||
iconCache = CONFIG.theme.iconCache
|
||||
|
||||
# Load Theme
|
||||
# ==========
|
||||
|
||||
@@ -45,7 +45,7 @@ def testManuscript_Init(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath: Pat
|
||||
"""Test the init/main functionality of the GuiManuscript dialog."""
|
||||
buildTestProject(nwGUI, projPath)
|
||||
nwGUI.openProject(projPath)
|
||||
nwGUI.theProject.storage.getDocument(C.hChapterDoc).writeDocument("## A Chapter\n\n\t\tHi")
|
||||
nwGUI.project.storage.getDocument(C.hChapterDoc).writeDocument("## A Chapter\n\n\t\tHi")
|
||||
allText = "New Novel\nBy Jane Doe\nA Chapter\n\t\tHi\n* * *"
|
||||
|
||||
manus = GuiManuscript(nwGUI)
|
||||
@@ -159,7 +159,7 @@ def testManuscript_Features(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath:
|
||||
manus.show()
|
||||
manus.loadContent()
|
||||
|
||||
cacheFile = CONFIG.dataPath("cache") / f"build_{nwGUI.theProject.data.uuid}.json"
|
||||
cacheFile = CONFIG.dataPath("cache") / f"build_{nwGUI.project.data.uuid}.json"
|
||||
manus.buildList.setCurrentRow(0)
|
||||
build = manus._getSelectedBuild()
|
||||
assert isinstance(build, BuildSettings)
|
||||
|
||||
@@ -128,11 +128,11 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
"worldRoot": 9,
|
||||
}
|
||||
|
||||
hPlotDoc = nwGUI.theProject.newFile("Main Plot", C.hPlotRoot)
|
||||
hCharDoc = nwGUI.theProject.newFile("Jane Doe", C.hCharRoot)
|
||||
hPlotDoc = nwGUI.project.newFile("Main Plot", C.hPlotRoot)
|
||||
hCharDoc = nwGUI.project.newFile("Jane Doe", C.hCharRoot)
|
||||
nwGUI.projView.projTree.revealNewTreeItem(hPlotDoc)
|
||||
nwGUI.projView.projTree.revealNewTreeItem(hCharDoc)
|
||||
nwGUI.theProject.tree[hPlotDoc].setActive(False) # type: ignore
|
||||
nwGUI.project.tree[hPlotDoc].setActive(False) # type: ignore
|
||||
|
||||
# Create the dialog and populate it
|
||||
bSettings = GuiBuildSettings(nwGUI, build)
|
||||
@@ -167,7 +167,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
|
||||
# Switch off novel docs
|
||||
filterTab.filterOpt._widgets[switchMap["incNovel"]].setChecked(False)
|
||||
assert build.buildItemFilter(nwGUI.theProject) == {
|
||||
assert build.buildItemFilter(nwGUI.project) == {
|
||||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||||
C.hTitlePage: (False, FilterMode.FILTERED),
|
||||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||||
@@ -182,7 +182,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
|
||||
# Switch on note docs
|
||||
filterTab.filterOpt._widgets[switchMap["incNotes"]].setChecked(True)
|
||||
assert build.buildItemFilter(nwGUI.theProject) == {
|
||||
assert build.buildItemFilter(nwGUI.project) == {
|
||||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||||
C.hTitlePage: (False, FilterMode.FILTERED),
|
||||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||||
@@ -197,7 +197,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
|
||||
# Switch on inactive docs
|
||||
filterTab.filterOpt._widgets[switchMap["incInactive"]].setChecked(True)
|
||||
assert build.buildItemFilter(nwGUI.theProject) == {
|
||||
assert build.buildItemFilter(nwGUI.project) == {
|
||||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||||
C.hTitlePage: (False, FilterMode.FILTERED),
|
||||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||||
@@ -214,7 +214,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
filterTab._treeMap[C.hChapterDoc].setSelected(True)
|
||||
filterTab._treeMap[C.hSceneDoc].setSelected(True)
|
||||
filterTab.includedButton.click()
|
||||
assert build.buildItemFilter(nwGUI.theProject) == {
|
||||
assert build.buildItemFilter(nwGUI.project) == {
|
||||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||||
C.hTitlePage: (False, FilterMode.FILTERED),
|
||||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||||
@@ -232,7 +232,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
filterTab._treeMap[hPlotDoc].setSelected(True) # type: ignore
|
||||
filterTab._treeMap[hCharDoc].setSelected(True) # type: ignore
|
||||
filterTab.excludedButton.click()
|
||||
assert build.buildItemFilter(nwGUI.theProject) == {
|
||||
assert build.buildItemFilter(nwGUI.project) == {
|
||||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||||
C.hTitlePage: (False, FilterMode.FILTERED),
|
||||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||||
@@ -247,7 +247,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
|
||||
# Switch on novel docs
|
||||
filterTab.filterOpt._widgets[switchMap["incNovel"]].setChecked(True)
|
||||
assert build.buildItemFilter(nwGUI.theProject) == {
|
||||
assert build.buildItemFilter(nwGUI.project) == {
|
||||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||||
C.hTitlePage: (True, FilterMode.FILTERED), # Now enabled
|
||||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||||
@@ -264,7 +264,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
filterTab.optTree.clearSelection()
|
||||
filterTab._treeMap[C.hNovelRoot].setSelected(True)
|
||||
filterTab.resetButton.click()
|
||||
assert build.buildItemFilter(nwGUI.theProject) == {
|
||||
assert build.buildItemFilter(nwGUI.project) == {
|
||||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||||
C.hTitlePage: (True, FilterMode.FILTERED),
|
||||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||||
@@ -284,7 +284,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
filterTab._treeMap[hPlotDoc].setSelected(True) # type: ignore
|
||||
filterTab._treeMap[hCharDoc].setSelected(True) # type: ignore
|
||||
filterTab.resetButton.click()
|
||||
assert build.buildItemFilter(nwGUI.theProject) == {
|
||||
assert build.buildItemFilter(nwGUI.project) == {
|
||||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||||
C.hTitlePage: (True, FilterMode.FILTERED),
|
||||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||||
@@ -302,8 +302,8 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
C.hNovelRoot, C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
||||
C.hPlotRoot, hPlotDoc, C.hCharRoot, hCharDoc,
|
||||
]
|
||||
nwGUI.theProject.tree[hCharDoc].setRoot(None) # type: ignore
|
||||
nwGUI.theProject.tree[hPlotDoc].setParent(None) # type: ignore
|
||||
nwGUI.project.tree[hCharDoc].setRoot(None) # type: ignore
|
||||
nwGUI.project.tree[hPlotDoc].setParent(None) # type: ignore
|
||||
filterTab._populateTree()
|
||||
assert list(filterTab._treeMap.keys()) == [
|
||||
C.hNovelRoot, C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
||||
|
||||
@@ -39,7 +39,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
|
||||
"""
|
||||
# Create a project to work on
|
||||
buildTestProject(nwGUI, projPath)
|
||||
project = nwGUI.theProject
|
||||
project = nwGUI.project
|
||||
|
||||
qtbot.wait(100)
|
||||
assert nwGUI.saveProject()
|
||||
|
||||
+36
-36
@@ -154,59 +154,59 @@ def cleanProject(path: str | Path):
|
||||
return
|
||||
|
||||
|
||||
def buildTestProject(theObject, projPath):
|
||||
"""Build a standard test project in projPath using theProject
|
||||
def buildTestProject(obj, projPath):
|
||||
"""Build a standard test project in projPath using the project
|
||||
object as the parent.
|
||||
"""
|
||||
from novelwriter.enum import nwItemClass
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
if isinstance(theObject, NWProject):
|
||||
theGUI = None
|
||||
theProject = theObject
|
||||
if isinstance(obj, NWProject):
|
||||
nwGUI = None
|
||||
project = obj
|
||||
else:
|
||||
theGUI = theObject
|
||||
theProject = theObject.theProject
|
||||
nwGUI = obj
|
||||
project = obj.project
|
||||
|
||||
theProject.clearProject()
|
||||
theProject.storage.openProjectInPlace(projPath)
|
||||
theProject.setDefaultStatusImport()
|
||||
project.clearProject()
|
||||
project.storage.openProjectInPlace(projPath)
|
||||
project.setDefaultStatusImport()
|
||||
|
||||
theProject.data.setUuid("d0f3fe10-c6e6-4310-8bfd-181eb4224eed")
|
||||
theProject.data.setName("New Project")
|
||||
theProject.data.setTitle("New Novel")
|
||||
theProject.data.setAuthor("Jane Doe")
|
||||
project.data.setUuid("d0f3fe10-c6e6-4310-8bfd-181eb4224eed")
|
||||
project.data.setName("New Project")
|
||||
project.data.setTitle("New Novel")
|
||||
project.data.setAuthor("Jane Doe")
|
||||
|
||||
# Creating a minimal project with a few root folders and a
|
||||
# single chapter folder with a single file.
|
||||
xHandle = {}
|
||||
xHandle[1] = theProject.newRoot(nwItemClass.NOVEL, "Novel")
|
||||
xHandle[2] = theProject.newRoot(nwItemClass.PLOT, "Plot")
|
||||
xHandle[3] = theProject.newRoot(nwItemClass.CHARACTER, "Characters")
|
||||
xHandle[4] = theProject.newRoot(nwItemClass.WORLD, "World")
|
||||
xHandle[5] = theProject.newFile("Title Page", xHandle[1])
|
||||
xHandle[6] = theProject.newFolder("New Chapter", xHandle[1])
|
||||
xHandle[7] = theProject.newFile("New Chapter", xHandle[6])
|
||||
xHandle[8] = theProject.newFile("New Scene", xHandle[6])
|
||||
xHandle[1] = project.newRoot(nwItemClass.NOVEL, "Novel")
|
||||
xHandle[2] = project.newRoot(nwItemClass.PLOT, "Plot")
|
||||
xHandle[3] = project.newRoot(nwItemClass.CHARACTER, "Characters")
|
||||
xHandle[4] = project.newRoot(nwItemClass.WORLD, "World")
|
||||
xHandle[5] = project.newFile("Title Page", xHandle[1])
|
||||
xHandle[6] = project.newFolder("New Chapter", xHandle[1])
|
||||
xHandle[7] = project.newFile("New Chapter", xHandle[6])
|
||||
xHandle[8] = project.newFile("New Scene", xHandle[6])
|
||||
|
||||
aDoc = theProject.storage.getDocument(xHandle[5])
|
||||
aDoc = project.storage.getDocument(xHandle[5])
|
||||
aDoc.writeDocument("#! New Novel\n\n>> By Jane Doe <<\n")
|
||||
theProject.index.reIndexHandle(xHandle[5])
|
||||
project.index.reIndexHandle(xHandle[5])
|
||||
|
||||
aDoc = theProject.storage.getDocument(xHandle[7])
|
||||
aDoc.writeDocument("## %s\n\n" % theProject.tr("New Chapter"))
|
||||
theProject.index.reIndexHandle(xHandle[7])
|
||||
aDoc = project.storage.getDocument(xHandle[7])
|
||||
aDoc.writeDocument("## %s\n\n" % project.tr("New Chapter"))
|
||||
project.index.reIndexHandle(xHandle[7])
|
||||
|
||||
aDoc = theProject.storage.getDocument(xHandle[8])
|
||||
aDoc.writeDocument("### %s\n\n" % theProject.tr("New Scene"))
|
||||
theProject.index.reIndexHandle(xHandle[8])
|
||||
aDoc = project.storage.getDocument(xHandle[8])
|
||||
aDoc.writeDocument("### %s\n\n" % project.tr("New Scene"))
|
||||
project.index.reIndexHandle(xHandle[8])
|
||||
|
||||
theProject.session.startSession()
|
||||
theProject.setProjectChanged(True)
|
||||
theProject.saveProject(autoSave=True)
|
||||
project.session.startSession()
|
||||
project.setProjectChanged(True)
|
||||
project.saveProject(autoSave=True)
|
||||
|
||||
if theGUI is not None:
|
||||
theGUI.hasProject = True
|
||||
theGUI.rebuildTrees()
|
||||
if nwGUI is not None:
|
||||
nwGUI.hasProject = True
|
||||
nwGUI.rebuildTrees()
|
||||
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user