Make it possible to re-order build settings (#1591)
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user