Switch from DocketEntry widget to ItemDelegate.

We were using a subclassed QTextEdit widget so that we could capture
clicks on anchors.

Moving to a delegate removed the widget per row issue.  Unfortunately,
there was no more click on anchor.

Adding a mouseEvent() to the TableView allowed us to translate raw
mouse presses to anchor triggers.

Fixes: #18
This commit is contained in:
Christopher T. Johnson
2025-02-27 13:40:28 -05:00
parent db4716b21b
commit 69fa955be1

View File

@@ -1,13 +1,13 @@
from typing import cast from typing import cast
from PySide6.QtCore import ( from PySide6.QtCore import (
QAbstractItemModel,
QDir, QDir,
QFile, QFile,
QModelIndex, QModelIndex,
QObject,
QPersistentModelIndex, QPersistentModelIndex,
QPoint, QPoint,
QPointF,
QRect,
QSize, QSize,
Qt, Qt,
QUrl, QUrl,
@@ -16,7 +16,7 @@ from PySide6.QtCore import (
) )
from PySide6.QtGui import ( from PySide6.QtGui import (
QMouseEvent, QMouseEvent,
QPalette, QPainter,
QTextDocument, QTextDocument,
) )
from PySide6.QtNetwork import ( from PySide6.QtNetwork import (
@@ -26,7 +26,7 @@ from PySide6.QtNetwork import (
) )
from PySide6.QtWidgets import ( from PySide6.QtWidgets import (
QAbstractItemView, QAbstractItemView,
QSizePolicy, QStyle,
QStyledItemDelegate, QStyledItemDelegate,
QStyleOptionViewItem, QStyleOptionViewItem,
QTableView, QTableView,
@@ -34,7 +34,7 @@ from PySide6.QtWidgets import (
QWidget, QWidget,
) )
from docketModel import docketModel from lib.utils import QStyleOptionViewItemInit
from pdfView import PDFViewer from pdfView import PDFViewer
@@ -48,41 +48,32 @@ class docketEntryDelegate(QStyledItemDelegate):
def sizeHint( def sizeHint(
self, self,
_: QStyleOptionViewItem, option: QStyleOptionViewItem,
index: QModelIndex | QPersistentModelIndex, index: QModelIndex | QPersistentModelIndex,
) -> QSize: ) -> QSize:
widget = self.view.indexWidget(index) options = cast(QStyleOptionViewItemInit, option)
return widget.sizeHint() self.initStyleOption(options, index)
class docketEntry(QTextEdit):
def __init__(self, parent: QWidget | None = None) -> None:
super(docketEntry, self).__init__(parent)
self.setSizePolicy(
QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed
)
return
def mousePressEvent(self, e: QMouseEvent) -> None:
super().mousePressEvent(e)
anchor = self.anchorAt(e.pos())
if anchor:
obj = cast(QObject, self)
while not isinstance(obj, docketTableView) and obj is not None:
obj = obj.parent()
assert obj is not None
index = obj.indexAt(obj.mapFromGlobal(self.mapToGlobal(e.pos())))
obj.anchorSignal.emit(index, anchor)
return
def sizeHint(self) -> QSize:
size = self.size()
doc = QTextDocument() doc = QTextDocument()
doc.setPlainText(self.document().toPlainText()) doc.setHtml(options.text)
doc.setTextWidth(size.width()) doc.setTextWidth(options.rect.width())
docSize = doc.size() return QSize(int(doc.idealWidth()), int(doc.size().height()))
return QSize(size.width(), int(docSize.height()))
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex | QPersistentModelIndex) -> None:
options = cast(QStyleOptionViewItemInit, option)
self.initStyleOption(options, index)
painter.save()
doc = QTextDocument()
doc.setHtml(options.text)
doc.setTextWidth(options.rect.width())
options.text = ''
options.widget.style().drawControl(QStyle.ControlElement.CE_ItemViewItem, options, painter)
painter.translate(options.rect.left(), options.rect.top())
clip = QRect(0,0, options.rect.width(), options.rect.height())
doc.drawContents(painter, clip)
painter.restore()
return
class docketTableView(QTableView): class docketTableView(QTableView):
@@ -99,12 +90,6 @@ class docketTableView(QTableView):
self.manager.finished.connect(self.getDone) self.manager.finished.connect(self.getDone)
return return
def setModel(self, model: QAbstractItemModel | None) -> None:
assert model is not None
super().setModel(model)
self.model().modelReset.connect(self.modelReset)
return
@Slot(QNetworkReply) # type: ignore @Slot(QNetworkReply) # type: ignore
def getDone(self, reply: QNetworkReply) -> None: def getDone(self, reply: QNetworkReply) -> None:
dest = QFile("." + reply.url().path()) dest = QFile("." + reply.url().path())
@@ -136,16 +121,33 @@ class docketTableView(QTableView):
self.manager.get(QNetworkRequest(url)) self.manager.get(QNetworkRequest(url))
return return
def modelReset(self) -> None: def mousePressEvent(self, event: QMouseEvent) -> None:
model = self.model() #
red = QPalette() # The mouse has been pressed somewere in our rect. We need to translate that to a click
red.setColor(QPalette.ColorRole.Base, Qt.GlobalColor.red) # within the cell with the document. This will allow the document to find anchors.
for row in range(0, model.rowCount()): #
index = model.index(row, docketModel.ColumnNames.text) index = self.indexAt(event.pos())
widget = docketEntry() if not index.isValid():
widget.setHtml(model.data(index, Qt.ItemDataRole.DisplayRole)) return
widget.setAutoFillBackground(False) if index.column() != 1:
widget.setReadOnly(True) return
widget.setPalette(red) doc = QTextDocument()
self.setIndexWidget(index, widget) doc.setHtml(index.data(Qt.ItemDataRole.DisplayRole))
doc.setTextWidth(self.columnWidth(index.column()))
#
# We need to map our click position to a position within the cell.
#
pos = event.position()
new_pos = QPointF(pos.x() - self.horizontalScrollBar().value(),
pos.y() - self.verticalScrollBar().value())
rowHeight = 0
for row in range(0, index.row()):
rowHeight += self.rowHeight(row)
cell_pos = QPointF(new_pos.x() - self.columnWidth(0),
new_pos.y() - rowHeight)
te = QTextEdit()
te.setDocument(doc)
anchor = te.anchorAt(cell_pos.toPoint())
if anchor:
self.anchorSignal.emit(index,anchor)
return return