Update Project Details for multi-novel projects (#1130)

This commit is contained in:
Veronica Berglyd Olsen
2022-10-01 22:11:21 +02:00
committed by GitHub
3 changed files with 66 additions and 18 deletions
+4 -2
View File
@@ -498,13 +498,15 @@ class NWIndex:
""" """
return self._itemIndex.mainItemHeader(tHandle) return self._itemIndex.mainItemHeader(tHandle)
def getTableOfContents(self, maxDepth, skipExcl=True): def getTableOfContents(self, rootHandle, maxDepth, skipExcl=True):
"""Generate a table of contents up to a maximum depth. """Generate a table of contents up to a maximum depth.
""" """
tOrder = [] tOrder = []
tData = {} tData = {}
pKey = None pKey = None
for tHandle, sTitle, hItem in self._itemIndex.iterNovelStructure(skipExcl=skipExcl): for tHandle, sTitle, hItem in self._itemIndex.iterNovelStructure(
rootHandle=rootHandle, skipExcl=skipExcl
):
tKey = f"{tHandle}:{sTitle}" tKey = f"{tHandle}:{sTitle}"
iLevel = nwHeaders.H_LEVEL.get(hItem.level, 0) iLevel = nwHeaders.H_LEVEL.get(hItem.level, 0)
if iLevel > maxDepth: if iLevel > maxDepth:
+56 -10
View File
@@ -27,15 +27,17 @@ import math
import logging import logging
import novelwriter import novelwriter
from PyQt5.QtCore import Qt, QSize from PyQt5.QtCore import Qt, QSize, pyqtSlot
from PyQt5.QtGui import QFont from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QWidget, QDialogButtonBox, QVBoxLayout, QTreeWidget, QTreeWidgetItem, QAbstractItemView, QComboBox, QDialogButtonBox, QGridLayout, QHBoxLayout,
QLabel, QSpinBox, QGridLayout, QHBoxLayout, QLineEdit, QAbstractItemView QLabel, QLineEdit, QSpinBox, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
QWidget
) )
from novelwriter.enum import nwItemClass
from novelwriter.common import numberToRoman from novelwriter.common import numberToRoman
from novelwriter.constants import nwUnicode from novelwriter.constants import nwLabels, nwUnicode
from novelwriter.gui.custom import PagedDialog, QSwitch from novelwriter.gui.custom import PagedDialog, QSwitch
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -281,12 +283,26 @@ class GuiProjectDetailsContents(QWidget):
# Internal # Internal
self._theToC = [] self._theToC = []
self._currentRoot = None
iPx = self.mainTheme.baseIconSize iPx = self.mainTheme.baseIconSize
hPx = self.mainConf.pxInt(12) hPx = self.mainConf.pxInt(12)
vPx = self.mainConf.pxInt(4) vPx = self.mainConf.pxInt(4)
pOptions = self.theProject.options pOptions = self.theProject.options
# Header
# ======
self.tocLabel = QLabel("<b>%s</b>" % self.tr("Table of Contents"))
self.novelValue = QComboBox(self)
self.novelValue.setMinimumWidth(self.mainConf.pxInt(200))
self.novelValue.currentIndexChanged.connect(self._novelValueChanged)
self.headBox = QHBoxLayout()
self.headBox.addWidget(self.tocLabel)
self.headBox.addWidget(self.novelValue)
# Contents Tree # Contents Tree
# ============= # =============
@@ -389,7 +405,7 @@ class GuiProjectDetailsContents(QWidget):
# ======== # ========
self.outerBox = QVBoxLayout() self.outerBox = QVBoxLayout()
self.outerBox.addWidget(QLabel("<b>%s</b>" % self.tr("Table of Contents"))) self.outerBox.addLayout(self.headBox)
self.outerBox.addWidget(self.tocTree) self.outerBox.addWidget(self.tocTree)
self.outerBox.addLayout(self.optionsBox) self.outerBox.addLayout(self.optionsBox)
@@ -412,19 +428,37 @@ class GuiProjectDetailsContents(QWidget):
def updateValues(self): def updateValues(self):
"""Populate the tree. """Populate the tree.
""" """
self._prepareData() self._currentRoot = None
self._populateNovelList()
rootHandle = self.novelValue.currentData()
self._prepareData(rootHandle)
self._populateTree() self._populateTree()
return return
## ##
# Internal Functions # Internal Functions
## ##
def _prepareData(self): def _populateNovelList(self):
"""Extract the data for the tree. """Fill the novel combo box with a list of all novel folders.
""" """
self._theToC = [] self.novelValue.clear()
self._theToC = self.theProject.index.getTableOfContents(2)
tIcon = self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL])
for tHandle, nwItem in self.theProject.tree.iterRoots(nwItemClass.NOVEL):
self.novelValue.addItem(tIcon, nwItem.itemName, tHandle)
self.novelValue.setVisible(self.novelValue.count() > 1)
return
def _prepareData(self, rootHandle):
"""Extract the information from the project index.
"""
logger.debug("Populating ToC from handle '%s'", rootHandle)
self._theToC = self.theProject.index.getTableOfContents(rootHandle, 2)
self._theToC.append(("", 0, self.tr("END"), 0)) self._theToC.append(("", 0, self.tr("END"), 0))
return return
@@ -432,6 +466,18 @@ class GuiProjectDetailsContents(QWidget):
# Slots # Slots
## ##
@pyqtSlot()
def _novelValueChanged(self):
"""Refresh the tree with another root item.
"""
rootHandle = self.novelValue.currentData()
if rootHandle != self._currentRoot:
self._prepareData(rootHandle)
self._populateTree()
self._currentRoot = rootHandle
return
@pyqtSlot()
def _populateTree(self): def _populateTree(self):
"""Set the content of the chapter/page tree. """Set the content of the chapter/page tree.
""" """
+6 -6
View File
@@ -709,16 +709,16 @@ def testCoreIndex_ExtractData(mockGUI, fncDir, mockRnd):
assert theIndex.getNovelTitleCounts(skipExcl=True) == [0, 1, 2, 3, 0] assert theIndex.getNovelTitleCounts(skipExcl=True) == [0, 1, 2, 3, 0]
# Table of Contents # Table of Contents
assert theIndex.getTableOfContents(0, skipExcl=True) == [] assert theIndex.getTableOfContents("0000000000010", 0, skipExcl=True) == []
assert theIndex.getTableOfContents(1, skipExcl=True) == [ assert theIndex.getTableOfContents("0000000000010", 1, skipExcl=True) == [
("0000000000014:T000001", 1, "New Novel", 15), ("0000000000014:T000001", 1, "New Novel", 15),
] ]
assert theIndex.getTableOfContents(2, skipExcl=True) == [ assert theIndex.getTableOfContents("0000000000010", 2, skipExcl=True) == [
("0000000000014:T000001", 1, "New Novel", 5), ("0000000000014:T000001", 1, "New Novel", 5),
("0000000000016:T000001", 2, "New Chapter", 4), ("0000000000016:T000001", 2, "New Chapter", 4),
("%s:T000001" % hHandle, 2, "Chapter One", 6), ("%s:T000001" % hHandle, 2, "Chapter One", 6),
] ]
assert theIndex.getTableOfContents(3, skipExcl=True) == [ assert theIndex.getTableOfContents("0000000000010", 3, skipExcl=True) == [
("0000000000014:T000001", 1, "New Novel", 5), ("0000000000014:T000001", 1, "New Novel", 5),
("0000000000016:T000001", 2, "New Chapter", 2), ("0000000000016:T000001", 2, "New Chapter", 2),
("0000000000017:T000001", 3, "New Scene", 2), ("0000000000017:T000001", 3, "New Scene", 2),
@@ -727,8 +727,8 @@ def testCoreIndex_ExtractData(mockGUI, fncDir, mockRnd):
("%s:T000001" % tHandle, 3, "Scene Two", 2), ("%s:T000001" % tHandle, 3, "Scene Two", 2),
] ]
assert theIndex.getTableOfContents(0, skipExcl=False) == [] assert theIndex.getTableOfContents("0000000000010", 0, skipExcl=False) == []
assert theIndex.getTableOfContents(1, skipExcl=False) == [ assert theIndex.getTableOfContents("0000000000010", 1, skipExcl=False) == [
("0000000000014:T000001", 1, "New Novel", 9), ("0000000000014:T000001", 1, "New Novel", 9),
("%s:T000001" % nHandle, 1, "Hello World!", 12), ("%s:T000001" % nHandle, 1, "Hello World!", 12),
("%s:T000011" % nHandle, 1, "Hello World!", 22), ("%s:T000011" % nHandle, 1, "Hello World!", 22),