diff --git a/novelwriter/core/index.py b/novelwriter/core/index.py index 76a7ec55..ee9ea089 100644 --- a/novelwriter/core/index.py +++ b/novelwriter/core/index.py @@ -73,9 +73,8 @@ class NWIndex: self._indexBroken = False # TimeStamps - self._timeNovel = 0 - self._timeNotes = 0 - self._timeIndex = 0 + self._indexChange = 0 + self._rootChange = {} return @@ -99,9 +98,8 @@ class NWIndex: """ self._tagsIndex.clear() self._itemIndex.clear() - self._timeNovel = 0 - self._timeNotes = 0 - self._timeIndex = 0 + self._indexChange = 0 + self._rootChange = {} return def deleteHandle(self, tHandle): @@ -129,20 +127,16 @@ class NWIndex: return True - def novelChangedSince(self, checkTime): - """Check if the novel index has changed since a given time. - """ - return self._timeNovel > checkTime - - def notesChangedSince(self, checkTime): - """Check if the notes index has changed since a given time. - """ - return self._timeNotes > checkTime - def indexChangedSince(self, checkTime): """Check if the index has changed since a given time. """ - return self._timeIndex > checkTime + return self._indexChange > checkTime + + def rootChangedSince(self, rootHandle, checkTime): + """Check if the index has changed since a given time for a + given root item. + """ + return self._rootChange.get(rootHandle, self._indexChange) > checkTime ## # Load and Save Index to/from File @@ -184,10 +178,7 @@ class NWIndex: logger.warning("Item '%s' is not in the index", fHandle) self.reIndexHandle(fHandle) - nowTime = round(time()) - self._timeNovel = nowTime - self._timeNotes = nowTime - self._timeIndex = nowTime + self._indexChange = round(time()) logger.verbose("Index loaded in %.3f ms", (time() - tStart)*1000) @@ -307,11 +298,8 @@ class NWIndex: # Update timestamps for index changes nowTime = round(time()) - self._timeIndex = nowTime - if theItem.itemLayout == nwItemLayout.NOTE: - self._timeNotes = nowTime - else: - self._timeNovel = nowTime + self._indexChange = nowTime + self._rootChange[theItem.itemRoot] = nowTime return True @@ -466,14 +454,14 @@ class NWIndex: # Extract Data ## - def novelStructure(self, skipExcl=True): + def novelStructure(self, rootHandle=None, skipExcl=True): """Iterate over all titles in the novel, in the correct order as they appear in the tree view and in the respective document files, but skipping all note files. """ - for tHandle, sTitle, hItem in self._itemIndex.iterNovelStructure(skipExcl=skipExcl): - tKey = f"{tHandle}:{sTitle}" - yield tKey, tHandle, sTitle, hItem + novStruct = self._itemIndex.iterNovelStructure(rootHandle=rootHandle, skipExcl=skipExcl) + for tHandle, sTitle, hItem in novStruct: + yield f"{tHandle}:{sTitle}", tHandle, sTitle, hItem return def getNovelWordCount(self, skipExcl=True): diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py index a1cd11d3..e5ad816e 100644 --- a/novelwriter/gui/noveltree.py +++ b/novelwriter/gui/noveltree.py @@ -136,7 +136,7 @@ class GuiNovelTree(QTreeWidget): """ logger.verbose("Requesting refresh of the novel tree") treeChanged = self.theParent.treeView.changedSince(self._lastBuild) - indexChanged = self.theProject.index.novelChangedSince(self._lastBuild) + indexChanged = self.theProject.index.indexChangedSince(self._lastBuild) if not (treeChanged or indexChanged or overRide): logger.verbose("No changes have been made to the novel index") return diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py index 58710584..ea919615 100644 --- a/novelwriter/gui/outline.py +++ b/novelwriter/gui/outline.py @@ -83,6 +83,7 @@ class GuiOutline(QWidget): self.outlineView.hiddenStateChanged.connect(self._updateMenuColumns) self.outlineView.activeItemChanged.connect(self.outlineData.showItem) self.outlineData.itemTagClicked.connect(self._tagClicked) + self.outlineBar.novelRootChanged.connect(self._rootItemChanged) self.outlineBar.viewColumnToggled.connect(self.outlineView.menuColumnToggled) self.outlineBar.viewRefreshRequested.connect( lambda: self.outlineView.refreshTree(overRide=True) @@ -153,6 +154,13 @@ class GuiOutline(QWidget): self.loadDocumentTagRequest.emit(link, nwDocMode.VIEW) return + @pyqtSlot(str) + def _rootItemChanged(self, handle): + """The root novel handle has been changed. + """ + self.outlineView.refreshTree(rootHandle=handle, overRide=True) + return + # END Class GuiOutline @@ -394,7 +402,7 @@ class GuiOutlineView(QTreeWidget): return - def refreshTree(self, overRide=False, novelChanged=False): + def refreshTree(self, rootHandle=None, overRide=False, novelChanged=False): """Called whenever the Outline tab is activated and controls what data to load, and if necessary, force a rebuild of the tree. @@ -402,17 +410,17 @@ class GuiOutlineView(QTreeWidget): # If it's the first time, we always build if self._firstView or self._firstView and overRide: self._loadHeaderState() - self._populateTree() + self._populateTree(rootHandle) self._firstView = False return # If the novel index or novel tree has changed since the tree # was last built, we rebuild the tree from the updated index. - indexChanged = self.theProject.index.novelChangedSince(self._lastBuild) + indexChanged = self.theProject.index.rootChangedSince(rootHandle, self._lastBuild) doBuild = (novelChanged or indexChanged) and self.theProject.autoOutline if doBuild or overRide: logger.debug("Rebuilding Project Outline") - self._populateTree() + self._populateTree(rootHandle) return @@ -577,7 +585,7 @@ class GuiOutlineView(QTreeWidget): return - def _populateTree(self): + def _populateTree(self, rootHandle): """Build the tree based on the project index, and the header based on the defined constants, default values and user selected width, order and hidden state. All columns are populated, even @@ -610,7 +618,8 @@ class GuiOutlineView(QTreeWidget): currChapter = None currScene = None - for _, tHandle, sTitle, novIdx in self.theProject.index.novelStructure(skipExcl=True): + novStruct = self.theProject.index.novelStructure(rootHandle=rootHandle, skipExcl=True) + for _, tHandle, sTitle, novIdx in novStruct: tItem = self._createTreeItem(tHandle, sTitle, novIdx) diff --git a/sample/content/a520879ca0b45.nwd b/sample/content/a520879ca0b45.nwd new file mode 100644 index 00000000..12d7a62a --- /dev/null +++ b/sample/content/a520879ca0b45.nwd @@ -0,0 +1,17 @@ +%%~name: Chapter One +%%~path: e5e47ebf63b1c/a520879ca0b45 +%%~kind: NOVEL/DOCUMENT +### Chapter One + +@pov: Jane + +% Synopsis: Remember Jane and John? + +### Scene One + +@pov: Jane +@focus: John + +A project can have multiple novel root folders for multiple novels. This is the first scene of a sequel to the first novel. + +In this way, the writer can keep the same notes for multiple novels. This can be especially useful if the writer is planning a multi-novel story in advance. diff --git a/sample/content/bacb7059e3083.nwd b/sample/content/bacb7059e3083.nwd new file mode 100644 index 00000000..b6be7a07 --- /dev/null +++ b/sample/content/bacb7059e3083.nwd @@ -0,0 +1,8 @@ +%%~name: Title Page +%%~path: e5e47ebf63b1c/bacb7059e3083 +%%~kind: NOVEL/DOCUMENT +#! Sequel Novel + +>> **By Jane Doh** << + +% Synopsis: Jane and John are back in a sequel to My Novel! diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx index cdd3ae50..9f3a6587 100644 --- a/sample/nwProject.nwx +++ b/sample/nwProject.nwx @@ -1,13 +1,13 @@ - + Sample Project Sample Project Jane Smith Jay Doh - 1331 - 220 - 67108 + 1334 + 225 + 67746 False @@ -15,10 +15,10 @@ True None True - 636b6aa9b697b + a520879ca0b45 636b6aa9b697b - 1303 - 894 + 1363 + 954 409 B @@ -33,10 +33,10 @@
- New + New Notes Started - 1st Draft + 1st Draft 2nd Draft 3rd Draft Finished @@ -48,13 +48,13 @@ Main
- + Novel - + Title Page @@ -93,7 +93,19 @@ We Found John! - + + + Sequel + + + + Title Page + + + + Chapter One + + Characters @@ -109,7 +121,7 @@ Jane Smith - + Locations @@ -125,7 +137,7 @@ Mars - + Archive @@ -137,7 +149,7 @@ Old File - + Trash diff --git a/tests/test_core/test_core_index.py b/tests/test_core/test_core_index.py index 78361bb6..8f126e56 100644 --- a/tests/test_core/test_core_index.py +++ b/tests/test_core/test_core_index.py @@ -197,8 +197,7 @@ def testCoreIndex_CheckThese(mockGUI, fncDir, mockRnd): nItem = theProject.tree[nHandle] cItem = theProject.tree[cHandle] - assert theIndex.novelChangedSince(0) is False - assert theIndex.notesChangedSince(0) is False + assert theIndex.rootChangedSince("0000000000010", 0) is False assert theIndex.indexChangedSince(0) is False assert theIndex.scanText(cHandle, ( @@ -228,8 +227,7 @@ def testCoreIndex_CheckThese(mockGUI, fncDir, mockRnd): "@time": [] } - assert theIndex.novelChangedSince(0) is True - assert theIndex.notesChangedSince(0) is True + assert theIndex.rootChangedSince("0000000000010", 0) is True assert theIndex.indexChangedSince(0) is True assert theIndex.getHandleHeaderLevel(cHandle) == "H1"