Rewrite index class to use sequential title keys rather than line numbers

This commit is contained in:
Veronica Berglyd Olsen
2022-11-14 16:59:51 +01:00
parent e52d8d9ff7
commit b0a0ca089f
7 changed files with 133 additions and 96 deletions
+2 -2
View File
@@ -154,11 +154,11 @@ def isHandle(value):
def isTitleTag(value): def isTitleTag(value):
"""Check if a string is a valid title string. """Check if a string is a valid title tag string.
""" """
if not isinstance(value, str): if not isinstance(value, str):
return False return False
if len(value) != 7: if len(value) != 5:
return False return False
if not value.startswith("T"): if not value.startswith("T"):
return False return False
-1
View File
@@ -61,7 +61,6 @@ class nwHeaders:
H_VALID = ("H0", "H1", "H2", "H3", "H4") H_VALID = ("H0", "H1", "H2", "H3", "H4")
H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4} H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
TT_NONE = "T000000"
# END Class nwHeaders # END Class nwHeaders
+82 -53
View File
@@ -41,6 +41,8 @@ from novelwriter.common import (
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
TT_NONE = "T0000"
class NWIndex: class NWIndex:
"""This class holds the entire index for a given project. The index """This class holds the entire index for a given project. The index
@@ -281,50 +283,58 @@ class NWIndex:
def _scanActive(self, tHandle, theItem, theText, itemTags): def _scanActive(self, tHandle, theItem, theText, itemTags):
"""Scan an active document for meta data. """Scan an active document for meta data.
""" """
nTitle = 0 nTitle = 0 # Line Number of the previous title
findHeader = True cTitle = TT_NONE # Tag of the current title
theLines = theText.splitlines() pTitle = TT_NONE # Tag of the previous title
firstHeader = True # First header has been seen
theLines = theText.splitlines()
for nLine, aLine in enumerate(theLines, start=1): for nLine, aLine in enumerate(theLines, start=1):
if len(aLine.strip()) == 0: if aLine.strip() == "":
continue continue
if aLine.startswith("#"): if aLine.startswith("#"):
if findHeader: hDepth, hText = self._splitHeading(aLine)
hDepth, _ = self._splitHeading(aLine) if hDepth == "H0":
if hDepth != "H0": continue
theItem.setMainHeading(hDepth)
findHeader = False
isTitle = self._indexTitle(tHandle, aLine, nLine) if firstHeader:
if isTitle and nLine > 0: theItem.setMainHeading(hDepth)
firstHeader = False
cTitle = self._itemIndex.addItemHeading(tHandle, nLine, hDepth, hText)
if cTitle != TT_NONE:
if nTitle > 0: if nTitle > 0:
# We have a new title, so we need to count the words of the previous one
lastText = "\n".join(theLines[nTitle-1:nLine-1]) lastText = "\n".join(theLines[nTitle-1:nLine-1])
self._indexWordCounts(tHandle, lastText, nTitle) self._indexWordCounts(tHandle, lastText, pTitle)
nTitle = nLine nTitle = nLine
pTitle = cTitle
elif aLine.startswith("@"): elif aLine.startswith("@"):
self._indexKeyword(tHandle, aLine, nTitle, theItem.itemClass, itemTags) if cTitle != TT_NONE:
self._indexKeyword(tHandle, aLine, cTitle, theItem.itemClass, itemTags)
elif aLine.startswith("%"): elif aLine.startswith("%"):
if nTitle > 0: if cTitle != TT_NONE:
toCheck = aLine[1:].lstrip() toCheck = aLine[1:].lstrip()
synTag = toCheck[:9].lower() synTag = toCheck[:9].lower()
tLen = len(aLine) tLen = len(aLine)
cLen = len(toCheck) cLen = len(toCheck)
cOff = tLen - cLen cOff = tLen - cLen
if synTag == "synopsis:": if synTag == "synopsis:":
self._indexSynopsis(tHandle, aLine[cOff+9:].strip(), nTitle) sText = aLine[cOff+9:].strip()
self._itemIndex.setHeadingSynopsis(tHandle, cTitle, sText)
# Count words for remaining text after last heading # Count words for remaining text after last heading
if nTitle > 0: if pTitle != TT_NONE:
lastText = "\n".join(theLines[nTitle-1:]) lastText = "\n".join(theLines[nTitle-1:])
self._indexWordCounts(tHandle, lastText, nTitle) self._indexWordCounts(tHandle, lastText, pTitle)
# Also count words on a page with no titles # Also count words on a page with no titles
if nTitle == 0: if cTitle == TT_NONE:
self._indexWordCounts(tHandle, theText, nTitle) self._indexWordCounts(tHandle, theText, cTitle)
# Prune no longer used tags # Prune no longer used tags
for tTag, isActive in itemTags.items(): for tTag, isActive in itemTags.items():
@@ -362,34 +372,14 @@ class NWIndex:
return "H2", aLine[4:].strip() return "H2", aLine[4:].strip()
return "H0", "" return "H0", ""
def _indexTitle(self, tHandle, aLine, nTitle): def _indexWordCounts(self, tHandle, theText, sTitle):
"""Save information about the title and its location in the
file to the index.
"""
hDepth, hText = self._splitHeading(aLine)
if hDepth == "H0":
return False
sTitle = f"T{nTitle:06d}"
self._itemIndex.addItemHeading(tHandle, sTitle, hDepth, hText)
return True
def _indexWordCounts(self, tHandle, theText, nTitle):
"""Count text stats and save the counts to the index. """Count text stats and save the counts to the index.
""" """
sTitle = f"T{nTitle:06d}"
cC, wC, pC = countWords(theText) cC, wC, pC = countWords(theText)
self._itemIndex.setHeadingCounts(tHandle, sTitle, cC, wC, pC) self._itemIndex.setHeadingCounts(tHandle, sTitle, cC, wC, pC)
return return
def _indexSynopsis(self, tHandle, theText, nTitle): def _indexKeyword(self, tHandle, aLine, sTitle, itemClass, itemTags):
"""Save the synopsis to the index.
"""
sTitle = f"T{nTitle:06d}"
self._itemIndex.setHeadingSynopsis(tHandle, sTitle, theText)
return
def _indexKeyword(self, tHandle, aLine, nTitle, itemClass, itemTags):
"""Validate and save the information about a reference to a tag """Validate and save the information about a reference to a tag
in another file, or the setting of a tag in the file. A record in another file, or the setting of a tag in the file. A record
of active tags is updated so that no longer used tags can be of active tags is updated so that no longer used tags can be
@@ -404,7 +394,6 @@ class NWIndex:
logger.warning("Skipping invalid keyword '%s' in '%s'", theBits[0], tHandle) logger.warning("Skipping invalid keyword '%s' in '%s'", theBits[0], tHandle)
return return
sTitle = f"T{nTitle:06d}"
if theBits[0] == nwKeyWords.TAG_KEY: if theBits[0] == nwKeyWords.TAG_KEY:
tagName = theBits[1] tagName = theBits[1]
self._tagsIndex.add(tagName, tHandle, sTitle, itemClass) self._tagsIndex.add(tagName, tHandle, sTitle, itemClass)
@@ -506,6 +495,14 @@ class NWIndex:
""" """
return self._itemIndex[tHandle] return self._itemIndex[tHandle]
def getItemHeader(self, tHandle, sTitle):
"""Get the header entry for a specific item and heading.
"""
tItem = self._itemIndex[tHandle]
if isinstance(tItem, IndexItem):
return tItem[sTitle]
return None
def getNovelWordCount(self, skipExcl=True): def getNovelWordCount(self, skipExcl=True):
"""Count the number of words in the novel project. """Count the number of words in the novel project.
""" """
@@ -649,6 +646,8 @@ class TagsIndex:
control of the keys. control of the keys.
""" """
__slots__ = ("_tags")
def __init__(self): def __init__(self):
self._tags = {} self._tags = {}
return return
@@ -695,7 +694,7 @@ class TagsIndex:
def tagHeading(self, tagKey): def tagHeading(self, tagKey):
"""Get the heading of a given tag. """Get the heading of a given tag.
""" """
return self._tags.get(tagKey, {}).get("heading", nwHeaders.TT_NONE) return self._tags.get(tagKey, {}).get("heading", TT_NONE)
def tagClass(self, tagKey): def tagClass(self, tagKey):
"""Get the class of a given tag. """Get the class of a given tag.
@@ -754,6 +753,8 @@ class ItemIndex:
IndexHeading object for each header of the text. IndexHeading object for each header of the text.
""" """
__slots__ = ("_project", "_items")
def __init__(self, project): def __init__(self, project):
self._project = project self._project = project
self._items = {} self._items = {}
@@ -844,13 +845,15 @@ class ItemIndex:
# Setters # Setters
## ##
def addItemHeading(self, tHandle, sTitle, hDepth, hText): def addItemHeading(self, tHandle, lineNo, hDepth, hText):
"""Set the main heading level of an item. """Add a heading to an item.
""" """
if tHandle in self._items: if tHandle in self._items:
tItem = self._items[tHandle] tItem = self._items[tHandle]
tItem.addHeading(IndexHeading(sTitle, hDepth, hText)) sTitle = tItem.nextHeading()
return tItem.addHeading(IndexHeading(sTitle, lineNo, hDepth, hText))
return sTitle
return TT_NONE
def setHeadingCounts(self, tHandle, sTitle, cC, wC, pC): def setHeadingCounts(self, tHandle, sTitle, cC, wC, pC):
"""Set the character, word and paragraph counts of a heading """Set the character, word and paragraph counts of a heading
@@ -921,14 +924,16 @@ class IndexItem:
must be reset each time the item is re-indexed. must be reset each time the item is re-indexed.
""" """
__slots__ = ("_handle", "_item", "_headings", "_headings", "_count")
def __init__(self, tHandle, tItem): def __init__(self, tHandle, tItem):
self._handle = tHandle self._handle = tHandle
self._item = tItem self._item = tItem
self._headings = {} self._headings = {}
self._index = 0 self._count = 0
# Add a placeholder heading # Add a placeholder heading
self._headings[nwHeaders.TT_NONE] = IndexHeading(nwHeaders.TT_NONE) self._headings[TT_NONE] = IndexHeading(TT_NONE)
return return
@@ -951,8 +956,8 @@ class IndexItem:
"""Add a heading to the item. Also remove the placeholder entry """Add a heading to the item. Also remove the placeholder entry
if it exists. if it exists.
""" """
if nwHeaders.TT_NONE in self._headings: if TT_NONE in self._headings:
self._headings.pop(nwHeaders.TT_NONE) self._headings.pop(TT_NONE)
self._headings[tHeading.key] = tHeading self._headings[tHeading.key] = tHeading
return return
@@ -1011,6 +1016,12 @@ class IndexItem:
tags.append(tag) tags.append(tag)
return tags return tags
def nextHeading(self):
"""Return the next heading key to be used.
"""
self._count += 1
return f"T{self._count:04d}"
## ##
# Pack/Unpack # Pack/Unpack
## ##
@@ -1056,8 +1067,14 @@ class IndexHeading:
of all references made under each heading. of all references made under each heading.
""" """
def __init__(self, key, level="H0", title=""): __slots__ = (
"_key", "_line", "_level", "_title", "_charCount", "_wordCount",
"_paraCount", "_synopsis", "_tag", "_refs",
)
def __init__(self, key, line=0, level="H0", title=""):
self._key = key self._key = key
self._line = line
self._level = level self._level = level
self._title = title self._title = title
@@ -1082,6 +1099,10 @@ class IndexHeading:
def key(self): def key(self):
return self._key return self._key
@property
def line(self):
return self._line
@property @property
def level(self): def level(self):
return self._level return self._level
@@ -1125,6 +1146,12 @@ class IndexHeading:
self._level = level self._level = level
return return
def setLine(self, line):
"""Set the line number of a heading.
"""
self._line = max(0, checkInt(line, 0))
return
def setCounts(self, charCount, wordCount, paraCount): def setCounts(self, charCount, wordCount, paraCount):
"""Set the character, word and paragraph count. Make sure the """Set the character, word and paragraph count. Make sure the
value is an integer and is not smaller than 0. value is an integer and is not smaller than 0.
@@ -1166,6 +1193,7 @@ class IndexHeading:
return { return {
"level": self._level, "level": self._level,
"title": self._title, "title": self._title,
"line": self._line,
"tag": self._tag, "tag": self._tag,
"cCount": self._charCount, "cCount": self._charCount,
"wCount": self._wordCount, "wCount": self._wordCount,
@@ -1187,6 +1215,7 @@ class IndexHeading:
self.setLevel(data.get("level", "H0")) self.setLevel(data.get("level", "H0"))
self._title = str(data.get("title", "")) self._title = str(data.get("title", ""))
self._tag = str(data.get("tag", "")) self._tag = str(data.get("tag", ""))
self.setLine(data.get("line", 0))
self.setCounts( self.setCounts(
data.get("cCount", 0), data.get("cCount", 0),
data.get("wCount", 0), data.get("wCount", 0),
+7 -11
View File
@@ -40,7 +40,6 @@ from PyQt5.QtWidgets import (
) )
from novelwriter.enum import nwDocMode, nwItemClass, nwOutline from novelwriter.enum import nwDocMode, nwItemClass, nwOutline
from novelwriter.common import checkInt
from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -60,7 +59,7 @@ class GuiNovelView(QWidget):
# Signals for user interaction with the novel tree # Signals for user interaction with the novel tree
selectedItemChanged = pyqtSignal(str) selectedItemChanged = pyqtSignal(str)
openDocumentRequest = pyqtSignal(str, Enum, int, str) openDocumentRequest = pyqtSignal(str, Enum, str)
def __init__(self, mainGui): def __init__(self, mainGui):
super().__init__(parent=mainGui) super().__init__(parent=mainGui)
@@ -543,14 +542,11 @@ class GuiNovelTree(QTreeWidget):
selected, return the first. selected, return the first.
""" """
selItem = self.selectedItems() selItem = self.selectedItems()
tHandle = None
tLine = 0
if selItem: if selItem:
tHandle = selItem[0].data(self.C_TITLE, self.D_HANDLE) tHandle = selItem[0].data(self.C_TITLE, self.D_HANDLE)
sTitle = selItem[0].data(self.C_TITLE, self.D_TITLE) sTitle = selItem[0].data(self.C_TITLE, self.D_TITLE)
tLine = checkInt(sTitle[1:], 1) - 1 return tHandle, sTitle
return None, None
return tHandle, tLine
def setLastColType(self, colType, doRefresh=True): def setLastColType(self, colType, doRefresh=True):
"""Change the content type of the last column and rebuild. """Change the content type of the last column and rebuild.
@@ -609,11 +605,11 @@ class GuiNovelTree(QTreeWidget):
if not isinstance(selItem, QTreeWidgetItem): if not isinstance(selItem, QTreeWidgetItem):
return return
tHandle, _ = self.getSelectedHandle() tHandle, sTitle = self.getSelectedHandle()
if tHandle is None: if tHandle is None:
return return
self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, -1, "") self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, sTitle or "")
return return
@@ -655,8 +651,8 @@ class GuiNovelTree(QTreeWidget):
clicked, and send it to the main gui class for opening in the clicked, and send it to the main gui class for opening in the
document editor. document editor.
""" """
tHandle, tLine = self.getSelectedHandle() tHandle, sTitle = self.getSelectedHandle()
self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, tLine, "") self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, sTitle or "")
return return
## ##
+17 -16
View File
@@ -55,6 +55,7 @@ logger = logging.getLogger(__name__)
class GuiOutlineView(QWidget): class GuiOutlineView(QWidget):
loadDocumentTagRequest = pyqtSignal(str, Enum) loadDocumentTagRequest = pyqtSignal(str, Enum)
openDocumentRequest = pyqtSignal(str, Enum, str)
def __init__(self, mainGui): def __init__(self, mainGui):
super().__init__(parent=mainGui) super().__init__(parent=mainGui)
@@ -375,15 +376,16 @@ class GuiOutlineTree(QTreeWidget):
hiddenStateChanged = pyqtSignal() hiddenStateChanged = pyqtSignal()
activeItemChanged = pyqtSignal(str, str) activeItemChanged = pyqtSignal(str, str)
def __init__(self, theOutline): def __init__(self, outlineView):
super().__init__(parent=theOutline) super().__init__(parent=outlineView)
logger.debug("Initialising GuiOutlineTree ...") logger.debug("Initialising GuiOutlineTree ...")
self.mainConf = novelwriter.CONFIG self.mainConf = novelwriter.CONFIG
self.mainGui = theOutline.mainGui self.outlineView = outlineView
self.theProject = theOutline.mainGui.theProject self.mainGui = outlineView.mainGui
self.mainTheme = theOutline.mainGui.mainTheme self.theProject = outlineView.mainGui.theProject
self.mainTheme = outlineView.mainGui.mainTheme
self.setUniformRowHeights(True) self.setUniformRowHeights(True)
self.setFrameStyle(QFrame.NoFrame) self.setFrameStyle(QFrame.NoFrame)
@@ -524,13 +526,11 @@ class GuiOutlineTree(QTreeWidget):
selected, return the first. selected, return the first.
""" """
selItem = self.selectedItems() selItem = self.selectedItems()
tHandle = None
tLine = 0
if selItem: if selItem:
tHandle = selItem[0].data(self._colIdx[nwOutline.TITLE], self.D_HANDLE) tHandle = selItem[0].data(self._colIdx[nwOutline.TITLE], self.D_HANDLE)
tLine = checkInt(selItem[0].text(self._colIdx[nwOutline.LINE]), 1) - 1 sTitle = selItem[0].data(self._colIdx[nwOutline.TITLE], self.D_TITLE)
return tHandle, sTitle
return tHandle, tLine return None, None
## ##
# Slots # Slots
@@ -542,8 +542,10 @@ class GuiOutlineTree(QTreeWidget):
clicked, and send it to the main gui class for opening in the clicked, and send it to the main gui class for opening in the
document editor. document editor.
""" """
tHandle, tLine = self.getSelectedHandle() tHandle, sTitle = self.getSelectedHandle()
self.mainGui.openDocument(tHandle, tLine=tLine - 1, doScroll=True) if tHandle is None:
return
self.outlineView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, sTitle or "")
return return
@pyqtSlot() @pyqtSlot()
@@ -554,9 +556,8 @@ class GuiOutlineTree(QTreeWidget):
selItems = self.selectedItems() selItems = self.selectedItems()
if selItems: if selItems:
tHandle = selItems[0].data(self._colIdx[nwOutline.TITLE], self.D_HANDLE) tHandle = selItems[0].data(self._colIdx[nwOutline.TITLE], self.D_HANDLE)
sTitle = selItems[0].data(self._colIdx[nwOutline.TITLE], self.D_TITLE) sTitle = selItems[0].data(self._colIdx[nwOutline.TITLE], self.D_TITLE)
self.activeItemChanged.emit(tHandle, sTitle) self.activeItemChanged.emit(tHandle, sTitle)
return return
@pyqtSlot(int, int, int) @pyqtSlot(int, int, int)
@@ -718,7 +719,7 @@ class GuiOutlineTree(QTreeWidget):
trItem.setText(self._colIdx[nwOutline.LEVEL], novIdx.level) trItem.setText(self._colIdx[nwOutline.LEVEL], novIdx.level)
trItem.setIcon(self._colIdx[nwOutline.LABEL], self._dIcon[nwItem.mainHeading]) trItem.setIcon(self._colIdx[nwOutline.LABEL], self._dIcon[nwItem.mainHeading])
trItem.setText(self._colIdx[nwOutline.LABEL], nwItem.itemName) trItem.setText(self._colIdx[nwOutline.LABEL], nwItem.itemName)
trItem.setText(self._colIdx[nwOutline.LINE], sTitle[1:].lstrip("0")) trItem.setText(self._colIdx[nwOutline.LINE], f"{novIdx.line:n}")
trItem.setText(self._colIdx[nwOutline.SYNOP], novIdx.synopsis) trItem.setText(self._colIdx[nwOutline.SYNOP], novIdx.synopsis)
trItem.setText(self._colIdx[nwOutline.CCOUNT], f"{novIdx.charCount:n}") trItem.setText(self._colIdx[nwOutline.CCOUNT], f"{novIdx.charCount:n}")
trItem.setText(self._colIdx[nwOutline.WCOUNT], f"{novIdx.wordCount:n}") trItem.setText(self._colIdx[nwOutline.WCOUNT], f"{novIdx.wordCount:n}")
+5 -5
View File
@@ -60,7 +60,7 @@ class GuiProjectView(QWidget):
# Signals for user interaction with the project tree # Signals for user interaction with the project tree
selectedItemChanged = pyqtSignal(str) selectedItemChanged = pyqtSignal(str)
openDocumentRequest = pyqtSignal(str, Enum, int, str) openDocumentRequest = pyqtSignal(str, Enum, str)
# Requests for the main GUI # Requests for the main GUI
projectSettingsRequest = pyqtSignal(int) projectSettingsRequest = pyqtSignal(int)
@@ -1144,7 +1144,7 @@ class GuiProjectTree(QTreeWidget):
return return
if tItem.isFileType(): if tItem.isFileType():
self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, -1, "") self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, "")
else: else:
trItem.setExpanded(not trItem.isExpanded()) trItem.setExpanded(not trItem.isExpanded())
@@ -1190,11 +1190,11 @@ class GuiProjectTree(QTreeWidget):
if isFile: if isFile:
aOpenDoc = ctxMenu.addAction(self.tr("Open Document")) aOpenDoc = ctxMenu.addAction(self.tr("Open Document"))
aOpenDoc.triggered.connect( aOpenDoc.triggered.connect(
lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, -1, "") lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, "")
) )
aViewDoc = ctxMenu.addAction(self.tr("View Document")) aViewDoc = ctxMenu.addAction(self.tr("View Document"))
aViewDoc.triggered.connect( aViewDoc.triggered.connect(
lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, -1, "") lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, "")
) )
ctxMenu.addSeparator() ctxMenu.addSeparator()
@@ -1324,7 +1324,7 @@ class GuiProjectTree(QTreeWidget):
return return
if tItem.isFileType(): if tItem.isFileType():
self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, -1, "") self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, "")
return return
+20 -8
View File
@@ -230,6 +230,7 @@ class GuiMain(QMainWindow):
self.docViewer.loadDocumentTagRequest.connect(self._followTag) self.docViewer.loadDocumentTagRequest.connect(self._followTag)
self.outlineView.loadDocumentTagRequest.connect(self._followTag) self.outlineView.loadDocumentTagRequest.connect(self._followTag)
self.outlineView.openDocumentRequest.connect(self._openDocument)
# Finalise Initialisation # Finalise Initialisation
# ======================= # =======================
@@ -650,7 +651,7 @@ class GuiMain(QMainWindow):
return True return True
def viewDocument(self, tHandle=None, tAnchor=None): def viewDocument(self, tHandle=None, sTitle=None):
"""Load a document for viewing in the view panel. """Load a document for viewing in the view panel.
""" """
if not self.hasProject: if not self.hasProject:
@@ -689,7 +690,8 @@ class GuiMain(QMainWindow):
self.splitDocs.setSizes(vPos) self.splitDocs.setSizes(vPos)
self.viewMeta.setVisible(self.mainConf.showRefPanel) self.viewMeta.setVisible(self.mainConf.showRefPanel)
self.docViewer.navigateTo(tAnchor) if sTitle:
self.docViewer.navigateTo(f"#{sTitle}")
return True return True
@@ -777,17 +779,23 @@ class GuiMain(QMainWindow):
return False return False
tHandle = None tHandle = None
sTitle = None
tLine = None tLine = None
if self.projView.treeHasFocus(): if self.projView.treeHasFocus():
tHandle = self.projView.getSelectedHandle() tHandle = self.projView.getSelectedHandle()
elif self.novelView.treeHasFocus(): elif self.novelView.treeHasFocus():
tHandle, tLine = self.novelView.getSelectedHandle() tHandle, sTitle = self.novelView.getSelectedHandle()
elif self.outlineView.treeHasFocus(): elif self.outlineView.treeHasFocus():
tHandle, tLine = self.outlineView.getSelectedHandle() tHandle, sTitle = self.outlineView.getSelectedHandle()
else: else:
logger.warning("No item selected") logger.warning("No item selected")
return False return False
if tHandle is not None and sTitle is not None:
hItem = self.theProject.index.getItemHeader(tHandle, sTitle)
if hItem is not None:
tLine = hItem.line
if tHandle is not None: if tHandle is not None:
self.openDocument(tHandle, tLine=tLine, changeFocus=False, doScroll=False) self.openDocument(tHandle, tLine=tLine, changeFocus=False, doScroll=False)
@@ -1473,18 +1481,22 @@ class GuiMain(QMainWindow):
if tMode == nwDocMode.EDIT: if tMode == nwDocMode.EDIT:
self.openDocument(tHandle) self.openDocument(tHandle)
elif tMode == nwDocMode.VIEW: elif tMode == nwDocMode.VIEW:
self.viewDocument(tHandle=tHandle, tAnchor=f"#{sTitle}") self.viewDocument(tHandle=tHandle, sTitle=sTitle)
return return
@pyqtSlot(str, Enum, int, str) @pyqtSlot(str, Enum, str)
def _openDocument(self, tHandle, tMode, tLine, tAnchor): def _openDocument(self, tHandle, tMode, sTitle):
"""Handle an open document request from one of the tree views. """Handle an open document request from one of the tree views.
""" """
if tHandle is not None: if tHandle is not None:
if tMode == nwDocMode.EDIT: if tMode == nwDocMode.EDIT:
tLine = None
hItem = self.theProject.index.getItemHeader(tHandle, sTitle)
if hItem is not None:
tLine = hItem.line
self.openDocument(tHandle, tLine=tLine, changeFocus=False) self.openDocument(tHandle, tLine=tLine, changeFocus=False)
elif tMode == nwDocMode.VIEW: elif tMode == nwDocMode.VIEW:
self.viewDocument(tHandle=tHandle, tAnchor=(tAnchor or None)) self.viewDocument(tHandle=tHandle, sTitle=sTitle)
return return
@pyqtSlot(nwView) @pyqtSlot(nwView)