Export the entire novel structure from the Outline view
This commit is contained in:
@@ -608,6 +608,10 @@ class Index:
|
|||||||
yield from tItem.items()
|
yield from tItem.items()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def getStoryKeys(self) -> set[str]:
|
||||||
|
"""Return all story structure keys."""
|
||||||
|
return self._itemIndex.allStoryKeys()
|
||||||
|
|
||||||
def novelStructure(
|
def novelStructure(
|
||||||
self, rootHandle: str | None = None, activeOnly: bool = True
|
self, rootHandle: str | None = None, activeOnly: bool = True
|
||||||
) -> Iterable[tuple[str, str, str, IndexHeading]]:
|
) -> Iterable[tuple[str, str, str, IndexHeading]]:
|
||||||
@@ -956,6 +960,10 @@ class ItemIndex:
|
|||||||
self._items[tHandle] = IndexNode(self._cache, tHandle, nwItem)
|
self._items[tHandle] = IndexNode(self._cache, tHandle, nwItem)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def allStoryKeys(self) -> set[str]:
|
||||||
|
"""Return all story structure keys."""
|
||||||
|
return self._cache.story.copy()
|
||||||
|
|
||||||
def allItemTags(self, tHandle: str) -> list[str]:
|
def allItemTags(self, tHandle: str) -> list[str]:
|
||||||
"""Get all tags set for headings of an item."""
|
"""Get all tags set for headings of an item."""
|
||||||
if tHandle in self._items:
|
if tHandle in self._items:
|
||||||
|
|||||||
@@ -557,14 +557,11 @@ class GuiOutlineTree(QTreeWidget):
|
|||||||
)[0]:
|
)[0]:
|
||||||
CONFIG.setLastPath("outline", path)
|
CONFIG.setLastPath("outline", path)
|
||||||
logger.info("Writing CSV file: %s", path)
|
logger.info("Writing CSV file: %s", path)
|
||||||
cols = [col for col in self._treeOrder if not self._colHidden[col]]
|
|
||||||
order = [self._colIdx[col] for col in cols]
|
|
||||||
with open(path, mode="w", newline="", encoding="utf-8") as csvFile:
|
with open(path, mode="w", newline="", encoding="utf-8") as csvFile:
|
||||||
writer = csv.writer(csvFile, dialect="excel", quoting=csv.QUOTE_ALL)
|
writer = csv.writer(csvFile, dialect="excel", quoting=csv.QUOTE_ALL)
|
||||||
writer.writerow([trConst(nwLabels.OUTLINE_COLS[col]) for col in cols])
|
writer.writerows(
|
||||||
for i in range(self.topLevelItemCount()):
|
self._dumpNovelData(self.outlineView.outlineBar.novelValue.handle)
|
||||||
if item := self.topLevelItem(i):
|
)
|
||||||
writer.writerow(item.text(i) for i in order)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -751,6 +748,69 @@ class GuiOutlineTree(QTreeWidget):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _dumpNovelData(self, rootHandle: str | None) -> list[list[str | int]]:
|
||||||
|
"""Dump all novel data into a table."""
|
||||||
|
sLabel = SHARED.project.localLookup("Story Structure")
|
||||||
|
sKeys = sorted(SHARED.project.index.getStoryKeys())
|
||||||
|
sMatch = [f"story.{k}" for k in sKeys]
|
||||||
|
sHeaders = [f"{sLabel} ({k})" for k in sKeys]
|
||||||
|
|
||||||
|
data: list[list[str | int]] = [[
|
||||||
|
"H",
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.TITLE]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.LABEL]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.LINE]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.STATUS]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.CCOUNT]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.WCOUNT]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.PCOUNT]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.POV]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.FOCUS]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.CHAR]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.PLOT]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.TIME]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.WORLD]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.OBJECT]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.ENTITY]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.CUSTOM]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.STORY]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.MENTION]),
|
||||||
|
trConst(nwLabels.OUTLINE_COLS[nwOutline.SYNOP]),
|
||||||
|
*sHeaders,
|
||||||
|
]]
|
||||||
|
|
||||||
|
for _, tHandle, sTitle, novIdx in SHARED.project.index.novelStructure(
|
||||||
|
rootHandle=rootHandle, activeOnly=True
|
||||||
|
):
|
||||||
|
if novIdx.level != "H0" and (nwItem := SHARED.project.tree[tHandle]):
|
||||||
|
refs = SHARED.project.index.getReferences(tHandle, sTitle)
|
||||||
|
story = {k: v for k, v in novIdx.comments.items() if k in sMatch}.values()
|
||||||
|
data.append([
|
||||||
|
novIdx.level,
|
||||||
|
novIdx.title,
|
||||||
|
nwItem.itemName,
|
||||||
|
novIdx.line,
|
||||||
|
nwItem.getImportStatus()[0],
|
||||||
|
novIdx.charCount,
|
||||||
|
novIdx.wordCount,
|
||||||
|
novIdx.paraCount,
|
||||||
|
", ".join(refs[nwKeyWords.POV_KEY]),
|
||||||
|
", ".join(refs[nwKeyWords.FOCUS_KEY]),
|
||||||
|
", ".join(refs[nwKeyWords.CHAR_KEY]),
|
||||||
|
", ".join(refs[nwKeyWords.PLOT_KEY]),
|
||||||
|
", ".join(refs[nwKeyWords.TIME_KEY]),
|
||||||
|
", ".join(refs[nwKeyWords.WORLD_KEY]),
|
||||||
|
", ".join(refs[nwKeyWords.OBJECT_KEY]),
|
||||||
|
", ".join(refs[nwKeyWords.ENTITY_KEY]),
|
||||||
|
", ".join(refs[nwKeyWords.CUSTOM_KEY]),
|
||||||
|
", ".join(refs[nwKeyWords.STORY_KEY]),
|
||||||
|
", ".join(refs[nwKeyWords.MENTION_KEY]),
|
||||||
|
novIdx.synopsis,
|
||||||
|
*story,
|
||||||
|
])
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
class GuiOutlineHeaderMenu(QMenu):
|
class GuiOutlineHeaderMenu(QMenu):
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user