Add a tool tip with meta data behind a button on each novel tree item
This commit is contained in:
@@ -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 |
@@ -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
|
||||||
|
|
||||||
@@ -322,7 +322,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)
|
||||||
@@ -357,7 +362,7 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
self.setAllColumnsShowFocus(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)
|
||||||
@@ -369,7 +374,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()
|
||||||
@@ -387,8 +393,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)
|
||||||
|
|
||||||
@@ -451,7 +461,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)
|
||||||
@@ -478,8 +488,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
|
||||||
|
|
||||||
@@ -489,7 +500,7 @@ 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
|
||||||
@@ -527,6 +538,17 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
# 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
|
||||||
@@ -566,19 +588,21 @@ 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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
newItem.setData(self.C_MORE, Qt.DecorationRole, self._pMore)
|
||||||
|
|
||||||
self._treeMap[tKey] = newItem
|
self._treeMap[tKey] = newItem
|
||||||
self.addTopLevelItem(newItem)
|
self.addTopLevelItem(newItem)
|
||||||
@@ -609,4 +633,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
|
||||||
|
|||||||
@@ -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 = {
|
||||||
|
|||||||
@@ -137,26 +137,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: "
|
||||||
|
|||||||
Reference in New Issue
Block a user