Add Table of Contents to build dialog
This commit is contained in:
@@ -72,9 +72,6 @@ SETTINGS_TEMPLATE = {
|
|||||||
"format.replaceTabs": (bool, False),
|
"format.replaceTabs": (bool, False),
|
||||||
"odt.addColours": (bool, True),
|
"odt.addColours": (bool, True),
|
||||||
"html.addStyles": (bool, False),
|
"html.addStyles": (bool, False),
|
||||||
"build.splitNovel": (bool, False),
|
|
||||||
"build.splitNotes": (bool, False),
|
|
||||||
"build.splitChapters": (bool, False),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SETTINGS_LABELS = {
|
SETTINGS_LABELS = {
|
||||||
@@ -115,11 +112,6 @@ SETTINGS_LABELS = {
|
|||||||
|
|
||||||
"html": QT_TRANSLATE_NOOP("Builds", "HTML"),
|
"html": QT_TRANSLATE_NOOP("Builds", "HTML"),
|
||||||
"html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"),
|
"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"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ VALID_MAP = {
|
|||||||
"winWidth", "winHeight", "optsWidth", "viewWidth"
|
"winWidth", "winHeight", "optsWidth", "viewWidth"
|
||||||
},
|
},
|
||||||
"GuiManuscriptBuild": {
|
"GuiManuscriptBuild": {
|
||||||
"winWidth", "winHeight", "fmtWidth", "optsWidth"
|
"winWidth", "winHeight", "fmtWidth", "sumWidth"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ import logging
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt, pyqtSlot
|
from PyQt5.QtCore import QSize, Qt, pyqtSlot
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QAbstractButton, QDialog, QDialogButtonBox, QFrame, QGridLayout,
|
QAbstractButton, QAbstractItemView, QDialog, QDialogButtonBox, QGridLayout,
|
||||||
QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem, QProgressBar,
|
QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem, QProgressBar,
|
||||||
QPushButton, QSplitter, QVBoxLayout, QWidget
|
QPushButton, QSplitter, QVBoxLayout, QWidget
|
||||||
)
|
)
|
||||||
@@ -37,8 +37,8 @@ from PyQt5.QtWidgets import (
|
|||||||
from novelwriter import CONFIG
|
from novelwriter import CONFIG
|
||||||
from novelwriter.common import makeFileNameSafe
|
from novelwriter.common import makeFileNameSafe
|
||||||
from novelwriter.constants import nwLabels
|
from novelwriter.constants import nwLabels
|
||||||
|
from novelwriter.core.item import NWItem
|
||||||
from novelwriter.core.buildsettings import BuildSettings
|
from novelwriter.core.buildsettings import BuildSettings
|
||||||
from novelwriter.extensions.switchbox import NSwitchBox
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from novelwriter.guimain import GuiMain
|
from novelwriter.guimain import GuiMain
|
||||||
@@ -70,8 +70,9 @@ class GuiManuscriptBuild(QDialog):
|
|||||||
|
|
||||||
self.setWindowTitle(self.tr("Build Manuscript"))
|
self.setWindowTitle(self.tr("Build Manuscript"))
|
||||||
self.setMinimumWidth(CONFIG.pxInt(500))
|
self.setMinimumWidth(CONFIG.pxInt(500))
|
||||||
self.setMinimumHeight(CONFIG.pxInt(250))
|
self.setMinimumHeight(CONFIG.pxInt(300))
|
||||||
|
|
||||||
|
iPx = self.mainTheme.baseIconSize
|
||||||
wWin = CONFIG.pxInt(660)
|
wWin = CONFIG.pxInt(660)
|
||||||
hWin = CONFIG.pxInt(390)
|
hWin = CONFIG.pxInt(390)
|
||||||
|
|
||||||
@@ -81,11 +82,12 @@ class GuiManuscriptBuild(QDialog):
|
|||||||
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "winHeight", hWin))
|
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "winHeight", hWin))
|
||||||
)
|
)
|
||||||
|
|
||||||
# Formats
|
# Output Format
|
||||||
# =======
|
# =============
|
||||||
|
|
||||||
self.lblFormat = QLabel("<b>{0}</b>".format(self.tr("Build Format")))
|
self.lblFormat = QLabel(self.tr("Output Format"))
|
||||||
self.listFormats = QListWidget()
|
self.listFormats = QListWidget()
|
||||||
|
self.listFormats.setIconSize(QSize(iPx, iPx))
|
||||||
current = None
|
current = None
|
||||||
for key, (_, label) in nwLabels.BUILD_FORMATS.items():
|
for key, (_, label) in nwLabels.BUILD_FORMATS.items():
|
||||||
item = QListWidgetItem()
|
item = QListWidgetItem()
|
||||||
@@ -106,28 +108,23 @@ class GuiManuscriptBuild(QDialog):
|
|||||||
self.formatWidget.setLayout(self.formatBox)
|
self.formatWidget.setLayout(self.formatBox)
|
||||||
self.formatWidget.setContentsMargins(0, 0, 0, 0)
|
self.formatWidget.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
# Build Controls
|
# Table of Contents
|
||||||
# ==============
|
# =================
|
||||||
|
|
||||||
# Build Options
|
self.lblContent = QLabel(self.tr("Table of Contents"))
|
||||||
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.swtOptions.addLabel(self._build.getLabel("build"))
|
self.listContent = QListWidget(self)
|
||||||
self.swtOptions.addItem(
|
self.listContent.setIconSize(QSize(iPx, iPx))
|
||||||
self.mainTheme.getIcon("cls_novel"), self._build.getLabel("build.splitNovel"),
|
self.listContent.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
|
||||||
"build.splitNovel", default=self._build.getBool("build.splitNovel")
|
|
||||||
)
|
self.contentBox = QVBoxLayout()
|
||||||
self.swtOptions.addItem(
|
self.contentBox.addWidget(self.lblContent, 0)
|
||||||
self.mainTheme.getIcon("cls_custom"), self._build.getLabel("build.splitNotes"),
|
self.contentBox.addWidget(self.listContent, 0)
|
||||||
"build.splitNotes", default=self._build.getBool("build.splitNotes")
|
self.contentBox.setContentsMargins(0, 0, 0, 0)
|
||||||
)
|
|
||||||
self.swtOptions.addItem(
|
self.contentWidget = QWidget()
|
||||||
self.mainTheme.getIcon("proj_chapter"), self._build.getLabel("build.splitChapters"),
|
self.contentWidget.setLayout(self.contentBox)
|
||||||
"build.splitChapters", default=self._build.getBool("build.splitChapters")
|
self.contentWidget.setContentsMargins(0, 0, 0, 0)
|
||||||
)
|
|
||||||
|
|
||||||
# Dialog Controls
|
# Dialog Controls
|
||||||
# ===============
|
# ===============
|
||||||
@@ -168,6 +165,7 @@ class GuiManuscriptBuild(QDialog):
|
|||||||
# Build Progress
|
# Build Progress
|
||||||
self.lblProgress = QLabel(self.tr("Build Progress"))
|
self.lblProgress = QLabel(self.tr("Build Progress"))
|
||||||
self.buildProgress = QProgressBar()
|
self.buildProgress = QProgressBar()
|
||||||
|
self.buildProgress.setValue(0)
|
||||||
|
|
||||||
# Dialog Buttons
|
# Dialog Buttons
|
||||||
self.btnBuild = QPushButton(self.mainTheme.getIcon("export"), self.tr("&Build"))
|
self.btnBuild = QPushButton(self.mainTheme.getIcon("export"), self.tr("&Build"))
|
||||||
@@ -180,13 +178,13 @@ class GuiManuscriptBuild(QDialog):
|
|||||||
|
|
||||||
self.mainSplit = QSplitter()
|
self.mainSplit = QSplitter()
|
||||||
self.mainSplit.addWidget(self.formatWidget)
|
self.mainSplit.addWidget(self.formatWidget)
|
||||||
self.mainSplit.addWidget(self.swtOptions)
|
self.mainSplit.addWidget(self.contentWidget)
|
||||||
self.mainSplit.setHandleWidth(CONFIG.pxInt(16))
|
self.mainSplit.setHandleWidth(CONFIG.pxInt(16))
|
||||||
self.mainSplit.setCollapsible(0, False)
|
self.mainSplit.setCollapsible(0, False)
|
||||||
self.mainSplit.setCollapsible(1, False)
|
self.mainSplit.setCollapsible(1, False)
|
||||||
self.mainSplit.setSizes([
|
self.mainSplit.setSizes([
|
||||||
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "fmtWidth", int(0.45*wWin))),
|
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "fmtWidth", wWin//2)),
|
||||||
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "optsWidth", int(0.55*wWin))),
|
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "sumWidth", wWin//2)),
|
||||||
])
|
])
|
||||||
|
|
||||||
self.outerBox = QGridLayout()
|
self.outerBox = QGridLayout()
|
||||||
@@ -200,6 +198,7 @@ class GuiManuscriptBuild(QDialog):
|
|||||||
self.outerBox.addWidget(self.lblProgress, 5, 0, 1, 1)
|
self.outerBox.addWidget(self.lblProgress, 5, 0, 1, 1)
|
||||||
self.outerBox.addWidget(self.buildProgress, 5, 1, 1, 1)
|
self.outerBox.addWidget(self.buildProgress, 5, 1, 1, 1)
|
||||||
self.outerBox.addWidget(self.dlgButtons, 6, 0, 1, 2)
|
self.outerBox.addWidget(self.dlgButtons, 6, 0, 1, 2)
|
||||||
|
self.outerBox.setRowStretch(2, 1)
|
||||||
|
|
||||||
self.setLayout(self.outerBox)
|
self.setLayout(self.outerBox)
|
||||||
|
|
||||||
@@ -209,6 +208,7 @@ class GuiManuscriptBuild(QDialog):
|
|||||||
self._doResetBuildName()
|
self._doResetBuildName()
|
||||||
|
|
||||||
self.btnBuild.setFocus()
|
self.btnBuild.setFocus()
|
||||||
|
self._populateContentList()
|
||||||
|
|
||||||
logger.debug("Ready: GuiManuscriptBuild")
|
logger.debug("Ready: GuiManuscriptBuild")
|
||||||
|
|
||||||
@@ -294,16 +294,45 @@ class GuiManuscriptBuild(QDialog):
|
|||||||
winHeight = CONFIG.rpxInt(self.height())
|
winHeight = CONFIG.rpxInt(self.height())
|
||||||
|
|
||||||
mainSplit = self.mainSplit.sizes()
|
mainSplit = self.mainSplit.sizes()
|
||||||
fmtWidth = CONFIG.rpxInt(mainSplit[0])
|
fmtWidth = CONFIG.rpxInt(mainSplit[0])
|
||||||
optsWidth = CONFIG.rpxInt(mainSplit[1])
|
sumWidth = CONFIG.rpxInt(mainSplit[1])
|
||||||
|
|
||||||
pOptions = self.theProject.options
|
pOptions = self.theProject.options
|
||||||
pOptions.setValue("GuiManuscriptBuild", "winWidth", winWidth)
|
pOptions.setValue("GuiManuscriptBuild", "winWidth", winWidth)
|
||||||
pOptions.setValue("GuiManuscriptBuild", "winHeight", winHeight)
|
pOptions.setValue("GuiManuscriptBuild", "winHeight", winHeight)
|
||||||
pOptions.setValue("GuiManuscriptBuild", "fmtWidth", fmtWidth)
|
pOptions.setValue("GuiManuscriptBuild", "fmtWidth", fmtWidth)
|
||||||
pOptions.setValue("GuiManuscriptBuild", "optsWidth", optsWidth)
|
pOptions.setValue("GuiManuscriptBuild", "sumWidth", sumWidth)
|
||||||
pOptions.saveSettings()
|
pOptions.saveSettings()
|
||||||
|
|
||||||
return
|
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
|
# END Class GuiManuscriptBuild
|
||||||
|
|||||||
@@ -144,9 +144,12 @@ class GuiManuscript(QDialog):
|
|||||||
# ================
|
# ================
|
||||||
|
|
||||||
self.buildProgress = QProgressBar()
|
self.buildProgress = QProgressBar()
|
||||||
|
self.buildProgress.setValue(0)
|
||||||
|
|
||||||
self.btnPreview = QPushButton(self.tr("Build Preview"))
|
self.btnPreview = QPushButton(self.tr("Build Preview"))
|
||||||
self.btnPreview.clicked.connect(self._generatePreview)
|
self.btnPreview.clicked.connect(self._generatePreview)
|
||||||
self.manPreview = _PreviewWidget(self.mainGui)
|
|
||||||
|
self.docPreview = _PreviewWidget(self.mainGui)
|
||||||
|
|
||||||
self.btnBuild = QPushButton(self.tr("Build"))
|
self.btnBuild = QPushButton(self.tr("Build"))
|
||||||
self.btnBuild.clicked.connect(self._buildManuscript)
|
self.btnBuild.clicked.connect(self._buildManuscript)
|
||||||
@@ -182,7 +185,7 @@ class GuiManuscript(QDialog):
|
|||||||
|
|
||||||
self.mainSplit = QSplitter()
|
self.mainSplit = QSplitter()
|
||||||
self.mainSplit.addWidget(self.optsWidget)
|
self.mainSplit.addWidget(self.optsWidget)
|
||||||
self.mainSplit.addWidget(self.manPreview)
|
self.mainSplit.addWidget(self.docPreview)
|
||||||
self.mainSplit.setSizes([
|
self.mainSplit.setSizes([
|
||||||
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "optsWidth", wWin//3)),
|
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "optsWidth", wWin//3)),
|
||||||
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "viewWidth", 2*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):
|
def _updatePreview(self, data: dict, build: BuildSettings):
|
||||||
"""Update the preview widget and set relevant values."""
|
"""Update the preview widget and set relevant values."""
|
||||||
self.manPreview.setContent(data)
|
self.docPreview.setContent(data)
|
||||||
self.manPreview.setBuildName(build.name)
|
self.docPreview.setBuildName(build.name)
|
||||||
self.manPreview.setTextFont(
|
self.docPreview.setTextFont(
|
||||||
build.getStr("format.textFont"),
|
build.getStr("format.textFont"),
|
||||||
build.getInt("format.textSize")
|
build.getInt("format.textSize")
|
||||||
)
|
)
|
||||||
self.manPreview.setJustify(
|
self.docPreview.setJustify(
|
||||||
build.getBool("format.justifyText")
|
build.getBool("format.justifyText")
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -435,11 +435,15 @@ class _FilterTab(QWidget):
|
|||||||
logger.debug("Building project tree")
|
logger.debug("Building project tree")
|
||||||
self._treeMap = {}
|
self._treeMap = {}
|
||||||
self.optTree.clear()
|
self.optTree.clear()
|
||||||
for nwItem in self.theProject.getProjectItems():
|
for nwItem in self.theProject.tree:
|
||||||
|
|
||||||
tHandle = nwItem.itemHandle
|
tHandle = nwItem.itemHandle
|
||||||
pHandle = nwItem.itemParent
|
pHandle = nwItem.itemParent
|
||||||
rHandle = nwItem.itemRoot
|
rHandle = nwItem.itemRoot
|
||||||
|
|
||||||
|
if tHandle is None or rHandle is None:
|
||||||
|
continue
|
||||||
|
|
||||||
isFile = nwItem.isFileType()
|
isFile = nwItem.isFileType()
|
||||||
isActive = nwItem.isActive
|
isActive = nwItem.isActive
|
||||||
|
|
||||||
@@ -465,16 +469,10 @@ class _FilterTab(QWidget):
|
|||||||
|
|
||||||
trItem.setTextAlignment(self.C_NAME, Qt.AlignLeft)
|
trItem.setTextAlignment(self.C_NAME, Qt.AlignLeft)
|
||||||
|
|
||||||
if pHandle is None:
|
if pHandle is None and nwItem.isRootType():
|
||||||
if nwItem.isRootType():
|
self.optTree.addTopLevelItem(trItem)
|
||||||
self.optTree.addTopLevelItem(trItem)
|
|
||||||
else:
|
|
||||||
logger.debug("Skipping item '%s'", tHandle)
|
|
||||||
continue
|
|
||||||
|
|
||||||
elif pHandle in self._treeMap:
|
elif pHandle in self._treeMap:
|
||||||
self._treeMap[pHandle].addChild(trItem)
|
self._treeMap[pHandle].addChild(trItem)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.debug("Skipping item '%s'", tHandle)
|
logger.debug("Skipping item '%s'", tHandle)
|
||||||
continue
|
continue
|
||||||
|
|||||||
Reference in New Issue
Block a user