Make it possible to re-order build settings (#1591)

This commit is contained in:
Veronica Berglyd Olsen
2023-11-10 22:23:07 +01:00
committed by GitHub
3 changed files with 50 additions and 24 deletions
+39 -21
View File
@@ -156,6 +156,7 @@ class BuildSettings:
self._uuid = str(uuid.uuid4()) self._uuid = str(uuid.uuid4())
self._path = Path.home() self._path = Path.home()
self._build = "" self._build = ""
self._order = 0
self._format = nwBuildFmt.ODT self._format = nwBuildFmt.ODT
self._skipRoot = set() self._skipRoot = set()
self._excluded = set() self._excluded = set()
@@ -164,20 +165,32 @@ class BuildSettings:
self._changed = False self._changed = False
return return
@classmethod
def fromDict(cls, data: dict) -> BuildSettings:
"""Create a build settings object from a dict."""
cls = BuildSettings()
cls.unpack(data)
return cls
## ##
# Properties # Properties
## ##
@property @property
def name(self) -> str: def name(self) -> str:
"""The build name.""" """Return the build name."""
return self._name return self._name
@property @property
def buildID(self) -> str: def buildID(self) -> str:
"""The build ID as a UUID.""" """Return the build ID as a UUID."""
return self._uuid return self._uuid
@property
def order(self) -> int:
"""Return the build order."""
return self._order
@property @property
def lastPath(self) -> Path: def lastPath(self) -> Path:
"""The last used build path.""" """The last used build path."""
@@ -251,6 +264,12 @@ class BuildSettings:
self._uuid = value self._uuid = value
return return
def setOrder(self, value: int) -> None:
"""Set the build order."""
if isinstance(value, int):
self._order = value
return
def setLastPath(self, path: Path | str | None) -> None: def setLastPath(self, path: Path | str | None) -> None:
"""Set the last used build path.""" """Set the last used build path."""
if isinstance(path, str): if isinstance(path, str):
@@ -398,6 +417,7 @@ class BuildSettings:
"uuid": self._uuid, "uuid": self._uuid,
"path": str(self._path), "path": str(self._path),
"build": self._build, "build": self._build,
"order": self._order,
"format": self._format.name, "format": self._format.name,
"settings": self._settings.copy(), "settings": self._settings.copy(),
"content": { "content": {
@@ -409,14 +429,15 @@ class BuildSettings:
def unpack(self, data: dict) -> None: def unpack(self, data: dict) -> None:
"""Unpack a dictionary and populate the class.""" """Unpack a dictionary and populate the class."""
content = data.get("content", {})
settings = data.get("settings", {}) settings = data.get("settings", {})
content = data.get("content", {})
included = content.get("included", []) included = content.get("included", [])
excluded = content.get("excluded", []) excluded = content.get("excluded", [])
skipRoot = content.get("skipRoot", []) skipRoot = content.get("skipRoot", [])
self.setName(data.get("name", "")) self.setName(data.get("name", ""))
self.setBuildID(data.get("uuid", "")) self.setBuildID(data.get("uuid", ""))
self.setOrder(data.get("order", 0))
self.setLastPath(data.get("path", None)) self.setLastPath(data.get("path", None))
self.setLastBuildName(data.get("build", "")) self.setLastBuildName(data.get("build", ""))
@@ -453,9 +474,9 @@ class BuildCollection:
def __init__(self, project: NWProject) -> None: def __init__(self, project: NWProject) -> None:
self._project = project self._project = project
self._builds = {}
self._lastBuild = "" self._lastBuild = ""
self._defaultBuild = "" self._defaultBuild = ""
self._builds: dict[str, BuildSettings] = {}
self._loadCollection() self._loadCollection()
return return
@@ -483,21 +504,19 @@ class BuildCollection:
def getBuild(self, buildID: str) -> BuildSettings | None: def getBuild(self, buildID: str) -> BuildSettings | None:
"""Get a specific build settings object.""" """Get a specific build settings object."""
if buildID not in self._builds: return self._builds.get(buildID, None)
return None
build = BuildSettings()
build.unpack(self._builds[buildID])
return build
## ##
# Setters # Setters
## ##
def setLastBuild(self, buildID: str) -> None: def setBuildsState(self, lastBuild: str, order: list[str]) -> None:
"""Set the last active build id.""" """Set the last active build id."""
if buildID != self._lastBuild: for i, key in enumerate(order):
self._lastBuild = buildID if build := self._builds.get(key):
self._saveCollection() build.setOrder(i)
self._lastBuild = lastBuild
self._saveCollection()
return return
def setDefaultBuild(self, buildID: str) -> None: def setDefaultBuild(self, buildID: str) -> None:
@@ -510,8 +529,7 @@ class BuildCollection:
def setBuild(self, build: BuildSettings) -> None: def setBuild(self, build: BuildSettings) -> None:
"""Set build settings data in the collection.""" """Set build settings data in the collection."""
if isinstance(build, BuildSettings): if isinstance(build, BuildSettings):
buildID = build.buildID self._builds[build.buildID] = build
self._builds[buildID] = build.pack()
self._saveCollection() self._saveCollection()
return return
@@ -520,15 +538,15 @@ class BuildCollection:
## ##
def removeBuild(self, buildID: str) -> None: def removeBuild(self, buildID: str) -> None:
"""Remove the a build from the collection.""" """Remove a build from the collection."""
self._builds.pop(buildID, None) self._builds.pop(buildID, None)
self._saveCollection() self._saveCollection()
return return
def builds(self) -> Iterable[tuple[str, str]]: def builds(self) -> Iterable[tuple[str, str]]:
"""Iterate over all available builds.""" """Iterate over all available builds."""
for buildID in self._builds: for buildID, build in sorted(self._builds.items(), key=lambda x: x[1].order):
yield buildID, self._builds[buildID].get("name", "") yield buildID, build.name
return return
## ##
@@ -567,7 +585,7 @@ class BuildCollection:
elif key == "defaultBuild": elif key == "defaultBuild":
self._defaultBuild = str(entry) self._defaultBuild = str(entry)
elif isinstance(entry, dict): elif isinstance(entry, dict):
self._builds[key] = entry self._builds[key] = BuildSettings.fromDict(entry)
return True return True
@@ -579,11 +597,11 @@ class BuildCollection:
logger.debug("Saving builds file") logger.debug("Saving builds file")
try: try:
data = { data: dict[str, str | dict] = {
"lastBuild": self._lastBuild, "lastBuild": self._lastBuild,
"defaultBuild": self._defaultBuild, "defaultBuild": self._defaultBuild,
} }
data.update(self._builds) data.update({k: b.pack() for k, b in self._builds.items()})
with open(buildsFile, mode="w+", encoding="utf-8") as outFile: with open(buildsFile, mode="w+", encoding="utf-8") as outFile:
outFile.write(jsonEncode({"novelWriter.builds": data}, nmax=4)) outFile.write(jsonEncode({"novelWriter.builds": data}, nmax=4))
except Exception: except Exception:
+10 -2
View File
@@ -144,6 +144,8 @@ class GuiManuscript(QDialog):
self.buildList.setIconSize(QSize(iPx, iPx)) self.buildList.setIconSize(QSize(iPx, iPx))
self.buildList.doubleClicked.connect(self._editSelectedBuild) self.buildList.doubleClicked.connect(self._editSelectedBuild)
self.buildList.currentItemChanged.connect(self._updateBuildDetails) self.buildList.currentItemChanged.connect(self._updateBuildDetails)
self.buildList.setSelectionMode(QAbstractItemView.SingleSelection)
self.buildList.setDragDropMode(QAbstractItemView.InternalMove)
self.buildDetails = _DetailsWidget(self) self.buildDetails = _DetailsWidget(self)
self.buildDetails.setColumnWidth( self.buildDetails.setColumnWidth(
@@ -417,9 +419,15 @@ class GuiManuscript(QDialog):
"""Save the user GUI settings.""" """Save the user GUI settings."""
logger.debug("Saving GuiManuscript settings") logger.debug("Saving GuiManuscript settings")
buildOrder = []
for i in range(self.buildList.count()):
if item := self.buildList.item(i):
buildOrder.append(item.data(self.D_KEY))
current = self.buildList.currentItem() current = self.buildList.currentItem()
if isinstance(current, QListWidgetItem): lastBuild = current.data(self.D_KEY) if isinstance(current, QListWidgetItem) else ""
self._builds.setLastBuild(current.data(self.D_KEY))
self._builds.setBuildsState(lastBuild, buildOrder)
winWidth = CONFIG.rpxInt(self.width()) winWidth = CONFIG.rpxInt(self.width())
winHeight = CONFIG.rpxInt(self.height()) winHeight = CONFIG.rpxInt(self.height())
+1 -1
View File
@@ -435,7 +435,7 @@ def testCoreBuildSettings_Collection(monkeypatch, mockGUI, fncPath: Path, mockRn
(buildIDTwo, "Build Two"), (buildIDTwo, "Build Two"),
(buildIDOne, "Build One"), (buildIDOne, "Build One"),
] ]
builds.setLastBuild(buildIDOne) builds.setBuildsState(buildIDOne, [buildIDTwo, buildIDOne])
builds.setDefaultBuild(buildIDTwo) builds.setDefaultBuild(buildIDTwo)
# Check errors: No valid path # Check errors: No valid path