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,22 +1,22 @@
from typing import cast
from PySide6.QtCore import (
QAbstractItemModel,
QDir,
QFile,
QModelIndex,
QObject,
QPersistentModelIndex,
QPoint,
QPointF,
QRect,
QSize,
Qt,
QUrl,
Signal,
Slot,
)
)
from PySide6.QtGui import (
QMouseEvent,
QPalette,
QPainter,
QTextDocument,
)
from PySide6.QtNetwork import (
@@ -26,7 +26,7 @@ from PySide6.QtNetwork import (
)
from PySide6.QtWidgets import (
QAbstractItemView,
QSizePolicy,
QStyle,
QStyledItemDelegate,
QStyleOptionViewItem,
QTableView,
@@ -34,7 +34,7 @@ from PySide6.QtWidgets import (
QWidget,
)
from docketModel import docketModel
from lib.utils import QStyleOptionViewItemInit
from pdfView import PDFViewer
@@ -48,41 +48,32 @@ class docketEntryDelegate(QStyledItemDelegate):
def sizeHint(
self,
_: QStyleOptionViewItem,
option: QStyleOptionViewItem,
index: QModelIndex | QPersistentModelIndex,
) -> QSize:
widget = self.view.indexWidget(index)
return widget.sizeHint()
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()
options = cast(QStyleOptionViewItemInit, option)
self.initStyleOption(options, index)
doc = QTextDocument()
doc.setPlainText(self.document().toPlainText())
doc.setTextWidth(size.width())
docSize = doc.size()
return QSize(size.width(), int(docSize.height()))
doc.setHtml(options.text)
doc.setTextWidth(options.rect.width())
return QSize(int(doc.idealWidth()), int(doc.size().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):
@@ -99,12 +90,6 @@ class docketTableView(QTableView):
self.manager.finished.connect(self.getDone)
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
def getDone(self, reply: QNetworkReply) -> None:
dest = QFile("." + reply.url().path())
@@ -136,16 +121,33 @@ class docketTableView(QTableView):
self.manager.get(QNetworkRequest(url))
return
def modelReset(self) -> None:
model = self.model()
red = QPalette()
red.setColor(QPalette.ColorRole.Base, Qt.GlobalColor.red)
for row in range(0, model.rowCount()):
index = model.index(row, docketModel.ColumnNames.text)
widget = docketEntry()
widget.setHtml(model.data(index, Qt.ItemDataRole.DisplayRole))
widget.setAutoFillBackground(False)
widget.setReadOnly(True)
widget.setPalette(red)
self.setIndexWidget(index, widget)
def mousePressEvent(self, event: QMouseEvent) -> None:
#
# The mouse has been pressed somewere in our rect. We need to translate that to a click
# within the cell with the document. This will allow the document to find anchors.
#
index = self.indexAt(event.pos())
if not index.isValid():
return
if index.column() != 1:
return
doc = QTextDocument()
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