some fixes, more options for litebrowser

This commit is contained in:
Martin Rotter 2022-04-01 13:16:36 +02:00
parent a8f7b3eabf
commit ba6c81ceb7
14 changed files with 157 additions and 147 deletions

View File

@ -71,6 +71,7 @@
<file>./graphics/Breeze/mimetypes/64/text-html.svg</file>
<file>./graphics/Breeze/places/96/user-trash.svg</file>
<file>./graphics/Breeze/actions/22/view-fullscreen.svg</file>
<file>./graphics/Breeze/actions/22/viewimage.svg</file>
<file>./graphics/Breeze/actions/32/view-list-details.svg</file>
<file>./graphics/Breeze/actions/32/view-refresh.svg</file>
<file>./graphics/Breeze/actions/22/view-restore.svg</file>
@ -147,6 +148,7 @@
<file>./graphics/Breeze Dark/mimetypes/64/text-html.svg</file>
<file>./graphics/Breeze Dark/places/96/user-trash.svg</file>
<file>./graphics/Breeze Dark/actions/22/view-fullscreen.svg</file>
<file>./graphics/Breeze Dark/actions/22/viewimage.svg</file>
<file>./graphics/Breeze Dark/actions/32/view-list-details.svg</file>
<file>./graphics/Breeze Dark/actions/32/view-refresh.svg</file>
<file>./graphics/Breeze Dark/actions/22/view-restore.svg</file>
@ -303,6 +305,7 @@
<file>./graphics/Numix/22/actions/up.svg</file>
<file>./graphics/Numix/22/places/user-trash.svg</file>
<file>./graphics/Numix/22/actions/view-fullscreen.svg</file>
<file>./graphics/Numix/22/actions/viewimage.svg</file>
<file>./graphics/Numix/22/actions/view-list-details.svg</file>
<file>./graphics/Numix/22/actions/view-refresh.svg</file>
<file>./graphics/Numix/22/actions/view-restore.svg</file>

View File

@ -68,6 +68,18 @@ MessagePreviewer::MessagePreviewer(QWidget* parent)
clear();
}
MessagePreviewer::~MessagePreviewer() {
if (m_viewerLayout->count() > 1) {
// Make sure that previewer does not delete any custom article
// viewers as those are responsibility to free by their accounts.
auto* wdg = m_viewerLayout->widget(1);
wdg->setParent(nullptr);
m_viewerLayout->removeWidget(wdg);
}
}
void MessagePreviewer::reloadFontSettings() {
m_msgBrowser->reloadFontSettings();
}

View File

