an attempt to display text in a better way with QTextDocument + QTextBrowser

This commit is contained in:
Blue 2022-04-27 01:17:53 +03:00
parent 51ac1ac709
commit d86e2c28a0
Signed by untrusted user: blue
GPG key ID: 9B203B252A63EE38
7 changed files with 88 additions and 338 deletions

View file

@ -22,6 +22,7 @@
#include <QApplication>
#include <QMouseEvent>
#include <QAbstractItemView>
#include <QtMath>
#include "messagedelegate.h"
#include "messagefeed.h"
@ -42,7 +43,7 @@ MessageDelegate::MessageDelegate(QObject* parent):
nickFont(),
dateFont(),
bodyMetrics(bodyFont),
bodyMeter(),
bodyRenderer(new QTextDocument()),
nickMetrics(nickFont),
dateMetrics(dateFont),
buttonHeight(0),
@ -52,11 +53,13 @@ MessageDelegate::MessageDelegate(QObject* parent):
bars(new std::map<QString, QProgressBar*>()),
statusIcons(new std::map<QString, QLabel*>()),
pencilIcons(new std::map<QString, QLabel*>()),
bodies(new std::map<QString, QLabel*>()),
bodies(new std::map<QString, QTextBrowser*>()),
previews(new std::map<QString, Preview*>()),
idsToKeep(new std::set<QString>()),
clearingWidgets(false)
{
bodyRenderer->setDocumentMargin(0);
QPushButton btn(QCoreApplication::translate("MessageLine", "Download"));
buttonHeight = btn.sizeHint().height();
buttonWidth = btn.sizeHint().width();
@ -83,7 +86,7 @@ MessageDelegate::~MessageDelegate()
delete pair.second;
}
for (const std::pair<const QString, QLabel*>& pair: *bodies){
for (const std::pair<const QString, QTextBrowser*>& pair: *bodies){
delete pair.second;
}
@ -98,6 +101,7 @@ MessageDelegate::~MessageDelegate()
delete bars;
delete bodies;
delete previews;
delete bodyRenderer;
}
void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
@ -124,8 +128,6 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio
opt.displayAlignment = Qt::AlignRight | Qt::AlignTop;
}
QSize bodySize = bodyMeter.boundingSize(data.text, opt.rect.size());
QRect rect;
if (ntds) {
painter->setFont(nickFont);
@ -168,15 +170,7 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio
painter->restore();
QWidget* vp = static_cast<QWidget*>(painter->device());
if (data.text.size() > 0) {
QLabel* body = getBody(data);
body->setParent(vp);
body->setMinimumSize(bodySize);
body->setMaximumSize(bodySize);
body->move(opt.rect.left(), opt.rect.y());
body->show();
opt.rect.adjust(0, bodySize.height() + textMargin, 0, 0);
}
paintBody(data, painter, opt);
painter->setFont(dateFont);
QColor q = painter->pen().color();
QString dateString = data.date.toLocalTime().toString("hh:mm");
@ -304,7 +298,12 @@ QSize MessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel
Models::FeedItem data = qvariant_cast<Models::FeedItem>(vi);
QSize messageSize(0, 0);
if (data.text.size() > 0) {
messageSize = bodyMeter.boundingSize(data.text, messageRect.size());
bodyRenderer->setPlainText(data.text);
bodyRenderer->setTextWidth(messageRect.size().width());
QSizeF size = bodyRenderer->size();
size.setWidth(bodyRenderer->idealWidth());
messageSize = QSize(qCeil(size.width()), qCeil(size.height()));
messageSize.rheight() += textMargin;
}
@ -393,7 +392,7 @@ void MessageDelegate::initializeFonts(const QFont& font)
nickMetrics = QFontMetrics(nickFont);
dateMetrics = QFontMetrics(dateFont);
bodyMeter.initializeFonts(bodyFont);
bodyRenderer->setDefaultFont(bodyFont);
Preview::initializeFont(bodyFont);
}
@ -573,34 +572,36 @@ QLabel * MessageDelegate::getPencilIcon(const Models::FeedItem& data) const
return result;
}
QLabel * MessageDelegate::getBody(const Models::FeedItem& data) const
QTextBrowser * MessageDelegate::getBody(const Models::FeedItem& data) const
{
std::map<QString, QLabel*>::const_iterator itr = bodies->find(data.id);
QLabel* result = 0;
std::map<QString, QTextBrowser*>::const_iterator itr = bodies->find(data.id);
QTextBrowser* result = 0;
if (itr != bodies->end()) {
result = itr->second;
} else {
result = new QLabel();
result = new QTextBrowser();
result->setFont(bodyFont);
result->setContextMenuPolicy(Qt::NoContextMenu);
result->setWordWrap(true);
result->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
result->setContentsMargins(0, 0, 0, 0);
//result->viewport()->setAutoFillBackground(false);
result->document()->setDocumentMargin(0);
result->setFrameStyle(0);
result->setLineWidth(0);
//result->setAutoFillBackground(false);
//->setWordWrap(true);
result->setOpenExternalLinks(true);
//result->setTextInteractionFlags(result->textInteractionFlags() | Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
result->setOpenExternalLinks(true);
result->setTextInteractionFlags(result->textInteractionFlags() | Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
bodies->insert(std::make_pair(data.id, result));
}
result->setText(Shared::processMessageBody(data.text));
result->setHtml(Shared::processMessageBody(data.text));
return result;
}
void MessageDelegate::beginClearWidgets()
{
idsToKeep->clear();
clearingWidgets = true;
}
template <typename T>
void removeElements(std::map<QString, T*>* elements, std::set<QString>* idsToKeep) {
std::set<QString> toRemove;
@ -615,6 +616,51 @@ void removeElements(std::map<QString, T*>* elements, std::set<QString>* idsToKee
}
}
int MessageDelegate::paintBody(const Models::FeedItem& data, QPainter* painter, QStyleOptionViewItem& option) const
{
if (data.text.size() > 0) {
bodyRenderer->setHtml(Shared::processMessageBody(data.text));
bodyRenderer->setTextWidth(option.rect.size().width());
painter->save();
painter->translate(option.rect.topLeft());
bodyRenderer->drawContents(painter);
painter->restore();
QSize bodySize(qCeil(bodyRenderer->idealWidth()), qCeil(bodyRenderer->size().height()));
QTextBrowser* editor = nullptr;
if (option.state.testFlag(QStyle::State_MouseOver)) {
std::set<QString> ids({data.id});
removeElements(bodies, &ids);
editor = getBody(data);
editor->setParent(static_cast<QWidget*>(painter->device()));
} else {
std::map<QString, QTextBrowser*>::const_iterator itr = bodies->find(data.id);
if (itr != bodies->end()) {
editor = itr->second;
}
}
if (editor != nullptr) {
editor->setMinimumSize(bodySize);
editor->setMaximumSize(bodySize);
editor->move(option.rect.left(), option.rect.y());
editor->show();
}
option.rect.adjust(0, bodySize.height() + textMargin, 0, 0);
return bodySize.width();
}
return 0;
}
void MessageDelegate::beginClearWidgets()
{
idsToKeep->clear();
clearingWidgets = true;
}
void MessageDelegate::endClearWidgets()
{
if (clearingWidgets) {