diff --git a/nw/core/index.py b/nw/core/index.py index fd1ad776..ba2e06f3 100644 --- a/nw/core/index.py +++ b/nw/core/index.py @@ -627,7 +627,7 @@ class NWIndex(): pKey = tKey tOrder.append(tKey) tData[tKey] = { - "level": theData["level"], + "level": iLevel, "title": theData["title"], "words": theData["wCount"], } @@ -635,7 +635,10 @@ class NWIndex(): theToC = [] for tKey in tOrder: theToC.append(( - tKey, tData[tKey]["level"], tData[tKey]["title"], tData[tKey]["words"] + tKey, + tData[tKey]["level"], + tData[tKey]["title"], + tData[tKey]["words"], )) return theToC diff --git a/nw/core/options.py b/nw/core/options.py index 5f50370c..36da3f32 100644 --- a/nw/core/options.py +++ b/nw/core/options.py @@ -96,6 +96,7 @@ class OptionState(): "widthCol3", "widthCol4", "wordsPerPage", + "countFrom", "clearDouble", }, } diff --git a/nw/gui/projdetails.py b/nw/gui/projdetails.py index 1eb8fa99..7b46b39d 100644 --- a/nw/gui/projdetails.py +++ b/nw/gui/projdetails.py @@ -38,6 +38,7 @@ from PyQt5.QtWidgets import ( from nw.gui.custom import PagedDialog, QSwitch from nw.constants import nwUnicode +from nw.core import numberToRoman logger = logging.getLogger(__name__) @@ -109,6 +110,7 @@ class GuiProjectDetails(PagedDialog): widthCol4 = self.mainConf.rpxInt(cColWidth[4]) wordsPerPage = self.tabContents.wpValue.value() + countFrom = self.tabContents.poValue.value() clearDouble = self.tabContents.dblValue.isChecked() self.optState.setValue("GuiProjectDetails", "winWidth", winWidth) @@ -119,6 +121,7 @@ class GuiProjectDetails(PagedDialog): self.optState.setValue("GuiProjectDetails", "widthCol3", widthCol3) self.optState.setValue("GuiProjectDetails", "widthCol4", widthCol4) self.optState.setValue("GuiProjectDetails", "wordsPerPage", wordsPerPage) + self.optState.setValue("GuiProjectDetails", "countFrom", countFrom) self.optState.setValue("GuiProjectDetails", "clearDouble", clearDouble) return @@ -259,6 +262,7 @@ class GuiProjectDetailsContents(QWidget): iPx = self.theTheme.baseIconSize hPx = self.mainConf.pxInt(12) + vPx = self.mainConf.pxInt(4) # Contents Tree # ============= @@ -296,11 +300,15 @@ class GuiProjectDetailsContents(QWidget): # ======= wordsPerPage = self.optState.getInt("GuiProjectDetails", "wordsPerPage", 350) + countFrom = self.optState.getInt("GuiProjectDetails", "countFrom", 1) clearDouble = self.optState.getInt("GuiProjectDetails", "clearDouble", True) wordsHelp = ( "Typical word count for a 5 by 8 inch book page with 11 pt font is 350." ) + offsetHelp = ( + "Start counting page numbers from this page." + ) dblHelp = ( "Assume a new chapter or partition always start on an odd numbered page." ) @@ -316,6 +324,17 @@ class GuiProjectDetailsContents(QWidget): self.wpValue.setToolTip(wordsHelp) self.wpValue.valueChanged.connect(self._populateTree) + self.poLabel = QLabel("Count pages from") + self.poLabel.setToolTip(offsetHelp) + + self.poValue = QSpinBox() + self.poValue.setMinimum(1) + self.poValue.setMaximum(9999) + self.poValue.setSingleStep(1) + self.poValue.setValue(countFrom) + self.poValue.setToolTip(offsetHelp) + self.poValue.valueChanged.connect(self._populateTree) + self.dblLabel = QLabel("Clear double pages") self.dblLabel.setToolTip(dblHelp) @@ -324,18 +343,22 @@ class GuiProjectDetailsContents(QWidget): self.dblValue.setToolTip(dblHelp) self.dblValue.clicked.connect(self._populateTree) - self.optionsBox = QHBoxLayout() - self.optionsBox.addWidget(self.wpLabel) - self.optionsBox.addWidget(self.wpValue) - self.optionsBox.addStretch(1) - self.optionsBox.addWidget(self.dblLabel) - self.optionsBox.addWidget(self.dblValue) - self.optionsBox.setSpacing(hPx) + self.optionsBox = QGridLayout() + self.optionsBox.addWidget(self.wpLabel, 0, 0) + self.optionsBox.addWidget(self.wpValue, 0, 1) + self.optionsBox.addWidget(self.dblLabel, 0, 3) + self.optionsBox.addWidget(self.dblValue, 0, 4) + self.optionsBox.addWidget(self.poLabel, 1, 0) + self.optionsBox.addWidget(self.poValue, 1, 1) + self.optionsBox.setHorizontalSpacing(hPx) + self.optionsBox.setVerticalSpacing(vPx) + self.optionsBox.setColumnStretch(2, 1) # Assemble # ======== self.outerBox = QVBoxLayout() + self.outerBox.addWidget(QLabel("Table of Contents")) self.outerBox.addWidget(self.tocTree) self.outerBox.addLayout(self.optionsBox) @@ -367,7 +390,7 @@ class GuiProjectDetailsContents(QWidget): """ self._theToC = [] self._theToC = self.theIndex.getTableOfContents(2) - self._theToC.append(("", "H0", "END", 0)) + self._theToC.append(("", 0, "END", 0)) return ## @@ -379,39 +402,57 @@ class GuiProjectDetailsContents(QWidget): """ dblPages = self.dblValue.isChecked() wpPage = self.wpValue.value() + fstPage = self.poValue.value() - 1 - tPages = 1 pTotal = 0 + tPages = 1 theList = [] for _, tLevel, tTitle, wCount in self._theToC: pCount = math.ceil(wCount/wpPage) if dblPages: pCount += pCount%2 + pTotal += pCount theList.append((tLevel, tTitle, wCount, pCount)) + pMax = pTotal - fstPage + self.tocTree.clear() for tLevel, tTitle, wCount, pCount in theList: newItem = QTreeWidgetItem() - if tLevel == "H2": - tTitle = nwUnicode.U_ENSP+tTitle + if tPages <= fstPage: + progPage = numberToRoman(tPages, True) + progText = "" + else: + cPage = tPages - fstPage + pgProg = 100.0*(cPage - 1)/pMax if pMax > 0 else 0.0 + progPage = f"{cPage:n}" + progText = f"{pgProg:.1f}{nwUnicode.U_THSP}%" - pgProg = 100.0*(tPages - 1)/pTotal if pTotal > 0 else 0.0 - - newItem.setIcon(self.C_TITLE, self.theTheme.getIcon("doc_%s" % tLevel.lower())) + newItem.setIcon(self.C_TITLE, self.theTheme.getIcon("doc_h%d" % tLevel)) newItem.setText(self.C_TITLE, tTitle) newItem.setText(self.C_WORDS, f"{wCount:n}") newItem.setText(self.C_PAGES, f"{pCount:n}") - newItem.setText(self.C_PAGE, f"{tPages:n}") - newItem.setText(self.C_PROG, f"{pgProg:.1f}{nwUnicode.U_THSP}%") + newItem.setText(self.C_PAGE, progPage) + newItem.setText(self.C_PROG, progText) newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight) newItem.setTextAlignment(self.C_PAGES, Qt.AlignRight) newItem.setTextAlignment(self.C_PAGE, Qt.AlignRight) newItem.setTextAlignment(self.C_PROG, Qt.AlignRight) + # Make pages and titles/partitions stand out + if tLevel < 2: + bFont = newItem.font(self.C_TITLE) + if tLevel == 0: + bFont.setItalic(True) + else: + bFont.setBold(True) + bFont.setUnderline(True) + newItem.setFont(self.C_TITLE, bFont) + tPages += pCount self.tocTree.addTopLevelItem(newItem) diff --git a/nw/guimain.py b/nw/guimain.py index e48987bc..64e0a2e0 100644 --- a/nw/guimain.py +++ b/nw/guimain.py @@ -965,6 +965,8 @@ class GuiMain(QMainWindow): logger.error("No project open") return + self.treeView.flushTreeOrder() + dlgDetails = GuiProjectDetails(self, self.theProject) dlgDetails.setModal(False) dlgDetails.show() diff --git a/tests/test_core/test_core_index.py b/tests/test_core/test_core_index.py index 46396574..e10000d6 100644 --- a/tests/test_core/test_core_index.py +++ b/tests/test_core/test_core_index.py @@ -659,18 +659,18 @@ def testCoreIndex_ExtractData(nwMinimal, dummyGUI): assert theIndex.getTableOfContents(0, True) == [] assert theIndex.getTableOfContents(1, True) == [] assert theIndex.getTableOfContents(2, True) == [ - ("%s:T000001" % hHandle, "H2", "Chapter One", 6), + ("%s:T000001" % hHandle, 2, "Chapter One", 6), ] assert theIndex.getTableOfContents(3, True) == [ - ("%s:T000001" % hHandle, "H2", "Chapter One", 2), - ("%s:T000001" % sHandle, "H3", "Scene One", 2), - ("%s:T000001" % tHandle, "H3", "Scene Two", 2), + ("%s:T000001" % hHandle, 2, "Chapter One", 2), + ("%s:T000001" % sHandle, 3, "Scene One", 2), + ("%s:T000001" % tHandle, 3, "Scene Two", 2), ] assert theIndex.getTableOfContents(0, False) == [] assert theIndex.getTableOfContents(1, False) == [ - ("%s:T000001" % nHandle, "H1", "Hello World!", 12), - ("%s:T000011" % nHandle, "H1", "Hello World!", 18), + ("%s:T000001" % nHandle, 1, "Hello World!", 12), + ("%s:T000011" % nHandle, 1, "Hello World!", 18), ] assert theProject.closeProject() diff --git a/tests/test_gui/test_gui_projdetails.py b/tests/test_gui/test_gui_projdetails.py index 179b6d04..4919bb8d 100644 --- a/tests/test_gui/test_gui_projdetails.py +++ b/tests/test_gui/test_gui_projdetails.py @@ -27,7 +27,6 @@ from tools import getGuiItem from PyQt5.QtWidgets import QAction, QMessageBox from nw.gui import GuiProjectDetails -from nw.constants import nwUnicode keyDelay = 2 typeDelay = 1 @@ -78,31 +77,33 @@ def testGuiProjDetails_Dialog(qtbot, monkeypatch, nwGUI, nwLipsum): tocTree = tocTab.tocTree assert tocTree.topLevelItemCount() == 7 assert tocTree.topLevelItem(0).text(tocTab.C_TITLE) == "Lorem Ipsum" - assert tocTree.topLevelItem(2).text(tocTab.C_TITLE) == nwUnicode.U_ENSP+"Prologue" + assert tocTree.topLevelItem(2).text(tocTab.C_TITLE) == "Prologue" assert tocTree.topLevelItem(3).text(tocTab.C_TITLE) == "Act One" - assert tocTree.topLevelItem(4).text(tocTab.C_TITLE) == nwUnicode.U_ENSP+"Chapter One" - assert tocTree.topLevelItem(5).text(tocTab.C_TITLE) == nwUnicode.U_ENSP+"Chapter Two" + assert tocTree.topLevelItem(4).text(tocTab.C_TITLE) == "Chapter One" + assert tocTree.topLevelItem(5).text(tocTab.C_TITLE) == "Chapter Two" assert tocTree.topLevelItem(6).text(tocTab.C_TITLE) == "END" # Count Pages tocTab.wpValue.setValue(100) + tocTab.poValue.setValue(4) tocTab.dblValue.setChecked(False) tocTab._populateTree() - thePages = [1, 2, 1, 1, 11, 17, 0] - thePage = [1, 2, 4, 5, 6, 17, 34] + thePages = ["1", "2", "1", "1", "11", "17", "0"] + thePage = ["i", "ii", "1", "2", "3", "14", "31"] for i in range(7): - assert tocTree.topLevelItem(i).text(tocTab.C_PAGES) == f"{thePages[i]:n}" - assert tocTree.topLevelItem(i).text(tocTab.C_PAGE) == f"{thePage[i]:n}" + assert tocTree.topLevelItem(i).text(tocTab.C_PAGES) == thePages[i] + assert tocTree.topLevelItem(i).text(tocTab.C_PAGE) == thePage[i] + tocTab.poValue.setValue(5) tocTab.dblValue.setChecked(True) tocTab._populateTree() - thePages = [2, 2, 2, 2, 12, 18, 0] - thePage = [1, 3, 5, 7, 9, 21, 39] + thePages = ["2", "2", "2", "2", "12", "18", "0"] + thePage = ["i", "iii", "1", "3", "5", "17", "35"] for i in range(7): - assert tocTree.topLevelItem(i).text(tocTab.C_PAGES) == f"{thePages[i]:n}" - assert tocTree.topLevelItem(i).text(tocTab.C_PAGE) == f"{thePage[i]:n}" + assert tocTree.topLevelItem(i).text(tocTab.C_PAGES) == thePages[i] + assert tocTree.topLevelItem(i).text(tocTab.C_PAGE) == thePage[i] # qtbot.stopForInteraction()