From b0201c58e935cec4a309547ec575f677c77b1eea Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Mon, 5 Jun 2023 21:49:30 +0200 Subject: [PATCH] Add Table of Contents to build dialog --- novelwriter/core/buildsettings.py | 8 --- novelwriter/core/options.py | 2 +- novelwriter/tools/manusbuild.py | 95 +++++++++++++++++++----------- novelwriter/tools/manuscript.py | 15 +++-- novelwriter/tools/manussettings.py | 16 +++-- 5 files changed, 79 insertions(+), 57 deletions(-) diff --git a/novelwriter/core/buildsettings.py b/novelwriter/core/buildsettings.py index cf0701e0..bea5f408 100644 --- a/novelwriter/core/buildsettings.py +++ b/novelwriter/core/buildsettings.py @@ -72,9 +72,6 @@ SETTINGS_TEMPLATE = { "format.replaceTabs": (bool, False), "odt.addColours": (bool, True), "html.addStyles": (bool, False), - "build.splitNovel": (bool, False), - "build.splitNotes": (bool, False), - "build.splitChapters": (bool, False), } SETTINGS_LABELS = { @@ -115,11 +112,6 @@ SETTINGS_LABELS = { "html": QT_TRANSLATE_NOOP("Builds", "HTML"), "html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"), - - "build": QT_TRANSLATE_NOOP("Builds", "Build Options"), - "build.splitNovel": QT_TRANSLATE_NOOP("Builds", "Split Novel Root Folders"), - "build.splitNotes": QT_TRANSLATE_NOOP("Builds", "Split Note Root Folders"), - "build.splitChapters": QT_TRANSLATE_NOOP("Builds", "Split By Chapter Document"), } diff --git a/novelwriter/core/options.py b/novelwriter/core/options.py index 89cb6ab9..9a1c0af8 100644 --- a/novelwriter/core/options.py +++ b/novelwriter/core/options.py @@ -64,7 +64,7 @@ VALID_MAP = { "winWidth", "winHeight", "optsWidth", "viewWidth" }, "GuiManuscriptBuild": { - "winWidth", "winHeight", "fmtWidth", "optsWidth" + "winWidth", "winHeight", "fmtWidth", "sumWidth" }, } diff --git a/novelwriter/tools/manusbuild.py b/novelwriter/tools/manusbuild.py index 77d04a71..875a50b1 100644 --- a/novelwriter/tools/manusbuild.py +++ b/novelwriter/tools/manusbuild.py @@ -27,9 +27,9 @@ import logging from typing import TYPE_CHECKING -from PyQt5.QtCore import Qt, pyqtSlot +from PyQt5.QtCore import QSize, Qt, pyqtSlot from PyQt5.QtWidgets import ( - QAbstractButton, QDialog, QDialogButtonBox, QFrame, QGridLayout, + QAbstractButton, QAbstractItemView, QDialog, QDialogButtonBox, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem, QProgressBar, QPushButton, QSplitter, QVBoxLayout, QWidget ) @@ -37,8 +37,8 @@ from PyQt5.QtWidgets import ( from novelwriter import CONFIG from novelwriter.common import makeFileNameSafe from novelwriter.constants import nwLabels +from novelwriter.core.item import NWItem from novelwriter.core.buildsettings import BuildSettings -from novelwriter.extensions.switchbox import NSwitchBox if TYPE_CHECKING: from novelwriter.guimain import GuiMain @@ -70,8 +70,9 @@ class GuiManuscriptBuild(QDialog): self.setWindowTitle(self.tr("Build Manuscript")) self.setMinimumWidth(CONFIG.pxInt(500)) - self.setMinimumHeight(CONFIG.pxInt(250)) + self.setMinimumHeight(CONFIG.pxInt(300)) + iPx = self.mainTheme.baseIconSize wWin = CONFIG.pxInt(660) hWin = CONFIG.pxInt(390) @@ -81,11 +82,12 @@ class GuiManuscriptBuild(QDialog): CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "winHeight", hWin)) ) - # Formats - # ======= + # Output Format + # ============= - self.lblFormat = QLabel("{0}".format(self.tr("Build Format"))) + self.lblFormat = QLabel(self.tr("Output Format")) self.listFormats = QListWidget() + self.listFormats.setIconSize(QSize(iPx, iPx)) current = None for key, (_, label) in nwLabels.BUILD_FORMATS.items(): item = QListWidgetItem() @@ -106,28 +108,23 @@ class GuiManuscriptBuild(QDialog): self.formatWidget.setLayout(self.formatBox) self.formatWidget.setContentsMargins(0, 0, 0, 0) - # Build Controls - # ============== + # Table of Contents + # ================= - # Build Options - self.swtOptions = NSwitchBox(self, self.mainTheme.baseIconSize) - self.swtOptions.switchToggled.connect(self._applyBuildOptions) - self.swtOptions.setFrameStyle(QFrame.NoFrame) - self.swtOptions.setInnerContentsMargins(0, 0, 0, 0) + self.lblContent = QLabel(self.tr("Table of Contents")) - self.swtOptions.addLabel(self._build.getLabel("build")) - self.swtOptions.addItem( - self.mainTheme.getIcon("cls_novel"), self._build.getLabel("build.splitNovel"), - "build.splitNovel", default=self._build.getBool("build.splitNovel") - ) - self.swtOptions.addItem( - self.mainTheme.getIcon("cls_custom"), self._build.getLabel("build.splitNotes"), - "build.splitNotes", default=self._build.getBool("build.splitNotes") - ) - self.swtOptions.addItem( - self.mainTheme.getIcon("proj_chapter"), self._build.getLabel("build.splitChapters"), - "build.splitChapters", default=self._build.getBool("build.splitChapters") - ) + self.listContent = QListWidget(self) + self.listContent.setIconSize(QSize(iPx, iPx)) + self.listContent.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) + + self.contentBox = QVBoxLayout() + self.contentBox.addWidget(self.lblContent, 0) + self.contentBox.addWidget(self.listContent, 0) + self.contentBox.setContentsMargins(0, 0, 0, 0) + + self.contentWidget = QWidget() + self.contentWidget.setLayout(self.contentBox) + self.contentWidget.setContentsMargins(0, 0, 0, 0) # Dialog Controls # =============== @@ -168,6 +165,7 @@ class GuiManuscriptBuild(QDialog): # Build Progress self.lblProgress = QLabel(self.tr("Build Progress")) self.buildProgress = QProgressBar() + self.buildProgress.setValue(0) # Dialog Buttons self.btnBuild = QPushButton(self.mainTheme.getIcon("export"), self.tr("&Build")) @@ -180,13 +178,13 @@ class GuiManuscriptBuild(QDialog): self.mainSplit = QSplitter() self.mainSplit.addWidget(self.formatWidget) - self.mainSplit.addWidget(self.swtOptions) + self.mainSplit.addWidget(self.contentWidget) self.mainSplit.setHandleWidth(CONFIG.pxInt(16)) self.mainSplit.setCollapsible(0, False) self.mainSplit.setCollapsible(1, False) self.mainSplit.setSizes([ - CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "fmtWidth", int(0.45*wWin))), - CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "optsWidth", int(0.55*wWin))), + CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "fmtWidth", wWin//2)), + CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "sumWidth", wWin//2)), ]) self.outerBox = QGridLayout() @@ -200,6 +198,7 @@ class GuiManuscriptBuild(QDialog): self.outerBox.addWidget(self.lblProgress, 5, 0, 1, 1) self.outerBox.addWidget(self.buildProgress, 5, 1, 1, 1) self.outerBox.addWidget(self.dlgButtons, 6, 0, 1, 2) + self.outerBox.setRowStretch(2, 1) self.setLayout(self.outerBox) @@ -209,6 +208,7 @@ class GuiManuscriptBuild(QDialog): self._doResetBuildName() self.btnBuild.setFocus() + self._populateContentList() logger.debug("Ready: GuiManuscriptBuild") @@ -294,16 +294,45 @@ class GuiManuscriptBuild(QDialog): winHeight = CONFIG.rpxInt(self.height()) mainSplit = self.mainSplit.sizes() - fmtWidth = CONFIG.rpxInt(mainSplit[0]) - optsWidth = CONFIG.rpxInt(mainSplit[1]) + fmtWidth = CONFIG.rpxInt(mainSplit[0]) + sumWidth = CONFIG.rpxInt(mainSplit[1]) pOptions = self.theProject.options pOptions.setValue("GuiManuscriptBuild", "winWidth", winWidth) pOptions.setValue("GuiManuscriptBuild", "winHeight", winHeight) pOptions.setValue("GuiManuscriptBuild", "fmtWidth", fmtWidth) - pOptions.setValue("GuiManuscriptBuild", "optsWidth", optsWidth) + pOptions.setValue("GuiManuscriptBuild", "sumWidth", sumWidth) pOptions.saveSettings() return + def _populateContentList(self): + """Build the content list.""" + rootMap = {} + filtered = self._build.buildItemFilter(self.theProject) + self.listContent.clear() + for nwItem in self.theProject.tree: + tHandle = nwItem.itemHandle + rHandle = nwItem.itemRoot + + if tHandle is None or rHandle is None or not nwItem.isFileType(): + continue + + if filtered.get(tHandle, (False, 0))[0]: + if rHandle not in rootMap: + rItem = self.theProject.tree[rHandle] + if isinstance(rItem, NWItem): + rootMap[rHandle] = rItem.itemName + + itemIcon = self.mainTheme.getItemIcon( + nwItem.itemType, nwItem.itemClass, + nwItem.itemLayout, nwItem.mainHeading + ) + rootName = rootMap.get(rHandle, "??????") + item = QListWidgetItem(f"{rootName}: {nwItem.itemName}") + item.setIcon(itemIcon) + self.listContent.addItem(item) + + return + # END Class GuiManuscriptBuild diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py index fbdbac8e..51bd3121 100644 --- a/novelwriter/tools/manuscript.py +++ b/novelwriter/tools/manuscript.py @@ -144,9 +144,12 @@ class GuiManuscript(QDialog): # ================ self.buildProgress = QProgressBar() + self.buildProgress.setValue(0) + self.btnPreview = QPushButton(self.tr("Build Preview")) self.btnPreview.clicked.connect(self._generatePreview) - self.manPreview = _PreviewWidget(self.mainGui) + + self.docPreview = _PreviewWidget(self.mainGui) self.btnBuild = QPushButton(self.tr("Build")) self.btnBuild.clicked.connect(self._buildManuscript) @@ -182,7 +185,7 @@ class GuiManuscript(QDialog): self.mainSplit = QSplitter() self.mainSplit.addWidget(self.optsWidget) - self.mainSplit.addWidget(self.manPreview) + self.mainSplit.addWidget(self.docPreview) self.mainSplit.setSizes([ CONFIG.pxInt(pOptions.getInt("GuiManuscript", "optsWidth", wWin//3)), CONFIG.pxInt(pOptions.getInt("GuiManuscript", "viewWidth", 2*wWin//3)), @@ -338,13 +341,13 @@ class GuiManuscript(QDialog): def _updatePreview(self, data: dict, build: BuildSettings): """Update the preview widget and set relevant values.""" - self.manPreview.setContent(data) - self.manPreview.setBuildName(build.name) - self.manPreview.setTextFont( + self.docPreview.setContent(data) + self.docPreview.setBuildName(build.name) + self.docPreview.setTextFont( build.getStr("format.textFont"), build.getInt("format.textSize") ) - self.manPreview.setJustify( + self.docPreview.setJustify( build.getBool("format.justifyText") ) return diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index a831f650..53da155d 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -435,11 +435,15 @@ class _FilterTab(QWidget): logger.debug("Building project tree") self._treeMap = {} self.optTree.clear() - for nwItem in self.theProject.getProjectItems(): + for nwItem in self.theProject.tree: tHandle = nwItem.itemHandle pHandle = nwItem.itemParent rHandle = nwItem.itemRoot + + if tHandle is None or rHandle is None: + continue + isFile = nwItem.isFileType() isActive = nwItem.isActive @@ -465,16 +469,10 @@ class _FilterTab(QWidget): trItem.setTextAlignment(self.C_NAME, Qt.AlignLeft) - if pHandle is None: - if nwItem.isRootType(): - self.optTree.addTopLevelItem(trItem) - else: - logger.debug("Skipping item '%s'", tHandle) - continue - + if pHandle is None and nwItem.isRootType(): + self.optTree.addTopLevelItem(trItem) elif pHandle in self._treeMap: self._treeMap[pHandle].addChild(trItem) - else: logger.debug("Skipping item '%s'", tHandle) continue