Display build details in Manuscript tool (#1516)
This commit is contained in:
+44
-16
@@ -1986,53 +1986,53 @@
|
||||
<context>
|
||||
<name>GuiManuscript</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="80" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="82" />
|
||||
<source>Build Manuscript</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="110" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="112" />
|
||||
<source>Add New Build</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="117" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="119" />
|
||||
<source>Delete Selected Build</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="124" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="126" />
|
||||
<source>Edit Selected Build</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="128" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="130" />
|
||||
<source>Builds</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="145" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="164" />
|
||||
<source>Preview</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="148" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="167" />
|
||||
<source>Print</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="151" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="170" />
|
||||
<source>Build</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="154" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="173" />
|
||||
<source>Close</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="254" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="207" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="278" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="226" />
|
||||
<source>My Manuscript</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
@@ -4487,6 +4487,34 @@
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>_DetailsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="504" />
|
||||
<source>Setting</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="504" />
|
||||
<source>Value</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="573" />
|
||||
<source>Name</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="579" />
|
||||
<source>Selection</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="595" />
|
||||
<source>Title</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>_FilterTab</name>
|
||||
<message>
|
||||
@@ -4625,27 +4653,27 @@
|
||||
<context>
|
||||
<name>_PreviewWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="467" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="659" />
|
||||
<source>Press the "Build Preview" button to generate ...</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="565" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="757" />
|
||||
<source>Processing ...</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="594" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="786" />
|
||||
<source>Done</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="637" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="829" />
|
||||
<source>Unknown</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="638" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="830" />
|
||||
<source>Built</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
|
||||
@@ -319,7 +319,6 @@ class BuildSettings:
|
||||
value = min(max(value, definition[2]), definition[3])
|
||||
self._changed = value != self._settings[key]
|
||||
self._settings[key] = value
|
||||
logger.debug(f"Build Setting '{key}' set to: {value}")
|
||||
return True
|
||||
|
||||
##
|
||||
@@ -457,6 +456,8 @@ class BuildCollection:
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
self._project = project
|
||||
self._builds = {}
|
||||
self._lastBuild = ""
|
||||
self._defaultBuild = ""
|
||||
self._loadCollection()
|
||||
return
|
||||
|
||||
@@ -465,7 +466,21 @@ class BuildCollection:
|
||||
return len(self._builds)
|
||||
|
||||
##
|
||||
# Methods
|
||||
# Properties
|
||||
##
|
||||
|
||||
@property
|
||||
def lastBuild(self) -> str:
|
||||
"""Return the last active build."""
|
||||
return self._lastBuild
|
||||
|
||||
@property
|
||||
def defaultBuild(self) -> str:
|
||||
"""Return the default build."""
|
||||
return self._defaultBuild
|
||||
|
||||
##
|
||||
# Getters
|
||||
##
|
||||
|
||||
def getBuild(self, buildID: str) -> BuildSettings | None:
|
||||
@@ -476,6 +491,24 @@ class BuildCollection:
|
||||
build.unpack(self._builds[buildID])
|
||||
return build
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setLastBuild(self, buildID: str) -> None:
|
||||
"""Set the last active build id."""
|
||||
if buildID != self._lastBuild:
|
||||
self._lastBuild = buildID
|
||||
self._saveCollection()
|
||||
return
|
||||
|
||||
def setDefaultBuild(self, buildID: str) -> None:
|
||||
"""Set the default build id."""
|
||||
if buildID != self._defaultBuild:
|
||||
self._defaultBuild = buildID
|
||||
self._saveCollection()
|
||||
return
|
||||
|
||||
def setBuild(self, build: BuildSettings) -> None:
|
||||
"""Set build settings data in the collection."""
|
||||
if isinstance(build, BuildSettings):
|
||||
@@ -484,6 +517,10 @@ class BuildCollection:
|
||||
self._saveCollection()
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
|
||||
def removeBuild(self, buildID: str) -> None:
|
||||
"""Remove the a build from the collection."""
|
||||
self._builds.pop(buildID, None)
|
||||
@@ -527,7 +564,11 @@ class BuildCollection:
|
||||
return False
|
||||
|
||||
for key, entry in builds.items():
|
||||
if isinstance(entry, dict):
|
||||
if key == "lastBuild":
|
||||
self._lastBuild = str(entry)
|
||||
elif key == "defaultBuild":
|
||||
self._defaultBuild = str(entry)
|
||||
elif isinstance(entry, dict):
|
||||
self._builds[key] = entry
|
||||
|
||||
return True
|
||||
@@ -540,9 +581,13 @@ class BuildCollection:
|
||||
|
||||
logger.debug("Saving builds file")
|
||||
try:
|
||||
data = {"novelWriter.builds": self._builds}
|
||||
data = {
|
||||
"lastBuild": self._lastBuild,
|
||||
"defaultBuild": self._defaultBuild,
|
||||
}
|
||||
data.update(self._builds)
|
||||
with open(buildsFile, mode="w+", encoding="utf-8") as outFile:
|
||||
outFile.write(jsonEncode(data, nmax=4))
|
||||
outFile.write(jsonEncode({"novelWriter.builds": data}, nmax=4))
|
||||
except Exception:
|
||||
logger.error("Failed to save builds file")
|
||||
logException()
|
||||
|
||||
@@ -58,13 +58,14 @@ VALID_MAP = {
|
||||
"GuiWordList": {"winWidth", "winHeight"},
|
||||
"GuiNovelView": {"lastCol", "lastColSize"},
|
||||
"GuiBuildSettings": {
|
||||
"winWidth", "winHeight", "treeWidth", "filterWidth"
|
||||
"winWidth", "winHeight", "treeWidth", "filterWidth",
|
||||
},
|
||||
"GuiManuscript": {
|
||||
"winWidth", "winHeight", "optsWidth", "viewWidth"
|
||||
"winWidth", "winHeight", "optsWidth", "viewWidth", "listHeight",
|
||||
"detailsHeight", "detailsWidth", "detailsExpanded",
|
||||
},
|
||||
"GuiManuscriptBuild": {
|
||||
"winWidth", "winHeight", "fmtWidth", "sumWidth"
|
||||
"winWidth", "winHeight", "fmtWidth", "sumWidth",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -600,7 +600,7 @@ class NWProject:
|
||||
self._langData = json.load(inFile)
|
||||
logger.debug("Loaded project language file: %s", langFile.name)
|
||||
except Exception:
|
||||
logger.error("Failed to project language file")
|
||||
logger.error("Failed to load project language file")
|
||||
logException()
|
||||
return False
|
||||
|
||||
|
||||
+211
-21
@@ -33,8 +33,9 @@ from datetime import datetime
|
||||
from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent
|
||||
from PyQt5.QtCore import QSize, QTimer, Qt, pyqtSlot
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QGridLayout, QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPushButton,
|
||||
QSplitter, QTextBrowser, QToolButton, QVBoxLayout, QWidget, qApp
|
||||
QAbstractItemView, QDialog, QGridLayout, QHBoxLayout, QLabel, QListWidget,
|
||||
QListWidgetItem, QPushButton, QSplitter, QTextBrowser, QToolButton,
|
||||
QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget, qApp
|
||||
)
|
||||
from PyQt5.QtPrintSupport import QPrintPreviewDialog, QPrinter
|
||||
|
||||
@@ -43,6 +44,7 @@ from novelwriter.error import logException
|
||||
from novelwriter.common import checkInt, fuzzyTime
|
||||
from novelwriter.core.tohtml import ToHtml
|
||||
from novelwriter.core.docbuild import NWBuildDocument
|
||||
from novelwriter.core.tokenizer import HeadingFormatter
|
||||
from novelwriter.core.buildsettings import BuildCollection, BuildSettings
|
||||
from novelwriter.tools.manusbuild import GuiManuscriptBuild
|
||||
from novelwriter.tools.manussettings import GuiBuildSettings
|
||||
@@ -127,10 +129,6 @@ class GuiManuscript(QDialog):
|
||||
|
||||
self.lblBuilds = QLabel("<b>{0}</b>".format(self.tr("Builds")))
|
||||
|
||||
self.buildList = QListWidget()
|
||||
self.buildList.setIconSize(QSize(iPx, iPx))
|
||||
self.buildList.doubleClicked.connect(self._editSelectedBuild)
|
||||
|
||||
self.listToolBox = QHBoxLayout()
|
||||
self.listToolBox.addWidget(self.lblBuilds)
|
||||
self.listToolBox.addStretch(1)
|
||||
@@ -139,6 +137,27 @@ class GuiManuscript(QDialog):
|
||||
self.listToolBox.addWidget(self.tbEdit)
|
||||
self.listToolBox.setSpacing(0)
|
||||
|
||||
# Builds
|
||||
# ======
|
||||
|
||||
self.buildList = QListWidget()
|
||||
self.buildList.setIconSize(QSize(iPx, iPx))
|
||||
self.buildList.doubleClicked.connect(self._editSelectedBuild)
|
||||
self.buildList.currentItemChanged.connect(self._updateBuildDetails)
|
||||
|
||||
self.buildDetails = _DetailsWidget(self)
|
||||
self.buildDetails.setColumnWidth(
|
||||
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "detailsWidth", 100)),
|
||||
)
|
||||
|
||||
self.buildSplit = QSplitter(Qt.Orientation.Vertical, self)
|
||||
self.buildSplit.addWidget(self.buildList)
|
||||
self.buildSplit.addWidget(self.buildDetails)
|
||||
self.buildSplit.setSizes([
|
||||
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "listHeight", 50)),
|
||||
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "detailsHeight", 50)),
|
||||
])
|
||||
|
||||
# Process Controls
|
||||
# ================
|
||||
|
||||
@@ -167,7 +186,7 @@ class GuiManuscript(QDialog):
|
||||
|
||||
self.controlBox = QVBoxLayout()
|
||||
self.controlBox.addLayout(self.listToolBox, 0)
|
||||
self.controlBox.addWidget(self.buildList, 1)
|
||||
self.controlBox.addWidget(self.buildSplit, 1)
|
||||
self.controlBox.addLayout(self.processBox, 0)
|
||||
self.controlBox.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
@@ -206,8 +225,13 @@ class GuiManuscript(QDialog):
|
||||
build = BuildSettings()
|
||||
build.setName(self.tr("My Manuscript"))
|
||||
self._builds.setBuild(build)
|
||||
selected = build.buildID
|
||||
else:
|
||||
selected = self._builds.lastBuild
|
||||
|
||||
self._updateBuildsList()
|
||||
if selected in self._buildMap:
|
||||
self.buildList.setCurrentItem(self._buildMap[selected])
|
||||
|
||||
logger.debug("Loading build cache")
|
||||
cache = CONFIG.dataPath("cache") / f"build_{SHARED.project.data.uuid}.json"
|
||||
@@ -263,6 +287,15 @@ class GuiManuscript(QDialog):
|
||||
self._openSettingsDialog(build)
|
||||
return
|
||||
|
||||
@pyqtSlot("QListWidgetItem*", "QListWidgetItem*")
|
||||
def _updateBuildDetails(self, current: QListWidgetItem, previous: QListWidgetItem) -> None:
|
||||
"""Process change of build selection to update the details."""
|
||||
if isinstance(current, QListWidgetItem):
|
||||
build = self._builds.getBuild(current.data(self.D_KEY))
|
||||
if build is not None:
|
||||
self.buildDetails.updateInfo(build)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _deleteSelectedBuild(self):
|
||||
"""Delete the currently selected build settings entry."""
|
||||
@@ -278,6 +311,9 @@ class GuiManuscript(QDialog):
|
||||
"""Process new build settings from the settings dialog."""
|
||||
self._builds.setBuild(build)
|
||||
self._updateBuildItem(build)
|
||||
current = self.buildList.currentItem()
|
||||
if isinstance(current, QListWidgetItem) and current.data(self.D_KEY) == build.buildID:
|
||||
self._updateBuildDetails(current, current)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
@@ -363,8 +399,6 @@ class GuiManuscript(QDialog):
|
||||
self.docPreview.setJustify(
|
||||
build.getBool("format.justifyText")
|
||||
)
|
||||
if build.buildID and build.buildID in self._buildMap:
|
||||
self._buildMap[build.buildID].setSelected(True)
|
||||
return
|
||||
|
||||
def _getSelectedBuild(self) -> BuildSettings | None:
|
||||
@@ -383,6 +417,10 @@ class GuiManuscript(QDialog):
|
||||
"""Save the user GUI settings."""
|
||||
logger.debug("Saving GuiManuscript settings")
|
||||
|
||||
current = self.buildList.currentItem()
|
||||
if isinstance(current, QListWidgetItem):
|
||||
self._builds.setLastBuild(current.data(self.D_KEY))
|
||||
|
||||
winWidth = CONFIG.rpxInt(self.width())
|
||||
winHeight = CONFIG.rpxInt(self.height())
|
||||
|
||||
@@ -390,11 +428,21 @@ class GuiManuscript(QDialog):
|
||||
optsWidth = CONFIG.rpxInt(mainSplit[0])
|
||||
viewWidth = CONFIG.rpxInt(mainSplit[1])
|
||||
|
||||
buildSplit = self.buildSplit.sizes()
|
||||
listHeight = CONFIG.rpxInt(buildSplit[0])
|
||||
detailsHeight = CONFIG.rpxInt(buildSplit[1])
|
||||
detailsWidth = CONFIG.rpxInt(self.buildDetails.getColumnWidth())
|
||||
detailsExpanded = self.buildDetails.getExpandedState()
|
||||
|
||||
pOptions = SHARED.project.options
|
||||
pOptions.setValue("GuiManuscript", "winWidth", winWidth)
|
||||
pOptions.setValue("GuiManuscript", "winHeight", winHeight)
|
||||
pOptions.setValue("GuiManuscript", "optsWidth", optsWidth)
|
||||
pOptions.setValue("GuiManuscript", "viewWidth", viewWidth)
|
||||
pOptions.setValue("GuiManuscript", "listHeight", listHeight)
|
||||
pOptions.setValue("GuiManuscript", "detailsHeight", detailsHeight)
|
||||
pOptions.setValue("GuiManuscript", "detailsWidth", detailsWidth)
|
||||
pOptions.setValue("GuiManuscript", "detailsExpanded", detailsExpanded)
|
||||
pOptions.saveSettings()
|
||||
|
||||
return
|
||||
@@ -444,9 +492,151 @@ class GuiManuscript(QDialog):
|
||||
# END Class GuiManuscript
|
||||
|
||||
|
||||
class _DetailsWidget(QWidget):
|
||||
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self._initExpanded = True
|
||||
|
||||
# Tree Vidget
|
||||
self.listView = QTreeWidget(self)
|
||||
self.listView.setHeaderLabels([self.tr("Setting"), self.tr("Value")])
|
||||
self.listView.setIndentation(SHARED.theme.baseIconSize)
|
||||
self.listView.setSelectionMode(QAbstractItemView.NoSelection)
|
||||
|
||||
# Assemble
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.outerBox.addWidget(self.listView)
|
||||
self.outerBox.setContentsMargins(0, 0, 0, 0)
|
||||
self.setLayout(self.outerBox)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Getters
|
||||
##
|
||||
|
||||
def getColumnWidth(self) -> int:
|
||||
"""Get the width of the first column."""
|
||||
return self.listView.columnWidth(0)
|
||||
|
||||
def getExpandedState(self) -> list[bool]:
|
||||
"""Get the expanded state of each top level item."""
|
||||
state = []
|
||||
for i in range(self.listView.topLevelItemCount()):
|
||||
item = self.listView.topLevelItem(i)
|
||||
if isinstance(item, QTreeWidgetItem):
|
||||
state.append(item.isExpanded())
|
||||
return state
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setColumnWidth(self, value: int) -> None:
|
||||
"""Set the width of the first column."""
|
||||
self.listView.setColumnWidth(0, value)
|
||||
return
|
||||
|
||||
def setExpandedState(self, state: list[bool]) -> None:
|
||||
"""Set the expanded state of each top level item."""
|
||||
count = len(state)
|
||||
for i in range(self.listView.topLevelItemCount()):
|
||||
item = self.listView.topLevelItem(i)
|
||||
if isinstance(item, QTreeWidgetItem):
|
||||
item.setExpanded((state[i] if i < count else True) and item.childCount() > 0)
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
|
||||
def updateInfo(self, build: BuildSettings) -> None:
|
||||
"""Load the build settings info into the table."""
|
||||
if self._initExpanded:
|
||||
previous = SHARED.project.options.getValue("GuiManuscript", "detailsExpanded", [])
|
||||
expanded = [bool(s) for s in previous]
|
||||
self._initExpanded = False
|
||||
else:
|
||||
expanded = self.getExpandedState()
|
||||
|
||||
self.listView.clear()
|
||||
|
||||
on = SHARED.theme.getIcon("bullet-on")
|
||||
off = SHARED.theme.getIcon("bullet-off")
|
||||
|
||||
# Name
|
||||
item = QTreeWidgetItem()
|
||||
item.setText(0, self.tr("Name"))
|
||||
item.setText(1, build.name)
|
||||
self.listView.addTopLevelItem(item)
|
||||
|
||||
# Selection
|
||||
item = QTreeWidgetItem()
|
||||
item.setText(0, self.tr("Selection"))
|
||||
item.setText(1, "")
|
||||
self.listView.addTopLevelItem(item)
|
||||
for tHandle, nwItem in SHARED.project.tree.iterRoots(None):
|
||||
if not nwItem.isInactiveClass():
|
||||
sub = QTreeWidgetItem()
|
||||
sub.setText(0, nwItem.itemName)
|
||||
sub.setIcon(1, on if build.isRootAllowed(tHandle) else off)
|
||||
item.addChild(sub)
|
||||
|
||||
# Headings
|
||||
hFmt = HeadingFormatter(SHARED.project)
|
||||
hFmt.incChapter()
|
||||
hFmt.incScene()
|
||||
hFmt.resetScene()
|
||||
hFmt.incScene()
|
||||
title = self.tr("Title")
|
||||
|
||||
item = QTreeWidgetItem()
|
||||
item.setText(0, build.getLabel("headings"))
|
||||
item.setText(1, "")
|
||||
self.listView.addTopLevelItem(item)
|
||||
entries = [
|
||||
"headings.fmtTitle", "headings.fmtChapter", "headings.fmtUnnumbered",
|
||||
"headings.fmtScene", "headings.fmtSection"
|
||||
]
|
||||
for key in entries:
|
||||
sub = QTreeWidgetItem()
|
||||
sub.setText(0, build.getLabel(key))
|
||||
sub.setText(1, hFmt.apply(build.getStr(key), title))
|
||||
item.addChild(sub)
|
||||
for key in ["headings.hideScene", "headings.hideSection"]:
|
||||
sub = QTreeWidgetItem()
|
||||
sub.setText(0, build.getLabel(key))
|
||||
sub.setIcon(1, on if build.getBool(key) else off)
|
||||
item.addChild(sub)
|
||||
|
||||
# Text Content
|
||||
item = QTreeWidgetItem()
|
||||
item.setText(0, build.getLabel("text.grpContent"))
|
||||
item.setText(1, "")
|
||||
self.listView.addTopLevelItem(item)
|
||||
entries = [
|
||||
"text.includeSynopsis", "text.includeComments",
|
||||
"text.includeKeywords", "text.includeBodyText",
|
||||
]
|
||||
for key in entries:
|
||||
sub = QTreeWidgetItem()
|
||||
sub.setText(0, build.getLabel(key))
|
||||
sub.setIcon(1, on if build.getBool(key) else off)
|
||||
item.addChild(sub)
|
||||
|
||||
# Restore expanded state
|
||||
self.setExpandedState(expanded)
|
||||
|
||||
return
|
||||
|
||||
# END Class _DetailsWidget
|
||||
|
||||
|
||||
class _PreviewWidget(QTextBrowser):
|
||||
|
||||
def __init__(self, parent: QWidget):
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self._docTime = 0
|
||||
@@ -512,13 +702,13 @@ class _PreviewWidget(QTextBrowser):
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setBuildName(self, name: str):
|
||||
def setBuildName(self, name: str) -> None:
|
||||
"""Set the build name for the document label."""
|
||||
self._buildName = name
|
||||
self._updateBuildAge()
|
||||
return
|
||||
|
||||
def setJustify(self, state: bool):
|
||||
def setJustify(self, state: bool) -> None:
|
||||
"""Enable/disable the justify text option."""
|
||||
pOptions = self.document().defaultTextOption()
|
||||
if state:
|
||||
@@ -528,7 +718,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
self.document().setDefaultTextOption(pOptions)
|
||||
return
|
||||
|
||||
def setTextFont(self, family: str, size: int):
|
||||
def setTextFont(self, family: str, size: int) -> None:
|
||||
"""Set the text font properties."""
|
||||
if family:
|
||||
font = QFont()
|
||||
@@ -541,7 +731,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
# Methods
|
||||
##
|
||||
|
||||
def beginNewBuild(self, length: int):
|
||||
def beginNewBuild(self, length: int) -> None:
|
||||
"""Clear the document and show the progress bar."""
|
||||
self.buildProgress.setMaximum(length)
|
||||
self.buildProgress.setValue(0)
|
||||
@@ -551,13 +741,13 @@ class _PreviewWidget(QTextBrowser):
|
||||
self.clear()
|
||||
return
|
||||
|
||||
def buildStep(self, value: int):
|
||||
def buildStep(self, value: int) -> None:
|
||||
"""Update the progress bar value."""
|
||||
self.buildProgress.setValue(value)
|
||||
qApp.processEvents()
|
||||
return
|
||||
|
||||
def setContent(self, data: dict):
|
||||
def setContent(self, data: dict) -> None:
|
||||
"""Set the content of the preview widget."""
|
||||
sPos = self.verticalScrollBar().value()
|
||||
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||
@@ -602,7 +792,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
# Events
|
||||
##
|
||||
|
||||
def resizeEvent(self, event: QResizeEvent):
|
||||
def resizeEvent(self, event: QResizeEvent) -> None:
|
||||
"""Capture resize and update the document margins."""
|
||||
super().resizeEvent(event)
|
||||
self._updateDocMargins()
|
||||
@@ -613,7 +803,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
##
|
||||
|
||||
@pyqtSlot("QPrinter*")
|
||||
def printPreview(self, printer: QPrinter):
|
||||
def printPreview(self, printer: QPrinter) -> None:
|
||||
"""Connect the print preview painter to the document viewer."""
|
||||
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||
printer.setOrientation(QPrinter.Portrait)
|
||||
@@ -626,7 +816,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
##
|
||||
|
||||
@pyqtSlot()
|
||||
def _updateBuildAge(self):
|
||||
def _updateBuildAge(self) -> None:
|
||||
"""Update the build time and the fuzzy age."""
|
||||
if self._docTime > 0:
|
||||
strBuildTime = "%s (%s)" % (
|
||||
@@ -642,7 +832,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _hideProgress(self):
|
||||
def _hideProgress(self) -> None:
|
||||
"""Clean up the build progress bar."""
|
||||
self.buildProgress.setVisible(False)
|
||||
return
|
||||
@@ -651,7 +841,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _updateDocMargins(self):
|
||||
def _updateDocMargins(self) -> None:
|
||||
"""Automatically adjust the header to fill the top of the
|
||||
document within the viewport.
|
||||
"""
|
||||
|
||||
@@ -377,6 +377,8 @@ def testCoreBuildSettings_Collection(monkeypatch, mockGUI, fncPath: Path, mockRn
|
||||
builds = BuildCollection(project)
|
||||
assert len(builds) == 0
|
||||
assert not buildsFile.exists()
|
||||
assert builds.lastBuild == ""
|
||||
assert builds.defaultBuild == ""
|
||||
|
||||
# Create a default build
|
||||
buildOne = BuildSettings()
|
||||
@@ -412,7 +414,9 @@ def testCoreBuildSettings_Collection(monkeypatch, mockGUI, fncPath: Path, mockRn
|
||||
|
||||
# Check the file content
|
||||
data = json.loads(buildsFile.read_text(encoding="utf-8"))
|
||||
assert list(data["novelWriter.builds"].keys()) == [buildIDOne, buildIDTwo]
|
||||
assert list(data["novelWriter.builds"].keys()) == [
|
||||
"lastBuild", "defaultBuild", buildIDOne, buildIDTwo
|
||||
]
|
||||
|
||||
# Remove a build
|
||||
builds.removeBuild(buildIDOne)
|
||||
@@ -423,12 +427,16 @@ def testCoreBuildSettings_Collection(monkeypatch, mockGUI, fncPath: Path, mockRn
|
||||
|
||||
# Check the file content
|
||||
data = json.loads(buildsFile.read_text(encoding="utf-8"))
|
||||
assert list(data["novelWriter.builds"].keys()) == [buildIDTwo]
|
||||
assert list(data["novelWriter.builds"].keys()) == [
|
||||
"lastBuild", "defaultBuild", buildIDTwo
|
||||
]
|
||||
builds.setBuild(buildOne)
|
||||
assert list(builds.builds()) == [
|
||||
(buildIDTwo, "Build Two"),
|
||||
(buildIDOne, "Build One"),
|
||||
]
|
||||
builds.setLastBuild(buildIDOne)
|
||||
builds.setDefaultBuild(buildIDTwo)
|
||||
|
||||
# Check errors: No valid path
|
||||
with monkeypatch.context() as mp:
|
||||
@@ -447,7 +455,7 @@ def testCoreBuildSettings_Collection(monkeypatch, mockGUI, fncPath: Path, mockRn
|
||||
buildsFile.write_text("foobar")
|
||||
assert builds._loadCollection() is False
|
||||
|
||||
# Check errors: Valid jason file, but list instead of object
|
||||
# Check errors: Valid json file, but list instead of object
|
||||
buildsFile.write_text("[]")
|
||||
assert builds._loadCollection() is False
|
||||
buildsFile.unlink()
|
||||
@@ -459,5 +467,7 @@ def testCoreBuildSettings_Collection(monkeypatch, mockGUI, fncPath: Path, mockRn
|
||||
(buildIDTwo, "Build Two"),
|
||||
(buildIDOne, "Build One"),
|
||||
]
|
||||
assert another.lastBuild == buildIDOne
|
||||
assert another.defaultBuild == buildIDTwo
|
||||
|
||||
# END Test testCoreBuildSettings_Collection
|
||||
|
||||
Reference in New Issue
Block a user