Restore novel heading details tooltip and active row colouring

This commit is contained in:
Veronica Berglyd Olsen
2025-02-22 23:13:57 +01:00
parent 71ad7c3229
commit 43e420ab0b
4 changed files with 83 additions and 69 deletions
+5 -1
View File
@@ -125,7 +125,11 @@ class Index:
if (item := SHARED.project.tree[tHandle]) and item.isRootType() and item.isNovelLike(): if (item := SHARED.project.tree[tHandle]) and item.isRootType() and item.isNovelLike():
model = NovelModel() model = NovelModel()
for handle in SHARED.project.tree.subTree(tHandle): for handle in SHARED.project.tree.subTree(tHandle):
if node := self._itemIndex[handle]: if (
(node := self._itemIndex[handle])
and node.item.isDocumentLayout()
and node.item.isActive
):
model.append(node) model.append(node)
self._novelModels[tHandle] = model self._novelModels[tHandle] = model
return return
+4 -2
View File
@@ -84,8 +84,10 @@ class NovelModel(QAbstractTableModel):
def data(self, index: QModelIndex, role: Qt.ItemDataRole) -> T_NodeData: def data(self, index: QModelIndex, role: Qt.ItemDataRole) -> T_NodeData:
"""Return display data for a node.""" """Return display data for a node."""
if index.isValid() and (row := index.row()) < len(self._rows): try:
return self._rows[row].get(C_FACTOR*index.column() | role) return self._rows[index.row()].get(C_FACTOR*index.column() | role)
except Exception:
print("NovelModel Debug: Oops!")
return None return None
def keys(self, index: QModelIndex) -> tuple[str | None, str | None]: def keys(self, index: QModelIndex) -> tuple[str | None, str | None]:
+74 -65
View File
@@ -29,20 +29,24 @@ import logging
from enum import Enum from enum import Enum
from PyQt6.QtCore import QModelIndex, pyqtSignal, pyqtSlot from PyQt6.QtCore import QModelIndex, QPoint, pyqtSignal, pyqtSlot
from PyQt6.QtGui import QActionGroup, QFont, QPalette from PyQt6.QtGui import QActionGroup, QFont, QPainter, QPalette
from PyQt6.QtWidgets import QAbstractItemView, QFrame, QHBoxLayout, QMenu, QVBoxLayout, QWidget from PyQt6.QtWidgets import (
QAbstractItemView, QFrame, QHBoxLayout, QMenu, QStyleOptionViewItem,
QToolTip, QVBoxLayout, QWidget
)
from novelwriter import CONFIG, SHARED from novelwriter import CONFIG, SHARED
from novelwriter.common import qtAddAction, qtAddMenu, qtLambda from novelwriter.common import qtAddAction, qtAddMenu, qtLambda
from novelwriter.constants import nwKeyWords, nwLabels, trConst
from novelwriter.core.novelmodel import NovelModel from novelwriter.core.novelmodel import NovelModel
from novelwriter.enum import nwChange, nwDocMode, nwItemClass from novelwriter.enum import nwChange, nwDocMode, nwItemClass, nwOutline
from novelwriter.extensions.modified import NIconToolButton, NTreeView from novelwriter.extensions.modified import NIconToolButton, NTreeView
from novelwriter.extensions.novelselector import NovelSelector from novelwriter.extensions.novelselector import NovelSelector
from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
from novelwriter.types import ( from novelwriter.types import (
QtHeaderStretch, QtHeaderToContents, QtScrollAlwaysOff, QtScrollAsNeeded, QtHeaderStretch, QtHeaderToContents, QtScrollAlwaysOff, QtScrollAsNeeded,
QtSizeExpanding, QtUserRole QtSizeExpanding
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -166,7 +170,7 @@ class GuiNovelView(QWidget):
@pyqtSlot(str) @pyqtSlot(str)
def setActiveHandle(self, tHandle: str) -> None: def setActiveHandle(self, tHandle: str) -> None:
"""Highlight the rows associated with a given handle.""" """Highlight the rows associated with a given handle."""
# self.novelTree.setActiveHandle(tHandle) self.novelTree.setActiveHandle(tHandle)
return return
@pyqtSlot() @pyqtSlot()
@@ -350,17 +354,6 @@ class GuiNovelToolBar(QWidget):
class GuiNovelTree(NTreeView): class GuiNovelTree(NTreeView):
C_DATA = 0
C_TITLE = 0
C_WORDS = 1
C_EXTRA = 2
C_MORE = 3
D_HANDLE = QtUserRole
D_TITLE = QtUserRole + 1
D_KEY = QtUserRole + 2
D_EXTRA = QtUserRole + 3
def __init__(self, novelView: GuiNovelView) -> None: def __init__(self, novelView: GuiNovelView) -> None:
super().__init__(parent=novelView) super().__init__(parent=novelView)
@@ -369,10 +362,10 @@ class GuiNovelTree(NTreeView):
self.novelView = novelView self.novelView = novelView
# Internal Variables # Internal Variables
self._actHandle = None
# self._lastBuild = 0 # self._lastBuild = 0
# self._lastCol = NovelTreeColumn.POV # self._lastCol = NovelTreeColumn.POV
# self._lastColSize = 0.25 # self._lastColSize = 0.25
# self._actHandle = None
# self._treeMap: dict[str, QTreeWidgetItem] = {} # self._treeMap: dict[str, QTreeWidgetItem] = {}
# Cached Strings # Cached Strings
@@ -428,6 +421,17 @@ class GuiNovelTree(NTreeView):
return model.keys(self.currentIndex()) return model.keys(self.currentIndex())
return None, None return None, None
##
# Setters
##
def setActiveHandle(self, tHandle: str | None) -> None:
"""Set the handle to be highlighted."""
self._actHandle = tHandle
if viewport := self.viewport():
viewport.repaint()
return
## ##
# Class Methods # Class Methods
## ##
@@ -442,6 +446,17 @@ class GuiNovelTree(NTreeView):
header.setSectionResizeMode(i, QtHeaderToContents) header.setSectionResizeMode(i, QtHeaderToContents)
return return
##
# Overloads
##
def drawRow(self, painter: QPainter, opt: QStyleOptionViewItem, index: QModelIndex) -> None:
"""Draw a box on the active row."""
if (model := self._getModel()) and model.keys(index)[0] == self._actHandle:
painter.fillRect(opt.rect, self.palette().alternateBase())
super().drawRow(painter, opt, index)
return
## ##
# Private Slots # Private Slots
## ##
@@ -449,8 +464,13 @@ class GuiNovelTree(NTreeView):
@pyqtSlot(QModelIndex) @pyqtSlot(QModelIndex)
def _onSingleClick(self, index: QModelIndex) -> None: def _onSingleClick(self, index: QModelIndex) -> None:
"""The user single-clicked an index.""" """The user single-clicked an index."""
if (model := self._getModel()) and (keys := model.keys(index)) and (tHandle := keys[0]): if index.isValid() and (model := self._getModel()):
self.novelView.selectedItemChanged.emit(tHandle) keys = model.keys(index)
if (tHandle := keys[0]) and (sTitle := keys[1]):
self.novelView.selectedItemChanged.emit(tHandle)
if index.column() == model.columnCount(index) - 1:
pos = self.mapToGlobal(self.visualRect(index).topRight())
self._popMetaBox(pos, tHandle, sTitle)
return return
@pyqtSlot(QModelIndex) @pyqtSlot(QModelIndex)
@@ -483,6 +503,40 @@ class GuiNovelTree(NTreeView):
return model return model
return None return None
def _popMetaBox(self, qPos: QPoint, tHandle: str, sTitle: str) -> None:
"""Show the novel meta data box."""
if head := SHARED.project.index.getItemHeading(tHandle, sTitle):
logger.debug("Generating meta data tooltip for '%s:%s'", tHandle, sTitle)
if synopsis := head.synopsis:
label = trConst(nwLabels.OUTLINE_COLS[nwOutline.SYNOP])
synopsis = f"<p><b>{label}</b>: {synopsis}</p>"
def appendTags(refs: dict, key: str, lines: list[str]) -> list[str]:
"""Generate a reference list for a given reference key."""
if tags := ", ".join(refs.get(key, [])):
lines.append(f"<b>{trConst(nwLabels.KEY_NAME[key])}</b>: {tags}")
return lines
tags = SHARED.project.index.getReferences(tHandle, sTitle)
lines = []
lines = appendTags(tags, nwKeyWords.POV_KEY, lines)
lines = appendTags(tags, nwKeyWords.FOCUS_KEY, lines)
lines = appendTags(tags, nwKeyWords.CHAR_KEY, lines)
lines = appendTags(tags, nwKeyWords.PLOT_KEY, lines)
lines = appendTags(tags, nwKeyWords.TIME_KEY, lines)
lines = appendTags(tags, nwKeyWords.WORLD_KEY, lines)
lines = appendTags(tags, nwKeyWords.OBJECT_KEY, lines)
lines = appendTags(tags, nwKeyWords.ENTITY_KEY, lines)
lines = appendTags(tags, nwKeyWords.CUSTOM_KEY, lines)
text = ""
if lines:
refs = "<br>".join(lines)
text = f"<p>{refs}</p>"
if tooltip := (text + synopsis or self.tr("No meta data")):
QToolTip.showText(qPos, tooltip)
return
## ##
# Old Code # Old Code
## ##
@@ -747,48 +801,3 @@ class GuiNovelTree(NTreeView):
# return toolText, f"{refName}: {toolText}" # return toolText, f"{refName}: {toolText}"
# return "", "" # return "", ""
# def _popMetaBox(self, qPos: QPoint, tHandle: str, sTitle: str) -> None:
# """Show the novel meta data box."""
# logger.debug("Generating meta data tooltip for '%s:%s'", tHandle, sTitle)
# pIndex = SHARED.project.index
# novIdx = pIndex.getItemHeading(tHandle, sTitle)
# refTags = pIndex.getReferences(tHandle, sTitle)
# if not novIdx:
# return
# 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: dict, key: str, lines: list[str]) -> list[str]:
# """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
-1
View File
@@ -517,7 +517,6 @@ class GuiProjectTree(QTreeView):
def initSettings(self) -> None: def initSettings(self) -> None:
"""Set or update tree widget settings.""" """Set or update tree widget settings."""
# Scroll bars
if CONFIG.hideVScroll: if CONFIG.hideVScroll:
self.setVerticalScrollBarPolicy(QtScrollAlwaysOff) self.setVerticalScrollBarPolicy(QtScrollAlwaysOff)
else: else: