Add list of builds to manuscript build dialog

This commit is contained in:
Veronica Berglyd Olsen
2023-05-22 18:38:58 +02:00
parent 0a2355488e
commit 854cc77220
4 changed files with 184 additions and 31 deletions
+1
View File
@@ -85,6 +85,7 @@ class nwFiles:
OPTS_FILE = "guiOptions.json"
RECENT_FILE = "recentProjects.json"
BUILD_CACHE = "prevBuild.json"
BUILDS_FILE = "builds.json"
# END Class nwFiles
+104 -9
View File
@@ -4,7 +4,8 @@ novelWriter Build Settings Class
A class to hold build settings for the build tool
File History:
Created: 2023-02-14 [2.1b1]
Created: 2023-02-14 [2.1b1] BuildSettings
Created: 2023-05-22 [2.1b1] BuildCollection
This file is a part of novelWriter
Copyright 20182023, Veronica Berglyd Olsen
@@ -24,17 +25,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
import json
import uuid
import logging
from enum import Enum
from typing import Iterable
from pathlib import Path
from PyQt5.QtCore import QT_TRANSLATE_NOOP
from novelwriter.common import checkUuid, isHandle
from novelwriter.constants import nwHeadingFormats
from novelwriter.common import checkUuid, isHandle, jsonEncode
from novelwriter.constants import nwFiles, nwHeadingFormats
from novelwriter.core.item import NWItem
from novelwriter.core.project import NWProject
from novelwriter.error import logException
logger = logging.getLogger(__name__)
@@ -305,18 +310,21 @@ class BuildSettings:
"name": self._name,
"uuid": self._uuid,
"settings": self._settings.copy(),
"included": list(self._included),
"excluded": list(self._excluded),
"skipRoot": list(self._skipRoot),
"content": {
"included": list(self._included),
"excluded": list(self._excluded),
"skipRoot": list(self._skipRoot),
}
}
def unpack(self, data: dict):
"""Unpack a dictionary and populate the class.
"""
included = data.get("included", [])
excluded = data.get("excluded", [])
skipRoot = data.get("skipRoot", [])
settings = data.get("settings", {})
content = data.get("content", {})
included = content.get("included", [])
excluded = content.get("excluded", [])
skipRoot = content.get("skipRoot", [])
self.setName(data.get("name", ""))
self.setBuildID(data.get("uuid", ""))
@@ -337,3 +345,90 @@ class BuildSettings:
return
# END Class BuildSettings
class BuildCollection:
def __init__(self, project: NWProject):
self._project = project
self._builds = {}
return
def getBuild(self, buildID: str) -> BuildSettings | None:
"""
"""
if buildID not in self._builds:
return None
build = BuildSettings()
build.unpack(self._builds[buildID])
return build
def setBuild(self, build: BuildSettings) -> bool:
"""
"""
if not isinstance(build, BuildSettings):
return False
buildID = build.buildID
self._builds[buildID] = build.pack()
return True
def builds(self) -> Iterable[tuple[str, str]]:
"""
"""
for buildID in self._builds:
yield buildID, self._builds[buildID].get("name", "")
return
def loadCollection(self) -> bool:
"""
"""
buildsFile = self._project.storage.getMetaFile(nwFiles.BUILDS_FILE)
if not isinstance(buildsFile, Path):
return False
data = {}
if buildsFile.exists():
logger.debug("Loading builds file")
try:
with open(buildsFile, mode="r", encoding="utf-8") as inFile:
data = json.load(inFile)
except Exception:
logger.error("Failed to load builds file")
logException()
return False
if not isinstance(data, dict):
logger.error("Builds file is not a JSON object")
return False
builds = data.get("novelWriter.builds", None)
if not isinstance(builds, dict):
logger.error("No novelWriter.builds in the builds file")
return False
for key, entry in builds.items():
if isinstance(entry, dict):
self._builds[key] = entry
return True
def saveCollection(self) -> bool:
"""
"""
buildsFile = self._project.storage.getMetaFile(nwFiles.BUILDS_FILE)
if not isinstance(buildsFile, Path):
return False
logger.debug("Saving builds file")
try:
data = {"novelWriter.builds": self._builds}
with open(buildsFile, mode="w+", encoding="utf-8") as outFile:
outFile.write(jsonEncode(data, nmax=4))
except Exception:
logger.error("Failed to save builds file")
logException()
return False
return True
# END Class BuildCollection
+77 -20
View File
@@ -28,14 +28,14 @@ import logging
from typing import TYPE_CHECKING
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtCore import Qt, pyqtSlot
from PyQt5.QtWidgets import (
QDialog, QGridLayout, QPushButton, QSplitter, QTextBrowser, QVBoxLayout,
QWidget, qApp
QDialog, QHBoxLayout, QListWidget, QListWidgetItem, QPushButton, QSplitter,
QTextBrowser, QVBoxLayout, QWidget, qApp
)
from novelwriter import CONFIG
from novelwriter.core.buildsettings import BuildSettings
from novelwriter.core.buildsettings import BuildCollection, BuildSettings
from novelwriter.tools.manussettings import GuiBuildSettings
if TYPE_CHECKING:
@@ -53,6 +53,9 @@ class GuiBuildManuscript(QDialog):
self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self._builds = BuildCollection(self.theProject)
self._buildMap = {}
self.setWindowTitle(self.tr("Build Manuscript"))
self.setMinimumWidth(CONFIG.pxInt(600))
self.setMinimumHeight(CONFIG.pxInt(500))
@@ -69,19 +72,32 @@ class GuiBuildManuscript(QDialog):
# Controls
# ========
self.btnNew = QPushButton(self.tr("New Build"))
self.buildList = QListWidget()
self.btnNew = QPushButton(self.tr("New"))
self.btnNew.clicked.connect(self._createNewBuild)
self.optsGrid = QGridLayout()
self.optsGrid.addWidget(self.btnNew, 0, 0)
self.btnEdit = QPushButton(self.tr("Edit"))
self.btnEdit.clicked.connect(self._editSelectedBuild)
self.btnDel = QPushButton(self.tr("Delete"))
self.buttonBox = QHBoxLayout()
self.buttonBox.addWidget(self.btnNew)
self.buttonBox.addWidget(self.btnEdit)
self.buttonBox.addWidget(self.btnDel)
self.manPreview = GuiManuscriptPreview(self)
# Assemble GUI
# ============
self.controlBox = QVBoxLayout()
self.controlBox.addWidget(self.buildList)
self.controlBox.addLayout(self.buttonBox)
self.optsWidget = QWidget()
self.optsWidget.setLayout(self.optsGrid)
self.optsWidget.setLayout(self.controlBox)
self.mainSplit = QSplitter()
self.mainSplit.addWidget(self.optsWidget)
@@ -101,6 +117,8 @@ class GuiBuildManuscript(QDialog):
def loadContent(self):
"""
"""
self._builds.loadCollection()
self._updateBuildsList()
return
##
@@ -124,22 +142,27 @@ class GuiBuildManuscript(QDialog):
"""
build = BuildSettings()
build.setName(self.tr("My Manuscript"))
dlgSettings = GuiBuildSettings(self.mainGui, build)
dlgSettings.setModal(False)
dlgSettings.show()
dlgSettings.raise_()
qApp.processEvents()
dlgSettings.loadContent()
dlgSettings.newSettingsReady.connect(self._processNewSettings)
self._openSettingsDialog(build)
return
@pyqtSlot(dict)
def _processNewSettings(self, data: dict):
@pyqtSlot()
def _editSelectedBuild(self):
"""Edit the currently selected build settings entry.
"""
bItems = self.buildList.selectedItems()
if bItems:
build = self._builds.getBuild(bItems[0].data(Qt.UserRole))
if isinstance(build, BuildSettings):
self._openSettingsDialog(build)
return
@pyqtSlot(BuildSettings)
def _processNewSettings(self, build: BuildSettings):
"""Process new build settings from the settings dialog.
"""
print(data)
self._builds.setBuild(build)
self._builds.saveCollection()
self._updateBuildItem(build)
return
##
@@ -167,6 +190,40 @@ class GuiBuildManuscript(QDialog):
return
def _openSettingsDialog(self, build: BuildSettings):
"""Open a new build settings dialog.
"""
dlgSettings = GuiBuildSettings(self.mainGui, build)
dlgSettings.setModal(False)
dlgSettings.show()
dlgSettings.raise_()
qApp.processEvents()
dlgSettings.loadContent()
dlgSettings.newSettingsReady.connect(self._processNewSettings)
return
def _updateBuildsList(self):
"""Update the list of available builds.
"""
self.buildList.clear()
for key, name in self._builds.builds():
bItem = QListWidgetItem()
bItem.setText(name)
bItem.setData(Qt.UserRole, key)
self.buildList.addItem(bItem)
self._buildMap[key] = bItem
return
def _updateBuildItem(self, build: BuildSettings):
"""Update the entry of a specific build item.
"""
bItem = self._buildMap.get(build.buildID, None)
if isinstance(bItem, QListWidgetItem):
bItem.setText(build.name)
else: # Propbably a new item
self._updateBuildsList()
return
# END Class GuiBuildManuscript
+2 -2
View File
@@ -59,7 +59,7 @@ class GuiBuildSettings(QDialog):
OPT_CONTENT = 4
OPT_OUTPUT = 5
newSettingsReady = pyqtSignal(dict)
newSettingsReady = pyqtSignal(BuildSettings)
def __init__(self, mainGui: GuiMain, build: BuildSettings):
super().__init__(parent=mainGui)
@@ -194,7 +194,7 @@ class GuiBuildSettings(QDialog):
role = self.dlgButtons.buttonRole(button)
if role in (QDialogButtonBox.ApplyRole, QDialogButtonBox.AcceptRole):
self._build.setName(self.editBuildName.text())
self.newSettingsReady.emit(self._build.pack())
self.newSettingsReady.emit(self._build)
self._saveSettings()
if role == QDialogButtonBox.AcceptRole: