From 69fa955be1060734a0adfcde1e3311d51ddcdf2b Mon Sep 17 00:00:00 2001 From: "Christopher T. Johnson" Date: Thu, 27 Feb 2025 13:40:28 -0500 Subject: [PATCH] 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 --- dockettableview.py | 112 +++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/dockettableview.py b/dockettableview.py index 5550727..deddfb4 100644 --- a/dockettableview.py +++ b/dockettableview.py @@ -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,42 +48,33 @@ 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): manager: QNetworkAccessManager @@ -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