@ -34,6 +34,7 @@ class MessagePreviewer : public QWidget {
public:
explicit MessagePreviewer(QWidget* parent = nullptr);
virtual ~MessagePreviewer();
void reloadFontSettings();

View File

@ -23,10 +23,11 @@
#include <QTimer>
#include <QWheelEvent>
LiteHtmlViewer::LiteHtmlViewer(QWidget* parent) : QLiteHtmlWidget(parent), m_downloader(new Downloader(this)) {
LiteHtmlViewer::LiteHtmlViewer(QWidget* parent) : QLiteHtmlWidget(parent), m_downloader(new Downloader(this)),
m_reloadingWithImages(false) {
setResourceHandler([this](const QUrl& url) {
emit loadProgress(-1);
return handleResource(url);
return m_reloadingWithImages ? handleResource(url) : QByteArray{};
});
setFrameShape(QFrame::Shape::NoFrame);
@ -131,68 +132,9 @@ void LiteHtmlViewer::clear() {
}
void LiteHtmlViewer::loadMessages(const QList<Message>& messages, RootItem* root) {
Skin skin = qApp->skins()->currentSkin();
QString messages_layout;
QString single_message_layout = skin.m_layoutMarkup;
auto html_messages = qApp->skins()->generateHtmlOfArticles(messages, root);
for (const Message& message : messages) {
QString enclosures;
QString enclosure_images;
for (const Enclosure& enclosure : message.m_enclosures) {
QString enc_url = QUrl::fromPercentEncoding(enclosure.m_url.toUtf8());
enclosures += skin.m_enclosureMarkup.arg(enc_url,
QSL("&#129527;"),
enclosure.m_mimeType);
if (enclosure.m_mimeType.startsWith(QSL("image/")) &&
qApp->settings()->value(GROUP(Messages), SETTING(Messages::DisplayEnclosuresInMessage)).toBool()) {
// Add thumbnail image.
enclosure_images += skin.m_enclosureImageMarkup.arg(
enclosure.m_url,
enclosure.m_mimeType,
qApp->settings()->value(GROUP(Messages), SETTING(Messages::MessageHeadImageHeight)).toString());
}
}
QString msg_date = qApp->settings()->value(GROUP(Messages), SETTING(Messages::UseCustomDate)).toBool()
? message.m_created.toLocalTime().toString(qApp->settings()->value(GROUP(Messages),
SETTING(Messages::CustomDateFormat)).toString())
: qApp->localization()->loadedLocale().toString(message.m_created.toLocalTime(),
QLocale::FormatType::ShortFormat);
messages_layout.append(single_message_layout
.arg(message.m_title,
tr("Written by ") + (message.m_author.isEmpty() ?
tr("unknown author") :
message.m_author),
message.m_url,
message.m_contents,
msg_date,
enclosures,
enclosure_images,
QString::number(message.m_id)));
}
QString msg_contents = skin.m_layoutMarkupWrapper.arg(messages.size() == 1
? messages.at(0).m_title
: tr("Newspaper view"),
messages_layout);
auto* feed = root->getParentServiceRoot()->getItemFromSubTree([messages](const RootItem* it) {
return it->kind() == RootItem::Kind::Feed && it->customId() == messages.at(0).m_feedId;
})->toFeed();
QString base_url;
if (feed != nullptr) {
QUrl url(NetworkFactory::sanitizeUrl(feed->source()));
if (url.isValid()) {
base_url = url.scheme() + QSL("://") + url.host();
}
}
setHtml(msg_contents, QUrl::fromUserInput(base_url));
setHtml(html_messages.first, html_messages.second);
emit loadFinished(true);
}
@ -261,26 +203,46 @@ void LiteHtmlViewer::onLinkClicked(const QUrl& link) {
}
}
void LiteHtmlViewer::reloadPageWithImages() {
m_reloadingWithImages = true;
auto scroll = verticalScrollBar()->value();
setHtml(html(), url());
if (scroll > 0) {
verticalScrollBar()->setValue(scroll);
}
m_reloadingWithImages = false;
}
void LiteHtmlViewer::showContextMenu(const QPoint& pos, const QUrl& url) {
if (m_contextMenu.isNull()) {
m_contextMenu.reset(new QMenu("Context menu for web browser", this));
m_actionCopyUrl.reset(m_contextMenu->addAction(qApp->icons()->fromTheme(QSL("edit-copy")),
tr("Copy URL"),
[url]() {
QGuiApplication::clipboard()->setText(url.toString(), QClipboard::Mode::Clipboard);
}));
m_actionCopyUrl.reset(new QAction(qApp->icons()->fromTheme(QSL("edit-copy")),
tr("Copy URL"),
this));
m_actionCopyText.reset(m_contextMenu->addAction(qApp->icons()->fromTheme(QSL("edit-copy")),
tr("Copy selection"),
[this]() {
connect(m_actionCopyUrl.data(), &QAction::triggered, this, [url]() {
QGuiApplication::clipboard()->setText(url.toString(), QClipboard::Mode::Clipboard);
});
m_actionCopyText.reset(new QAction(qApp->icons()->fromTheme(QSL("edit-copy")),
tr("Copy selection"),
this));
connect(m_actionCopyText.data(), &QAction::triggered, this, [this]() {
QGuiApplication::clipboard()->setText(QLiteHtmlWidget::selectedText(), QClipboard::Mode::Clipboard);
}));
});
// Add option to open link in external viewe
m_actionOpenLinkExternally.reset(m_contextMenu->addAction(qApp->icons()->fromTheme(QSL("document-open")),
tr("Open link in external browser"),
[url]() {
m_actionOpenLinkExternally.reset(new QAction(qApp->icons()->fromTheme(QSL("document-open")),
tr("Open link in external browser"),
this));
connect(m_actionOpenLinkExternally.data(), &QAction::triggered, this, [url]() {
qApp->web()->openUrlInExternalBrowser(url.toString());
if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::BringAppToFrontAfterMessageOpenedExternally)).toBool()) {
@ -288,19 +250,24 @@ void LiteHtmlViewer::showContextMenu(const QPoint& pos, const QUrl& url) {
qApp->mainForm()->display();
});
}
}));
}
else {
m_contextMenu->clear();
});
m_actionReloadWithImages.reset(new QAction(qApp->icons()->fromTheme(QSL("viewimage"), QSL("view-refresh")),
tr("Reload with images"),
this));
connect(m_actionReloadWithImages.data(), &QAction::triggered, this, &LiteHtmlViewer::reloadPageWithImages);
}
m_actionCopyUrl->setEnabled(url.isValid());
m_actionCopyText->setEnabled(!QLiteHtmlWidget::selectedText().isEmpty());
m_actionOpenLinkExternally->setEnabled(url.isValid());
m_contextMenu->clear();
m_contextMenu->addActions({ m_actionCopyUrl.data(),
m_actionCopyText.data(),
m_actionOpenLinkExternally.data() });
m_actionOpenLinkExternally.data(),
m_actionReloadWithImages.data() });
if (url.isValid()) {
QFileIconProvider icon_provider;

View File

@ -40,6 +40,7 @@ class LiteHtmlViewer : public QLiteHtmlWidget, public WebViewer {
private slots:
void selectedTextChanged(bool available);
void onLinkClicked(const QUrl& link);
void reloadPageWithImages();
void showContextMenu(const QPoint& pos, const QUrl& url);
signals:
@ -63,6 +64,8 @@ class LiteHtmlViewer : public QLiteHtmlWidget, public WebViewer {
QScopedPointer<QAction> m_actionCopyUrl;
QScopedPointer<QAction> m_actionCopyText;
QScopedPointer<QAction> m_actionOpenLinkExternally;
QScopedPointer<QAction> m_actionReloadWithImages;
bool m_reloadingWithImages;
};
#endif // LITEHTMLVIEWER_H

View File

@ -53,75 +53,16 @@ WebEnginePage* WebEngineViewer::page() const {
}
void WebEngineViewer::loadMessages(const QList<Message>& messages, RootItem* root) {
Skin skin = qApp->skins()->currentSkin();
QString messages_layout;
QString single_message_layout = skin.m_layoutMarkup;
for (const Message& message : messages) {
QString enclosures;
QString enclosure_images;
for (const Enclosure& enclosure : message.m_enclosures) {
QString enc_url = QUrl::fromPercentEncoding(enclosure.m_url.toUtf8());
enclosures += skin.m_enclosureMarkup.arg(enc_url,
QSL("&#129527;"),
enclosure.m_mimeType);
if (enclosure.m_mimeType.startsWith(QSL("image/")) &&
qApp->settings()->value(GROUP(Messages), SETTING(Messages::DisplayEnclosuresInMessage)).toBool()) {
// Add thumbnail image.
enclosure_images += skin.m_enclosureImageMarkup.arg(
enclosure.m_url,
enclosure.m_mimeType,
qApp->settings()->value(GROUP(Messages), SETTING(Messages::MessageHeadImageHeight)).toString());
}
}
QString msg_date = qApp->settings()->value(GROUP(Messages), SETTING(Messages::UseCustomDate)).toBool()
? message.m_created.toLocalTime().toString(qApp->settings()->value(GROUP(Messages),
SETTING(Messages::CustomDateFormat)).toString())
: qApp->localization()->loadedLocale().toString(message.m_created.toLocalTime(),
QLocale::FormatType::ShortFormat);
messages_layout.append(single_message_layout
.arg(message.m_title,
tr("Written by ") + (message.m_author.isEmpty() ?
tr("unknown author") :
message.m_author),
message.m_url,
message.m_contents,
msg_date,
enclosures,
enclosure_images,
QString::number(message.m_id)));
}
m_messageContents = skin.m_layoutMarkupWrapper.arg(messages.size() == 1
? messages.at(0).m_title
: tr("Newspaper view"),
messages_layout);
auto html_messages = qApp->skins()->generateHtmlOfArticles(messages, root);
m_root = root;
auto* feed = root->getParentServiceRoot()->getItemFromSubTree([messages](const RootItem* it) {
return it->kind() == RootItem::Kind::Feed && it->customId() == messages.at(0).m_feedId;
})->toFeed();
m_messageBaseUrl = QString();
if (feed != nullptr) {
QUrl url(NetworkFactory::sanitizeUrl(feed->source()));
if (url.isValid()) {
m_messageBaseUrl = url.scheme() + QSL("://") + url.host();
}
}
m_messageContents = html_messages.first;
m_messageBaseUrl = html_messages.second;
bool previously_enabled = isEnabled();
setEnabled(false);
setHtml(m_messageContents, m_messageBaseUrl /*, QUrl::fromUserInput(INTERNAL_URL_MESSAGE)*/);
setHtml(m_messageContents, m_messageBaseUrl);
setEnabled(previously_enabled);
page()->runJavaScript(QSL("window.scrollTo(0, 0);"));

View File

@ -58,7 +58,7 @@ class WebEngineViewer : public QWebEngineView, public WebViewer {
private:
WebBrowser* m_browser;
RootItem* m_root;
QString m_messageBaseUrl;
QUrl m_messageBaseUrl;
QString m_messageContents;
};

View File

@ -4,6 +4,8 @@
#include "exceptions/ioexception.h"
#include "miscellaneous/application.h"
#include "network-web/networkfactory.h"
#include "services/abstract/rootitem.h"
#include <QDir>
#include <QDomDocument>
@ -129,6 +131,71 @@ QString SkinFactory::adBlockedPage(const QString& url, const QString& filter) {
return currentSkin().m_layoutMarkupWrapper.arg(tr("This page was blocked by AdBlock"), adblocked);
}
QPair<QString, QUrl> SkinFactory::generateHtmlOfArticles(const QList<Message>& messages, RootItem* root) const {
Skin skin = currentSkin();
QString messages_layout;
QString single_message_layout = skin.m_layoutMarkup;
for (const Message& message : messages) {
QString enclosures;
QString enclosure_images;
for (const Enclosure& enclosure : message.m_enclosures) {
QString enc_url = QUrl::fromPercentEncoding(enclosure.m_url.toUtf8());
enclosures += skin.m_enclosureMarkup.arg(enc_url,
QSL("&#129527;"),
enclosure.m_mimeType);
if (enclosure.m_mimeType.startsWith(QSL("image/")) &&
qApp->settings()->value(GROUP(Messages), SETTING(Messages::DisplayEnclosuresInMessage)).toBool()) {
// Add thumbnail image.
enclosure_images += skin.m_enclosureImageMarkup.arg(
enclosure.m_url,
enclosure.m_mimeType,
qApp->settings()->value(GROUP(Messages), SETTING(Messages::MessageHeadImageHeight)).toString());
}
}
QString msg_date = qApp->settings()->value(GROUP(Messages), SETTING(Messages::UseCustomDate)).toBool()
? message.m_created.toLocalTime().toString(qApp->settings()->value(GROUP(Messages),
SETTING(Messages::CustomDateFormat)).toString())
: qApp->localization()->loadedLocale().toString(message.m_created.toLocalTime(),
QLocale::FormatType::ShortFormat);
messages_layout.append(single_message_layout
.arg(message.m_title,
tr("Written by ") + (message.m_author.isEmpty() ?
tr("unknown author") :
message.m_author),
message.m_url,
message.m_contents,
msg_date,
enclosures,
enclosure_images,
QString::number(message.m_id)));
}
QString msg_contents = skin.m_layoutMarkupWrapper.arg(messages.size() == 1
? messages.at(0).m_title
: tr("Newspaper view"),
messages_layout);
auto* feed = root->getParentServiceRoot()->getItemFromSubTree([messages](const RootItem* it) {
return it->kind() == RootItem::Kind::Feed && it->customId() == messages.at(0).m_feedId;
})->toFeed();
QString base_url;
if (feed != nullptr) {
QUrl url(NetworkFactory::sanitizeUrl(feed->source()));
if (url.isValid()) {
base_url = url.scheme() + QSL("://") + url.host();
}
}
return { msg_contents, base_url };
}
Skin SkinFactory::skinInfo(const QString& skin_name, bool* ok) const {
Skin skin;
const QStringList skins_root_folders = {

View File

@ -5,6 +5,8 @@
#include <QObject>
#include "core/message.h"
#include <QColor>
#include <QHash>
#include <QMetaType>
@ -12,6 +14,8 @@
#include <QStringList>
#include <QVariant>
class RootItem;
class SkinEnums : public QObject {
Q_OBJECT
@ -82,6 +86,8 @@ class RSSGUARD_DLLSPEC SkinFactory : public QObject {
QString adBlockedPage(const QString& url, const QString& filter);
QPair<QString, QUrl> generateHtmlOfArticles(const QList<Message>& messages, RootItem* root) const;
// Gets skin about a particular skin.
Skin skinInfo(const QString& skin_name, bool* ok = nullptr) const;

View File

@ -12,6 +12,8 @@
CacheForServiceRoot::CacheForServiceRoot() : m_uniqueId(NO_PARENT_CATEGORY), m_cacheSaveMutex(new QMutex()) {}
CacheForServiceRoot::~CacheForServiceRoot() {}
void CacheForServiceRoot::addLabelsAssignmentsToCache(const QStringList& ids_of_messages,
const QString& lbl_custom_id,
bool assign) {

View File

@ -20,6 +20,7 @@ struct CacheSnapshot {
class CacheForServiceRoot {
public:
explicit CacheForServiceRoot();
virtual ~CacheForServiceRoot();
virtual void saveAllCachedData(bool ignore_errors) = 0;

View File

@ -440,7 +440,7 @@ void ServiceRoot::syncIn() {
QIcon original_icon = icon();
setIcon(qApp->icons()->fromTheme(QSL("view-refresh")));
itemChanged(QList<RootItem*>() << this);
itemChanged({ this });
RootItem* new_tree = obtainNewTreeForSyncIn();
if (new_tree != nullptr) {

View File

@ -25,6 +25,12 @@ GmailServiceRoot::GmailServiceRoot(RootItem* parent)
setIcon(GmailEntryPoint().icon());
}
GmailServiceRoot::~GmailServiceRoot() {
if (!m_emailPreview.isNull()) {
m_emailPreview->deleteLater();
}
}
void GmailServiceRoot::updateTitle() {
setTitle(TextFactory::extractUsernameFromEmail(m_network->username()) + QSL(" (Gmail)"));
}
@ -100,7 +106,7 @@ bool GmailServiceRoot::wantsBaggedIdsOfExistingMessages() const {
CustomMessagePreviewer* GmailServiceRoot::customMessagePreviewer() {
if (m_emailPreview.isNull()) {
m_emailPreview.reset(new EmailPreviewer());
m_emailPreview = new EmailPreviewer();
}
return m_emailPreview.data();

View File

@ -15,6 +15,7 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot {
public:
explicit GmailServiceRoot(RootItem* parent = nullptr);
virtual ~GmailServiceRoot();
void setNetwork(GmailNetworkFactory* network);
GmailNetworkFactory* network() const;
@ -49,7 +50,7 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot {
void updateTitle();
private:
QScopedPointer<EmailPreviewer> m_emailPreview;
QPointer<EmailPreviewer> m_emailPreview;
GmailNetworkFactory* m_network;
QAction* m_actionReply;
Message m_replyToMessage;