This commit is contained in:
Martin Rotter 2022-04-26 14:43:28 +02:00
parent cec08b4eb5
commit 4c0aee2ef4
2 changed files with 75 additions and 67 deletions

View file

@ -19,7 +19,9 @@
#include <QTimer> #include <QTimer>
TextBrowserViewer::TextBrowserViewer(QWidget* parent) TextBrowserViewer::TextBrowserViewer(QWidget* parent)
: QTextBrowser(parent), m_downloader(new Downloader(this)), m_document(new TextBrowserDocument(this)) { : QTextBrowser(parent), m_resourcesEnabled(false), m_resourceDownloader(new Downloader(this)),
m_placeholderImage(qApp->icons()->miscPixmap("image-placeholder")), m_downloader(new Downloader(this)),
m_document(new TextBrowserDocument(this)) {
setAutoFillBackground(true); setAutoFillBackground(true);
setFrameShape(QFrame::Shape::NoFrame); setFrameShape(QFrame::Shape::NoFrame);
setFrameShadow(QFrame::Shadow::Plain); setFrameShadow(QFrame::Shadow::Plain);
@ -27,16 +29,20 @@ TextBrowserViewer::TextBrowserViewer(QWidget* parent)
setOpenLinks(false); setOpenLinks(false);
viewport()->setAutoFillBackground(true); viewport()->setAutoFillBackground(true);
m_document.data()->setResourcesEnabled(qApp->settings() m_resourceTimer.setSingleShot(false);
->value(GROUP(Messages), SETTING(Messages::ShowResourcesInArticles)) m_resourceTimer.setInterval(300);
.toBool());
setResourcesEnabled(qApp->settings()->value(GROUP(Messages), SETTING(Messages::ShowResourcesInArticles)).toBool());
setDocument(m_document.data()); setDocument(m_document.data());
connect(m_document.data(), &TextBrowserDocument::reloadDocument, this, [this]() { connect(this, &TextBrowserViewer::reloadDocument, this, [this]() {
const auto scr = verticalScrollBarPosition();
setHtmlPrivate(html(), m_currentUrl); setHtmlPrivate(html(), m_currentUrl);
setVerticalScrollBarPosition(scr);
}); });
connect(&m_resourceTimer, &QTimer::timeout, this, &TextBrowserViewer::reloadHtmlDelayed);
connect(m_resourceDownloader.data(), &Downloader::completed, this, &TextBrowserViewer::resourceDownloaded);
connect(this, &QTextBrowser::anchorClicked, this, &TextBrowserViewer::onAnchorClicked); connect(this, &QTextBrowser::anchorClicked, this, &TextBrowserViewer::onAnchorClicked);
connect(this, QOverload<const QUrl&>::of(&QTextBrowser::highlighted), this, &TextBrowserViewer::linkMouseHighlighted); connect(this, QOverload<const QUrl&>::of(&QTextBrowser::highlighted), this, &TextBrowserViewer::linkMouseHighlighted);
} }
@ -48,6 +54,31 @@ QSize TextBrowserViewer::sizeHint() const {
return doc_size; return doc_size;
} }
QVariant TextBrowserViewer::loadOneResource(int type, const QUrl& name) {
if (type != QTextDocument::ResourceType::ImageResource) {
return {};
}
if (!m_resourcesEnabled) {
// Resources are not enabled.
return m_placeholderImage;
}
if (m_loadedResources.contains(name)) {
// Resources are enabled and we already have the resource.
return QImage::fromData(m_loadedResources.value(name));
}
else {
// Resources are not enabled and we need to download the resource.
if (!m_neededResources.contains(name) && m_resourceTimer.isActive()) {
m_neededResources.append(name);
m_resourceTimer.start();
}
return m_placeholderImage;
}
}
QPair<QString, QUrl> TextBrowserViewer::prepareHtmlForMessage(const QList<Message>& messages, QPair<QString, QUrl> TextBrowserViewer::prepareHtmlForMessage(const QList<Message>& messages,
RootItem* selected_item) const { RootItem* selected_item) const {
QString html; QString html;
@ -282,7 +313,7 @@ void TextBrowserViewer::contextMenuEvent(QContextMenuEvent* event) {
m_actionDownloadLink.reset(new QAction(qApp->icons()->fromTheme(QSL("download")), tr("Download"), this)); m_actionDownloadLink.reset(new QAction(qApp->icons()->fromTheme(QSL("download")), tr("Download"), this));
m_actionEnableResources.data()->setCheckable(true); m_actionEnableResources.data()->setCheckable(true);
m_actionEnableResources.data()->setChecked(m_document.data()->resourcesEnabled()); m_actionEnableResources.data()->setChecked(resourcesEnabled());
connect(m_actionOpenExternalBrowser.data(), connect(m_actionOpenExternalBrowser.data(),
&QAction::triggered, &QAction::triggered,
@ -353,7 +384,7 @@ void TextBrowserViewer::wheelEvent(QWheelEvent* event) {
void TextBrowserViewer::enableResources(bool enable) { void TextBrowserViewer::enableResources(bool enable) {
qApp->settings()->setValue(GROUP(Messages), Messages::ShowResourcesInArticles, enable); qApp->settings()->setValue(GROUP(Messages), Messages::ShowResourcesInArticles, enable);
m_document.data()->setResourcesEnabled(enable); setResourcesEnabled(enable);
} }
void TextBrowserViewer::openLinkInExternalBrowser() { void TextBrowserViewer::openLinkInExternalBrowser() {
@ -397,9 +428,9 @@ void TextBrowserViewer::onAnchorClicked(const QUrl& url) {
} }
void TextBrowserViewer::setHtml(const QString& html, const QUrl& base_url) { void TextBrowserViewer::setHtml(const QString& html, const QUrl& base_url) {
m_document.data()->m_resourceTimer.stop(); m_resourceTimer.stop();
m_document.data()->m_neededResources.clear(); m_neededResources.clear();
m_document.data()->m_resourceTimer.start(); m_resourceTimer.start();
setHtmlPrivate(html, base_url); setHtmlPrivate(html, base_url);
@ -424,43 +455,15 @@ void TextBrowserViewer::setHtmlPrivate(const QString& html, const QUrl& base_url
emit pageUrlChanged(base_url); emit pageUrlChanged(base_url);
} }
TextBrowserDocument::TextBrowserDocument(QObject* parent) TextBrowserDocument::TextBrowserDocument(TextBrowserViewer* parent) : QTextDocument(parent) {
: QTextDocument(parent), m_resourcesEnabled(false), m_resourceDownloader(new Downloader(this)), m_viewer = parent;
m_placeholderImage(qApp->icons()->miscPixmap("image-placeholder")) {
connect(&m_resourceTimer, &QTimer::timeout, this, &TextBrowserDocument::reloadHtmlDelayed);
connect(m_resourceDownloader.data(), &Downloader::completed, this, &TextBrowserDocument::resourceDownloaded);
m_resourceTimer.setSingleShot(false);
m_resourceTimer.setInterval(300);
} }
QVariant TextBrowserDocument::loadResource(int type, const QUrl& name) { QVariant TextBrowserDocument::loadResource(int type, const QUrl& name) {
if (type != QTextDocument::ResourceType::ImageResource) { return m_viewer->loadOneResource(type, name);
return {};
} }
if (!m_resourcesEnabled) { void TextBrowserViewer::reloadHtmlDelayed() {
// Resources are not enabled.
return m_placeholderImage;
}
if (m_loadedResources.contains(name)) {
// Resources are enabled and we already have the resource.
return QImage::fromData(m_loadedResources.value(name));
}
else {
// Resources are not enabled and we need to download the resource.
if (!m_neededResources.contains(name) && m_resourceTimer.isActive()) {
m_neededResources.append(name);
m_resourceTimer.start();
}
return m_placeholderImage;
}
}
void TextBrowserDocument::reloadHtmlDelayed() {
// Timer has elapsed, we do not wait for other resources, // Timer has elapsed, we do not wait for other resources,
// we download what we know about. // we download what we know about.
m_resourceTimer.stop(); m_resourceTimer.stop();
@ -470,7 +473,7 @@ void TextBrowserDocument::reloadHtmlDelayed() {
} }
} }
void TextBrowserDocument::downloadNextNeededResource() { void TextBrowserViewer::downloadNextNeededResource() {
if (m_neededResources.isEmpty()) { if (m_neededResources.isEmpty()) {
// Everything is downloaded. // Everything is downloaded.
emit reloadDocument(); emit reloadDocument();
@ -483,7 +486,7 @@ void TextBrowserDocument::downloadNextNeededResource() {
} }
} }
void TextBrowserDocument::resourceDownloaded(const QUrl& url, QNetworkReply::NetworkError status, QByteArray contents) { void TextBrowserViewer::resourceDownloaded(const QUrl& url, QNetworkReply::NetworkError status, QByteArray contents) {
if (status == QNetworkReply::NetworkError::NoError && !m_loadedResources.contains(url)) { if (status == QNetworkReply::NetworkError::NoError && !m_loadedResources.contains(url)) {
m_loadedResources.insert(url, contents); m_loadedResources.insert(url, contents);
} }
@ -491,10 +494,10 @@ void TextBrowserDocument::resourceDownloaded(const QUrl& url, QNetworkReply::Net
downloadNextNeededResource(); downloadNextNeededResource();
} }
bool TextBrowserDocument::resourcesEnabled() const { bool TextBrowserViewer::resourcesEnabled() const {
return m_resourcesEnabled; return m_resourcesEnabled;
} }
void TextBrowserDocument::setResourcesEnabled(bool enabled) { void TextBrowserViewer::setResourcesEnabled(bool enabled) {
m_resourcesEnabled = enabled; m_resourcesEnabled = enabled;
} }

View file

@ -19,36 +19,19 @@ class QResizeEvent;
class WebBrowser; class WebBrowser;
class Downloader; class Downloader;
class TextBrowserViewer;
class TextBrowserDocument : public QTextDocument { class TextBrowserDocument : public QTextDocument {
Q_OBJECT Q_OBJECT
friend class TextBrowserViewer;
public: public:
explicit TextBrowserDocument(QObject* parent = nullptr); explicit TextBrowserDocument(TextBrowserViewer* parent = nullptr);
bool resourcesEnabled() const;
void setResourcesEnabled(bool enabled);
protected: protected:
virtual QVariant loadResource(int type, const QUrl& name); virtual QVariant loadResource(int type, const QUrl& name);
signals:
void loadingProgress(int progress);
void reloadDocument();
private slots:
void reloadHtmlDelayed();
void downloadNextNeededResource();
void resourceDownloaded(const QUrl& url, QNetworkReply::NetworkError status, QByteArray contents = QByteArray());
private: private:
bool m_resourcesEnabled; QPointer<TextBrowserViewer> m_viewer;
QTimer m_resourceTimer;
QList<QUrl> m_neededResources;
QScopedPointer<Downloader> m_resourceDownloader;
QMap<QUrl, QByteArray> m_loadedResources;
QPixmap m_placeholderImage;
}; };
class TextBrowserViewer : public QTextBrowser, public WebViewer { class TextBrowserViewer : public QTextBrowser, public WebViewer {
@ -60,6 +43,9 @@ class TextBrowserViewer : public QTextBrowser, public WebViewer {
virtual QSize sizeHint() const; virtual QSize sizeHint() const;
public:
QVariant loadOneResource(int type, const QUrl& name);
public: public:
virtual void bindToBrowser(WebBrowser* browser); virtual void bindToBrowser(WebBrowser* browser);
virtual void findText(const QString& text, bool backwards); virtual void findText(const QString& text, bool backwards);
@ -86,6 +72,25 @@ class TextBrowserViewer : public QTextBrowser, public WebViewer {
void downloadLink(); void downloadLink();
void onAnchorClicked(const QUrl& url); void onAnchorClicked(const QUrl& url);
bool resourcesEnabled() const;
void setResourcesEnabled(bool enabled);
signals:
void reloadDocument();
private slots:
void reloadHtmlDelayed();
void downloadNextNeededResource();
void resourceDownloaded(const QUrl& url, QNetworkReply::NetworkError status, QByteArray contents = QByteArray());
private:
bool m_resourcesEnabled;
QTimer m_resourceTimer;
QList<QUrl> m_neededResources;
QScopedPointer<Downloader> m_resourceDownloader;
QMap<QUrl, QByteArray> m_loadedResources;
QPixmap m_placeholderImage;
signals: signals:
void pageTitleChanged(const QString& new_title); void pageTitleChanged(const QString& new_title);
void pageUrlChanged(const QUrl& url); void pageUrlChanged(const QUrl& url);