Add the Novel Tree meta data feature (#1088)

This commit is contained in:
Veronica Berglyd Olsen
2022-06-15 20:46:45 +02:00
committed by GitHub
18 changed files with 244 additions and 94 deletions
@@ -88,3 +88,4 @@ deco_doc_h1 = nw_deco-h1.svg
deco_doc_h2 = nw_deco-h2.svg deco_doc_h2 = nw_deco-h2.svg
deco_doc_h3 = nw_deco-h3.svg deco_doc_h3 = nw_deco-h3.svg
deco_doc_h4 = nw_deco-h4.svg deco_doc_h4 = nw_deco-h4.svg
deco_doc_more = nw_deco-noveltree-more.svg
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.2"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg2161"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata2167">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs2165" />
<path
d="M 9.7,18.2 16,12 9.7,5.8 C 9.5,5.6 9.2,5.5 9,5.5 8.8,5.5 8.5,5.6 8.3,5.8 8.1,6 8,6.2 8,6.5 v 11 c 0,0.3 0.1,0.5 0.3,0.7 0.2,0.2 0.5,0.3 0.7,0.3 0.2,0 0.5,-0.1 0.7,-0.3 z"
id="path3096"
style="fill:#848484;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 928 B

@@ -88,3 +88,4 @@ deco_doc_h1 = nw_deco-h1.svg
deco_doc_h2 = nw_deco-h2.svg deco_doc_h2 = nw_deco-h2.svg
deco_doc_h3 = nw_deco-h3.svg deco_doc_h3 = nw_deco-h3.svg
deco_doc_h4 = nw_deco-h4.svg deco_doc_h4 = nw_deco-h4.svg
deco_doc_more = nw_deco-noveltree-more.svg
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.2"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg2161"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata2167">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs2165" />
<path
d="M 9.7,18.2 16,12 9.7,5.8 C 9.5,5.6 9.2,5.5 9,5.5 8.8,5.5 8.5,5.6 8.3,5.8 8.1,6 8,6.2 8,6.5 v 11 c 0,0.3 0.1,0.5 0.3,0.7 0.2,0.2 0.5,0.3 0.7,0.3 0.2,0 0.5,-0.1 0.7,-0.3 z"
id="path3096"
style="fill:#848484;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 928 B

+1 -1
View File
@@ -10,7 +10,7 @@ licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
window = 54, 54, 54 window = 54, 54, 54
windowtext = 174, 174, 174 windowtext = 174, 174, 174
base = 62, 62, 62 base = 62, 62, 62
alternatebase = 67, 67, 67 alternatebase = 78, 78, 78
text = 174, 174, 174 text = 174, 174, 174
tooltipbase = 255, 255, 192 tooltipbase = 255, 255, 192
tooltiptext = 21, 21, 13 tooltiptext = 21, 21, 13
@@ -10,7 +10,7 @@ licenseurl = https://github.com/altercation/solarized/blob/master/LICENSE
window = 0, 43, 54 window = 0, 43, 54
windowtext = 253, 246, 227 windowtext = 253, 246, 227
base = 7, 54, 66 base = 7, 54, 66
alternatebase = 67, 67, 67 alternatebase = 0, 43, 54
text = 253, 246, 227 text = 253, 246, 227
tooltipbase = 133, 153, 0 tooltipbase = 133, 153, 0
tooltiptext = 0, 43, 54 tooltiptext = 0, 43, 54
+1 -27
View File
@@ -96,8 +96,6 @@ class Config:
# Sizes # Sizes
self.winGeometry = [1200, 650] self.winGeometry = [1200, 650]
self.prefGeometry = [700, 615] self.prefGeometry = [700, 615]
self.treeColWidth = [200, 50, 30]
self.novelColWidth = [200, 50]
self.projColWidth = [200, 60, 140] self.projColWidth = [200, 60, 140]
self.mainPanePos = [300, 800] self.mainPanePos = [300, 800]
self.docPanePos = [400, 400] self.docPanePos = [400, 400]
@@ -117,7 +115,7 @@ class Config:
# Text Editor # Text Editor
self.textFont = None # Editor font self.textFont = None # Editor font
self.textSize = 12 # Editor font size self.textSize = 12 # Editor font size
self.textWidth = 600 # Editor text width self.textWidth = 700 # Editor text width
self.textMargin = 40 # Editor/viewer text margin self.textMargin = 40 # Editor/viewer text margin
self.tabWidth = 40 # Editor tabulator width self.tabWidth = 40 # Editor tabulator width
@@ -460,8 +458,6 @@ class Config:
cnfSec = "Sizes" cnfSec = "Sizes"
self.winGeometry = theConf.rdIntList(cnfSec, "geometry", self.winGeometry) self.winGeometry = theConf.rdIntList(cnfSec, "geometry", self.winGeometry)
self.prefGeometry = theConf.rdIntList(cnfSec, "preferences", self.prefGeometry) self.prefGeometry = theConf.rdIntList(cnfSec, "preferences", self.prefGeometry)
self.treeColWidth = theConf.rdIntList(cnfSec, "treecols", self.treeColWidth)
self.novelColWidth = theConf.rdIntList(cnfSec, "novelcols", self.novelColWidth)
self.projColWidth = theConf.rdIntList(cnfSec, "projcols", self.projColWidth) self.projColWidth = theConf.rdIntList(cnfSec, "projcols", self.projColWidth)
self.mainPanePos = theConf.rdIntList(cnfSec, "mainpane", self.mainPanePos) self.mainPanePos = theConf.rdIntList(cnfSec, "mainpane", self.mainPanePos)
self.docPanePos = theConf.rdIntList(cnfSec, "docpane", self.docPanePos) self.docPanePos = theConf.rdIntList(cnfSec, "docpane", self.docPanePos)
@@ -581,8 +577,6 @@ class Config:
theConf["Sizes"] = { theConf["Sizes"] = {
"geometry": self._packList(self.winGeometry), "geometry": self._packList(self.winGeometry),
"preferences": self._packList(self.prefGeometry), "preferences": self._packList(self.prefGeometry),
"treecols": self._packList(self.treeColWidth),
"novelcols": self._packList(self.novelColWidth),
"projcols": self._packList(self.projColWidth), "projcols": self._packList(self.projColWidth),
"mainpane": self._packList(self.mainPanePos), "mainpane": self._packList(self.mainPanePos),
"docpane": self._packList(self.docPanePos), "docpane": self._packList(self.docPanePos),
@@ -811,20 +805,6 @@ class Config:
self.confChanged = True self.confChanged = True
return True return True
def setTreeColWidths(self, colWidths):
"""Set the column widths of the main project tree.
"""
self.treeColWidth = [int(x/self.guiScale) for x in colWidths]
self.confChanged = True
return True
def setNovelColWidths(self, colWidths):
"""Set the column widths of the novel tree.
"""
self.novelColWidth = [int(x/self.guiScale) for x in colWidths]
self.confChanged = True
return True
def setProjColWidths(self, colWidths): def setProjColWidths(self, colWidths):
"""Set the column widths of the Load Project dialog. """Set the column widths of the Load Project dialog.
""" """
@@ -910,12 +890,6 @@ class Config:
def getPreferencesSize(self): def getPreferencesSize(self):
return [int(x*self.guiScale) for x in self.prefGeometry] return [int(x*self.guiScale) for x in self.prefGeometry]
def getTreeColWidths(self):
return [int(x*self.guiScale) for x in self.treeColWidth]
def getNovelColWidths(self):
return [int(x*self.guiScale) for x in self.novelColWidth]
def getProjColWidths(self): def getProjColWidths(self):
return [int(x*self.guiScale) for x in self.projColWidth] return [int(x*self.guiScale) for x in self.projColWidth]
+120 -15
View File
@@ -35,11 +35,11 @@ from PyQt5.QtGui import QPalette
from PyQt5.QtCore import Qt, QSize, pyqtSlot, pyqtSignal from PyQt5.QtCore import Qt, QSize, pyqtSlot, pyqtSignal
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView, QLabel, QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView, QLabel,
QMenu, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QMenu, QSizePolicy, QToolButton, QToolTip, QTreeWidget, QTreeWidgetItem,
QWidget QVBoxLayout, QWidget
) )
from novelwriter.enum import nwDocMode, nwItemClass from novelwriter.enum import nwDocMode, nwItemClass, nwOutline
from novelwriter.common import checkInt from novelwriter.common import checkInt
from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst
@@ -84,6 +84,7 @@ class GuiNovelView(QWidget):
# Function Mappings # Function Mappings
self.updateWordCounts = self.novelTree.updateWordCounts self.updateWordCounts = self.novelTree.updateWordCounts
self.getSelectedHandle = self.novelTree.getSelectedHandle self.getSelectedHandle = self.novelTree.getSelectedHandle
self.setActiveHandle = self.novelTree.setActiveHandle
return return
@@ -322,7 +323,12 @@ class GuiNovelTree(QTreeWidget):
C_TITLE = 0 C_TITLE = 0
C_WORDS = 1 C_WORDS = 1
C_LAST = 2 C_EXTRA = 2
C_MORE = 3
D_HANDLE = Qt.UserRole
D_TITLE = Qt.UserRole + 1
D_KEY = Qt.UserRole + 2
def __init__(self, novelView): def __init__(self, novelView):
QTreeWidget.__init__(self, novelView) QTreeWidget.__init__(self, novelView)
@@ -339,6 +345,7 @@ class GuiNovelTree(QTreeWidget):
self._treeMap = {} self._treeMap = {}
self._lastBuild = 0 self._lastBuild = 0
self._lastCol = NovelTreeColumn.POV self._lastCol = NovelTreeColumn.POV
self._actHandle = None
# Cached Strings # Cached Strings
self._povLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY]) self._povLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY])
@@ -353,9 +360,11 @@ class GuiNovelTree(QTreeWidget):
self.setIconSize(QSize(iPx, iPx)) self.setIconSize(QSize(iPx, iPx))
self.setFrameStyle(QFrame.NoFrame) self.setFrameStyle(QFrame.NoFrame)
self.setUniformRowHeights(True)
self.setAllColumnsShowFocus(True)
self.setHeaderHidden(True) self.setHeaderHidden(True)
self.setIndentation(0) self.setIndentation(0)
self.setColumnCount(3) self.setColumnCount(4)
self.setSelectionBehavior(QAbstractItemView.SelectRows) self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSelectionMode(QAbstractItemView.SingleSelection) self.setSelectionMode(QAbstractItemView.SingleSelection)
self.setExpandsOnDoubleClick(False) self.setExpandsOnDoubleClick(False)
@@ -367,7 +376,8 @@ class GuiNovelTree(QTreeWidget):
treeHeader.setMinimumSectionSize(iPx + cMg) treeHeader.setMinimumSectionSize(iPx + cMg)
treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.Stretch) treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.Stretch)
treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeToContents) treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeToContents)
treeHeader.setSectionResizeMode(self.C_LAST, QHeaderView.ResizeToContents) treeHeader.setSectionResizeMode(self.C_EXTRA, QHeaderView.ResizeToContents)
treeHeader.setSectionResizeMode(self.C_MORE, QHeaderView.ResizeToContents)
# Pre-Generate Tree Formatting # Pre-Generate Tree Formatting
fH1 = self.font() fH1 = self.font()
@@ -385,8 +395,12 @@ class GuiNovelTree(QTreeWidget):
self.mainTheme.loadDecoration("deco_doc_h3", pxH=iPx), self.mainTheme.loadDecoration("deco_doc_h3", pxH=iPx),
self.mainTheme.loadDecoration("deco_doc_h4", pxH=iPx), self.mainTheme.loadDecoration("deco_doc_h4", pxH=iPx),
] ]
self._pMore = self.mainTheme.loadDecoration("deco_doc_more", pxH=iPx)
self._pActive = self.mainTheme.loadDecoration("deco_more_on", pxH=iPx)
self._pInactive = self.mainTheme.loadDecoration("deco_more_off", pxH=iPx)
# Connect signals # Connect signals
self.clicked.connect(self._treeItemClicked)
self.itemDoubleClicked.connect(self._treeDoubleClick) self.itemDoubleClicked.connect(self._treeDoubleClick)
self.itemSelectionChanged.connect(self._treeSelectionChange) self.itemSelectionChanged.connect(self._treeSelectionChange)
@@ -449,7 +463,7 @@ class GuiNovelTree(QTreeWidget):
selItem = self.selectedItems() selItem = self.selectedItems()
titleKey = None titleKey = None
if selItem: if selItem:
titleKey = selItem[0].data(self.C_TITLE, Qt.UserRole)[2] titleKey = selItem[0].data(self.C_TITLE, self.D_KEY)
self._populateTree(rootHandle) self._populateTree(rootHandle)
self.theProject.setLastNovelViewed(rootHandle) self.theProject.setLastNovelViewed(rootHandle)
@@ -476,8 +490,9 @@ class GuiNovelTree(QTreeWidget):
tHandle = None tHandle = None
tLine = 0 tLine = 0
if selItem: if selItem:
tHandle = selItem[0].data(self.C_TITLE, Qt.UserRole)[0] tHandle = selItem[0].data(self.C_TITLE, self.D_HANDLE)
tLine = checkInt(selItem[0].data(self.C_TITLE, Qt.UserRole)[1], 1) - 1 sTitle = selItem[0].data(self.C_TITLE, self.D_TITLE)
tLine = checkInt(sTitle[1:], 1) - 1
return tHandle, tLine return tHandle, tLine
@@ -487,11 +502,34 @@ class GuiNovelTree(QTreeWidget):
if self._lastCol != colType: if self._lastCol != colType:
logger.debug("Changing last column to %s", colType.name) logger.debug("Changing last column to %s", colType.name)
self._lastCol = colType self._lastCol = colType
self.setColumnHidden(self.C_LAST, colType == NovelTreeColumn.HIDDEN) self.setColumnHidden(self.C_EXTRA, colType == NovelTreeColumn.HIDDEN)
if doRefresh: if doRefresh:
self.refreshTree(rootHandle=self.theProject.lastNovel, overRide=True) self.refreshTree(rootHandle=self.theProject.lastNovel, overRide=True)
return return
def setActiveHandle(self, tHandle):
"""Highlight the rows associated with a given handle.
"""
tStart = time()
self._actHandle = tHandle
for i in range(self.topLevelItemCount()):
tItem = self.topLevelItem(i)
if tItem.data(self.C_TITLE, self.D_HANDLE) == tHandle:
tItem.setBackground(self.C_TITLE, self.palette().alternateBase())
tItem.setBackground(self.C_WORDS, self.palette().alternateBase())
tItem.setBackground(self.C_EXTRA, self.palette().alternateBase())
tItem.setBackground(self.C_MORE, self.palette().alternateBase())
else:
tItem.setBackground(self.C_TITLE, self.palette().base())
tItem.setBackground(self.C_WORDS, self.palette().base())
tItem.setBackground(self.C_EXTRA, self.palette().base())
tItem.setBackground(self.C_MORE, self.palette().base())
logger.verbose("Highlighted Novel Tree in %.3f ms", (time() - tStart)*1000)
return
## ##
# Events # Events
## ##
@@ -521,10 +559,28 @@ class GuiNovelTree(QTreeWidget):
return return
def focusOutEvent(self, theEvent):
"""Clear the selection when the tree no longer has focus.
"""
QTreeWidget.focusOutEvent(self, theEvent)
self.clearSelection()
return
## ##
# Private Slots # Private Slots
## ##
@pyqtSlot("QModelIndex")
def _treeItemClicked(self, mIndex):
"""The user clicked on an item in the tree.
"""
if mIndex.column() == self.C_MORE:
tHandle = mIndex.siblingAtColumn(self.C_TITLE).data(self.D_HANDLE)
sTitle = mIndex.siblingAtColumn(self.C_TITLE).data(self.D_TITLE)
tipPos = self.mapToGlobal(self.visualRect(mIndex).topRight())
self._popMetaBox(tipPos, tHandle, sTitle)
return
@pyqtSlot() @pyqtSlot()
def _treeSelectionChange(self): def _treeSelectionChange(self):
"""Extract the handle and line number of the currently selected """Extract the handle and line number of the currently selected
@@ -564,23 +620,27 @@ class GuiNovelTree(QTreeWidget):
continue continue
newItem = QTreeWidgetItem() newItem = QTreeWidgetItem()
theData = (tHandle, sTitle[1:].lstrip("0"), tKey)
newItem.setData(self.C_TITLE, Qt.DecorationRole, self._pIndent[iLevel]) newItem.setData(self.C_TITLE, Qt.DecorationRole, self._pIndent[iLevel])
newItem.setText(self.C_TITLE, novIdx.title) newItem.setText(self.C_TITLE, novIdx.title)
newItem.setData(self.C_TITLE, Qt.UserRole, theData) newItem.setData(self.C_TITLE, self.D_HANDLE, tHandle)
newItem.setData(self.C_TITLE, self.D_TITLE, sTitle)
newItem.setData(self.C_TITLE, self.D_KEY, tKey)
newItem.setFont(self.C_TITLE, self._hFonts[iLevel]) newItem.setFont(self.C_TITLE, self._hFonts[iLevel])
newItem.setText(self.C_WORDS, f"{novIdx.wordCount:n}") newItem.setText(self.C_WORDS, f"{novIdx.wordCount:n}")
newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight) newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
newItem.setData(self.C_MORE, Qt.DecorationRole, self._pMore)
# Custom column
lastText, toolTip = self._getLastColumnText(tHandle, sTitle) lastText, toolTip = self._getLastColumnText(tHandle, sTitle)
newItem.setText(self.C_LAST, lastText) newItem.setText(self.C_EXTRA, lastText)
if lastText: if lastText:
newItem.setToolTip(self.C_LAST, toolTip) newItem.setToolTip(self.C_EXTRA, toolTip)
self._treeMap[tKey] = newItem self._treeMap[tKey] = newItem
self.addTopLevelItem(newItem) self.addTopLevelItem(newItem)
self.setActiveHandle(self._actHandle)
logger.verbose("Novel Tree built in %.3f ms", (time() - tStart)*1000) logger.verbose("Novel Tree built in %.3f ms", (time() - tStart)*1000)
self._lastBuild = time() self._lastBuild = time()
@@ -607,4 +667,49 @@ class GuiNovelTree(QTreeWidget):
return "", "" return "", ""
def _popMetaBox(self, qPos, tHandle, sTitle):
"""Show the novel meta data box.
"""
logger.debug("Generating meta data tooltip for '%s:%s'", tHandle, sTitle)
pIndex = self.theProject.index
novIdx = pIndex.getNovelData(tHandle, sTitle)
refTags = pIndex.getReferences(tHandle, sTitle)
synopText = novIdx.synopsis
if synopText:
synopLabel = trConst(nwLabels.OUTLINE_COLS[nwOutline.SYNOP])
synopText = f"<p><b>{synopLabel}</b>: {synopText}</p>"
refLines = []
refLines = self._appendMetaTag(refTags, nwKeyWords.POV_KEY, refLines)
refLines = self._appendMetaTag(refTags, nwKeyWords.FOCUS_KEY, refLines)
refLines = self._appendMetaTag(refTags, nwKeyWords.CHAR_KEY, refLines)
refLines = self._appendMetaTag(refTags, nwKeyWords.PLOT_KEY, refLines)
refLines = self._appendMetaTag(refTags, nwKeyWords.TIME_KEY, refLines)
refLines = self._appendMetaTag(refTags, nwKeyWords.WORLD_KEY, refLines)
refLines = self._appendMetaTag(refTags, nwKeyWords.OBJECT_KEY, refLines)
refLines = self._appendMetaTag(refTags, nwKeyWords.ENTITY_KEY, refLines)
refLines = self._appendMetaTag(refTags, nwKeyWords.CUSTOM_KEY, refLines)
refText = ""
if refLines:
refList = "<br>".join(refLines)
refText = f"<p>{refList}</p>"
ttText = refText + synopText or self.tr("No meta data")
if ttText:
QToolTip.showText(qPos, ttText)
return
@staticmethod
def _appendMetaTag(refs, key, lines):
"""Generate a reference list for a given reference key.
"""
tags = ", ".join(refs.get(key, []))
if tags:
lines.append(f"<b>{trConst(nwLabels.KEY_NAME[key])}</b>: {tags}")
return lines
# END Class GuiNovelTree # END Class GuiNovelTree
+1
View File
@@ -326,6 +326,7 @@ class GuiOutlineTree(QTreeWidget):
self.theProject = theOutline.mainGui.theProject self.theProject = theOutline.mainGui.theProject
self.mainTheme = theOutline.mainGui.mainTheme self.mainTheme = theOutline.mainGui.mainTheme
self.setUniformRowHeights(True)
self.setFrameStyle(QFrame.NoFrame) self.setFrameStyle(QFrame.NoFrame)
self.setSelectionBehavior(QAbstractItemView.SelectRows) self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSelectionMode(QAbstractItemView.SingleSelection) self.setSelectionMode(QAbstractItemView.SingleSelection)
+3
View File
@@ -350,7 +350,10 @@ class GuiProjectTree(QTreeWidget):
self.setIconSize(QSize(iPx, iPx)) self.setIconSize(QSize(iPx, iPx))
self.setFrameStyle(QFrame.NoFrame) self.setFrameStyle(QFrame.NoFrame)
self.setUniformRowHeights(True)
self.setAllColumnsShowFocus(True)
self.setExpandsOnDoubleClick(False) self.setExpandsOnDoubleClick(False)
self.setAutoExpandDelay(1000)
self.setHeaderHidden(True) self.setHeaderHidden(True)
self.setIndentation(iPx) self.setIndentation(iPx)
self.setColumnCount(4) self.setColumnCount(4)
+1 -1
View File
@@ -474,7 +474,7 @@ class GuiIcons:
"bullet-on", "bullet-off", "bullet-on", "bullet-off",
# Decorations # Decorations
"deco_doc_h0", "deco_doc_h1", "deco_doc_h2", "deco_doc_h3", "deco_doc_h4", "deco_doc_h0", "deco_doc_h1", "deco_doc_h2", "deco_doc_h3", "deco_doc_h4", "deco_doc_more",
} }
IMAGE_MAP = { IMAGE_MAP = {
+5 -2
View File
@@ -558,7 +558,7 @@ class GuiMain(QMainWindow):
# Document Actions # Document Actions
## ##
def closeDocument(self): def closeDocument(self, beforeOpen=False):
"""Close the document and clear the editor and title field. """Close the document and clear the editor and title field.
""" """
if not self.hasProject: if not self.hasProject:
@@ -573,6 +573,8 @@ class GuiMain(QMainWindow):
if self.docEditor.docChanged(): if self.docEditor.docChanged():
self.saveDocument() self.saveDocument()
self.docEditor.clearEditor() self.docEditor.clearEditor()
if not beforeOpen:
self.novelView.setActiveHandle(None)
return True return True
@@ -587,13 +589,14 @@ class GuiMain(QMainWindow):
logger.debug("Requested item '%s' is not a document", tHandle) logger.debug("Requested item '%s' is not a document", tHandle)
return False return False
self.closeDocument() self.closeDocument(beforeOpen=True)
self._changeView(nwView.EDITOR) self._changeView(nwView.EDITOR)
if self.docEditor.loadText(tHandle, tLine): if self.docEditor.loadText(tHandle, tLine):
if changeFocus: if changeFocus:
self.docEditor.setFocus() self.docEditor.setFocus()
self.theProject.setLastEdited(tHandle) self.theProject.setLastEdited(tHandle)
self.projView.setSelectedHandle(tHandle, doScroll=doScroll) self.projView.setSelectedHandle(tHandle, doScroll=doScroll)
self.novelView.setActiveHandle(tHandle)
else: else:
return False return False
+1 -3
View File
@@ -13,8 +13,6 @@ hidehscroll = False
[Sizes] [Sizes]
geometry = 1200, 650 geometry = 1200, 650
preferences = 700, 615 preferences = 700, 615
treecols = 200, 50, 30
novelcols = 200, 50
projcols = 200, 60, 140 projcols = 200, 60, 140
mainpane = 300, 800 mainpane = 300, 800
docpane = 400, 400 docpane = 400, 400
@@ -30,7 +28,7 @@ emphlabels = True
[Editor] [Editor]
textfont = None textfont = None
textsize = 12 textsize = 12
width = 600 width = 700
margin = 40 margin = 40
tabwidth = 40 tabwidth = 40
focuswidth = 800 focuswidth = 800
@@ -13,8 +13,6 @@ hidehscroll = True
[Sizes] [Sizes]
geometry = 1200, 650 geometry = 1200, 650
preferences = 670, 589 preferences = 670, 589
treecols = 200, 50, 30
novelcols = 200, 50
projcols = 200, 60, 140 projcols = 200, 60, 140
mainpane = 300, 800 mainpane = 300, 800
docpane = 400, 400 docpane = 400, 400
+2 -28
View File
@@ -410,32 +410,6 @@ def testBaseConfig_SettersGetters(tmpConf, tmpDir, outDir, refDir):
assert tmpConf.setPreferencesSize(700, 615) assert tmpConf.setPreferencesSize(700, 615)
# Project Tree Columns
tmpConf.guiScale = 2.0
assert tmpConf.setTreeColWidths([10, 20, 25])
assert tmpConf.getTreeColWidths() == [10, 20, 24]
assert tmpConf.treeColWidth == [5, 10, 12]
tmpConf.guiScale = 1.0
assert tmpConf.setTreeColWidths([10, 20, 25])
assert tmpConf.getTreeColWidths() == [10, 20, 25]
assert tmpConf.treeColWidth == [10, 20, 25]
assert tmpConf.setTreeColWidths([200, 50, 30])
# Novel Tree Columns
tmpConf.guiScale = 2.0
assert tmpConf.setNovelColWidths([10, 20])
assert tmpConf.getNovelColWidths() == [10, 20]
assert tmpConf.novelColWidth == [5, 10]
tmpConf.guiScale = 1.0
assert tmpConf.setNovelColWidths([10, 20])
assert tmpConf.getNovelColWidths() == [10, 20]
assert tmpConf.novelColWidth == [10, 20]
assert tmpConf.setNovelColWidths([200, 50])
# Project Settings Tree Columns # Project Settings Tree Columns
tmpConf.guiScale = 2.0 tmpConf.guiScale = 2.0
assert tmpConf.setProjColWidths([10, 20, 30]) assert tmpConf.setProjColWidths([10, 20, 30])
@@ -505,13 +479,13 @@ def testBaseConfig_SettersGetters(tmpConf, tmpDir, outDir, refDir):
# ============ # ============
tmpConf.guiScale = 1.0 tmpConf.guiScale = 1.0
assert tmpConf.getTextWidth(False) == 600 assert tmpConf.getTextWidth(False) == 700
assert tmpConf.getTextWidth(True) == 800 assert tmpConf.getTextWidth(True) == 800
assert tmpConf.getTextMargin() == 40 assert tmpConf.getTextMargin() == 40
assert tmpConf.getTabWidth() == 40 assert tmpConf.getTabWidth() == 40
tmpConf.guiScale = 2.0 tmpConf.guiScale = 2.0
assert tmpConf.getTextWidth(False) == 1200 assert tmpConf.getTextWidth(False) == 1400
assert tmpConf.getTextWidth(True) == 1600 assert tmpConf.getTextWidth(True) == 1600
assert tmpConf.getTextMargin() == 80 assert tmpConf.getTextMargin() == 80
assert tmpConf.getTabWidth() == 80 assert tmpConf.getTabWidth() == 80
+2 -2
View File
@@ -239,8 +239,8 @@ def testDlgPreferences_Main(qtbot, monkeypatch, fncDir, outDir, refDir):
copyfile(projFile, testFile) copyfile(projFile, testFile)
ignTuple = ( ignTuple = (
"timestamp", "guifont", "lastnotes", "guilang", "geometry", "timestamp", "guifont", "lastnotes", "guilang", "geometry",
"preferences", "treecols", "novelcols", "projcols", "mainpane", "preferences", "projcols", "mainpane", "docpane", "viewpane",
"docpane", "viewpane", "outlinepane", "textfont", "textsize" "outlinepane", "textfont", "textsize"
) )
assert cmpFiles(testFile, compFile, ignoreStart=ignTuple) assert cmpFiles(testFile, compFile, ignoreStart=ignTuple)
+43 -11
View File
@@ -24,8 +24,9 @@ import pytest
from tools import buildTestProject, writeFile from tools import buildTestProject, writeFile
from PyQt5.QtCore import Qt from PyQt5.QtGui import QFocusEvent
from PyQt5.QtWidgets import QMessageBox from PyQt5.QtCore import Qt, QEvent
from PyQt5.QtWidgets import QMessageBox, QToolTip
from novelwriter.enum import nwWidget, nwItemType from novelwriter.enum import nwWidget, nwItemType
from novelwriter.dialogs import GuiEditLabel from novelwriter.dialogs import GuiEditLabel
@@ -53,8 +54,12 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
"# Jane Doe\n\n@tag: Jane\n\n" "# Jane Doe\n\n@tag: Jane\n\n"
) )
writeFile( writeFile(
os.path.join(nwGUI.theProject.projContent, "000000000000f.nwd"), os.path.join(nwGUI.theProject.projContent, "000000000000f.nwd"), (
"### Scene One\n\n@pov: Jane\n@focus: Jane\n\n" "### Scene One\n\n"
"@pov: Jane\n"
"@focus: Jane\n\n"
"% Synopsis: This is a scene."
)
) )
novelView = nwGUI.novelView novelView = nwGUI.novelView
@@ -124,12 +129,12 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
assert nwGUI.docViewer.docHandle() is None assert nwGUI.docViewer.docHandle() is None
scRect = novelTree.visualItemRect(scItem) scRect = novelTree.visualItemRect(scItem)
oldData = scItem.data(novelTree.C_TITLE, Qt.UserRole) oldData = scItem.data(novelTree.C_TITLE, novelTree.D_HANDLE)
scItem.setData(novelTree.C_TITLE, Qt.UserRole, (None, "", "")) scItem.setData(novelTree.C_TITLE, novelTree.D_HANDLE, None)
qtbot.mouseClick(vPort, Qt.MiddleButton, pos=scRect.center(), delay=10) qtbot.mouseClick(vPort, Qt.MiddleButton, pos=scRect.center(), delay=10)
assert nwGUI.docViewer.docHandle() is None assert nwGUI.docViewer.docHandle() is None
scItem.setData(novelTree.C_TITLE, Qt.UserRole, oldData) scItem.setData(novelTree.C_TITLE, novelTree.D_HANDLE, oldData)
qtbot.mouseClick(vPort, Qt.MiddleButton, pos=scRect.center(), delay=10) qtbot.mouseClick(vPort, Qt.MiddleButton, pos=scRect.center(), delay=10)
assert nwGUI.docViewer.docHandle() == "000000000000f" assert nwGUI.docViewer.docHandle() == "000000000000f"
@@ -137,26 +142,26 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# =========== # ===========
novelBar.setLastColType(NovelTreeColumn.HIDDEN) novelBar.setLastColType(NovelTreeColumn.HIDDEN)
assert novelTree.isColumnHidden(novelTree.C_LAST) is True assert novelTree.isColumnHidden(novelTree.C_EXTRA) is True
assert novelTree.lastColType == NovelTreeColumn.HIDDEN assert novelTree.lastColType == NovelTreeColumn.HIDDEN
assert novelTree._getLastColumnText("000000000000f", "T000001") == ("", "") assert novelTree._getLastColumnText("000000000000f", "T000001") == ("", "")
novelBar.setLastColType(NovelTreeColumn.POV) novelBar.setLastColType(NovelTreeColumn.POV)
assert novelTree.isColumnHidden(novelTree.C_LAST) is False assert novelTree.isColumnHidden(novelTree.C_EXTRA) is False
assert novelTree.lastColType == NovelTreeColumn.POV assert novelTree.lastColType == NovelTreeColumn.POV
assert novelTree._getLastColumnText("000000000000f", "T000001") == ( assert novelTree._getLastColumnText("000000000000f", "T000001") == (
"Jane", "Point of View: Jane" "Jane", "Point of View: Jane"
) )
novelBar.setLastColType(NovelTreeColumn.FOCUS) novelBar.setLastColType(NovelTreeColumn.FOCUS)
assert novelTree.isColumnHidden(novelTree.C_LAST) is False assert novelTree.isColumnHidden(novelTree.C_EXTRA) is False
assert novelTree.lastColType == NovelTreeColumn.FOCUS assert novelTree.lastColType == NovelTreeColumn.FOCUS
assert novelTree._getLastColumnText("000000000000f", "T000001") == ( assert novelTree._getLastColumnText("000000000000f", "T000001") == (
"Jane", "Focus: Jane" "Jane", "Focus: Jane"
) )
novelBar.setLastColType(NovelTreeColumn.PLOT) novelBar.setLastColType(NovelTreeColumn.PLOT)
assert novelTree.isColumnHidden(novelTree.C_LAST) is False assert novelTree.isColumnHidden(novelTree.C_EXTRA) is False
assert novelTree.lastColType == NovelTreeColumn.PLOT assert novelTree.lastColType == NovelTreeColumn.PLOT
assert novelTree._getLastColumnText("000000000000f", "T000001") == ( assert novelTree._getLastColumnText("000000000000f", "T000001") == (
"", "Plot: " "", "Plot: "
@@ -165,6 +170,33 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
novelTree._lastCol = None novelTree._lastCol = None
assert novelTree._getLastColumnText("0000000000000", "T000000") == ("", "") assert novelTree._getLastColumnText("0000000000000", "T000000") == ("", "")
# Item Meta
# =========
ttText = ""
def showText(pos, text):
nonlocal ttText
ttText = text
mIndex = novelTree.model().index(2, novelTree.C_MORE)
with monkeypatch.context() as mp:
mp.setattr(QToolTip, "showText", showText)
novelTree._treeItemClicked(mIndex)
assert ttText == (
"<p><b>Point of View</b>: Jane<br><b>Focus</b>: Jane</p>"
"<p><b>Synopsis</b>: This is a scene.</p>"
)
# Other Checks
# ============
scItem = novelTree.topLevelItem(2)
scItem.setSelected(True)
assert scItem.isSelected()
novelTree.focusOutEvent(QFocusEvent(QEvent.None_, Qt.MouseFocusReason))
assert not scItem.isSelected()
# Close # Close
# ===== # =====
+1 -1
View File
@@ -81,7 +81,7 @@ def testGuiTheme_Main(qtbot, monkeypatch, nwMinimal, tmpDir):
assert thePalette.window().color() == QColor(54, 54, 54) assert thePalette.window().color() == QColor(54, 54, 54)
assert thePalette.windowText().color() == QColor(174, 174, 174) assert thePalette.windowText().color() == QColor(174, 174, 174)
assert thePalette.base().color() == QColor(62, 62, 62) assert thePalette.base().color() == QColor(62, 62, 62)
assert thePalette.alternateBase().color() == QColor(67, 67, 67) assert thePalette.alternateBase().color() == QColor(78, 78, 78)
assert thePalette.text().color() == QColor(174, 174, 174) assert thePalette.text().color() == QColor(174, 174, 174)
assert thePalette.toolTipBase().color() == QColor(255, 255, 192) assert thePalette.toolTipBase().color() == QColor(255, 255, 192)
assert thePalette.toolTipText().color() == QColor(21, 21, 13) assert thePalette.toolTipText().color() == QColor(21, 21, 13)