Messagelib

webenginepage.cpp
1/*
2 SPDX-FileCopyrightText: 2016-2024 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "webenginepage.h"
8#include "webenginemanagescript.h"
9#include "webhittest.h"
10
11#include <KLocalizedString>
12
13#include <KColorScheme>
14#include <QEventLoop>
15#include <QFileDialog>
16#include <QGuiApplication>
17#include <QPointer>
18#include <QPrinter>
19#include <QTimer>
20#include <QWebEngineDownloadRequest>
21#include <QWebEngineProfile>
22#include <QWebEngineScriptCollection>
23#include <QWebEngineView>
24
25using namespace WebEngineViewer;
26
27class WebEnginePage::Private
28{
29public:
30 std::optional<QPalette> lastPalette;
31 std::optional<KColorScheme> lastColorScheme;
32 QWebEngineScript refreshScript;
33};
34
36 : QWebEnginePage(/*new QWebEngineProfile, */ parent)
37 , d(std::make_unique<WebEnginePage::Private>())
38{
39 // Create a private (off the record) QWebEngineProfile here to isolate the
40 // browsing settings, and adopt it as a child so that it will be deleted
41 // when we are destroyed. The profile must remain active for as long as
42 // any QWebEnginePage's belonging to it exist, see the API documentation
43 // of QWebEnginePage::QWebEnginePage(QWebEngineProfile *, QObject *).
44 // Deleting it as our child on destruction is safe.
45 //
46 // Do not try to save a line of code by setting the parent on construction:
47 //
48 // WebEnginePage::WebEnginePage(QObject *parent)
49 // : QWebEnginePage(new QWebEngineProfile(this), parent)
50 //
51 // because the QWebEngineProfile constructor will call out to the QWebEnginePage
52 // and crash because the QWebEnginePage is not fully constructed yet.
53 // profile()->setParent(this);
54
55 init();
56}
57
59
60void WebEnginePage::init()
61{
62 connect(profile(), &QWebEngineProfile::downloadRequested, this, &WebEnginePage::saveHtml);
63 qGuiApp->installEventFilter(this);
64
65 // Expose main colors from KColorScheme
66 d->refreshScript.setName(QStringLiteral("injectColorScheme"));
67 d->refreshScript.setSourceCode(refreshCssVariablesScript());
68 d->refreshScript.setInjectionPoint(QWebEngineScript::DocumentReady);
69 d->refreshScript.setRunsOnSubFrames(true);
70 d->refreshScript.setWorldId(QWebEngineScript::ApplicationWorld);
71 scripts().insert(d->refreshScript);
72}
73
74bool WebEnginePage::eventFilter(QObject *obj, QEvent *event)
75{
76 if (obj != qGuiApp) {
77 return false;
78 }
79
81 // Refresh main colors from KColorScheme
82 auto cssVariablesScript = refreshCssVariablesScript();
83 runJavaScript(cssVariablesScript, WebEngineViewer::WebEngineManageScript::scriptWordId());
84
85 d->refreshScript.setSourceCode(cssVariablesScript);
86 scripts().remove(d->refreshScript);
87 scripts().insert(d->refreshScript);
88 }
89 return QObject::eventFilter(obj, event);
90}
91
92QString WebEnginePage::refreshCssVariablesScript()
93{
94 // Same logic as KIconColors
95 auto palette = qGuiApp->palette();
96 if (!d->lastColorScheme || !d->lastPalette || palette != d->lastPalette) {
97 d->lastPalette = palette;
99 }
100
101 const auto script = QStringLiteral(R"RAW(
102{
103 const root = document.querySelector(':root');
104 root.style.setProperty('--kcolorscheme-background', '%1');
105 root.style.setProperty('--kcolorscheme-text', '%2');
106 root.style.setProperty('--kcolorscheme-highlight', '%3');
107 root.style.setProperty('--kcolorscheme-highlight-text', '%4');
108 root.style.setProperty('--kcolorscheme-accent', '%5');
109 root.style.setProperty('--kcolorscheme-positive-text', '%6');
110 root.style.setProperty('--kcolorscheme-positive-background', '%7');
111 root.style.setProperty('--kcolorscheme-neutral-text', '%8');
112 root.style.setProperty('--kcolorscheme-neutral-background', '%9');
113 root.style.setProperty('--kcolorscheme-negative-text', '%10');
114 root.style.setProperty('--kcolorscheme-negative-background', '%11');
115 root.style.setProperty('--kcolorscheme-active-text', '%12');
116 root.style.setProperty('--kcolorscheme-active-background', '%13');
117 root.style.setProperty('--kcolorscheme-text-disabled', '%14');
118 root.style.setProperty('--kcolorscheme-text-link', '%15');
119}
120 )RAW")
121 .arg(d->lastColorScheme->background(KColorScheme::NormalBackground).color().name(),
122 d->lastColorScheme->foreground(KColorScheme::NormalText).color().name(),
123 palette.highlight().color().name(),
124 palette.highlightedText().color().name(),
125 palette.accent().color().name(),
126 d->lastColorScheme->foreground(KColorScheme::PositiveText).color().name(),
127 d->lastColorScheme->background(KColorScheme::PositiveBackground).color().name(),
128 d->lastColorScheme->foreground(KColorScheme::NeutralText).color().name(),
129 d->lastColorScheme->background(KColorScheme::NeutralBackground).color().name(),
130 d->lastColorScheme->foreground(KColorScheme::NegativeText).color().name(),
131 d->lastColorScheme->background(KColorScheme::NegativeBackground).color().name(),
132 d->lastColorScheme->foreground(KColorScheme::ActiveText).color().name(),
133 d->lastColorScheme->background(KColorScheme::ActiveBackground).color().name(),
134 d->lastColorScheme->foreground(KColorScheme::InactiveText).color().name(),
135 d->lastColorScheme->foreground(KColorScheme::LinkText).color().name());
136
137 return script;
138}
139
140WebEngineViewer::WebHitTest *WebEnginePage::hitTestContent(const QPoint &pos)
141{
142 return new WebHitTest(this, mapToViewport(pos), pos);
143}
144
145QPoint WebEnginePage::mapToViewport(const QPoint &pos) const
146{
147 return QPoint(pos.x() / zoomFactor(), pos.y() / zoomFactor());
148}
149
150void WebEnginePage::saveHtml(QWebEngineDownloadRequest *download)
151{
152 const QString fileName = QFileDialog::getSaveFileName(QWebEngineView::forPage(this), i18nc("@title:window", "Save HTML Page"));
153 if (!fileName.isEmpty()) {
154 download->setSavePageFormat(QWebEngineDownloadRequest::SingleHtmlSaveFormat);
155 download->setDownloadDirectory(QFileInfo(fileName).path());
156 download->setDownloadFileName(QFileInfo(fileName).fileName());
157 download->accept();
158 }
159}
160
161bool WebEnginePage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame)
162{
163 if (isMainFrame && type == NavigationTypeLinkClicked) {
164 Q_EMIT urlClicked(url);
165 return false;
166 }
167 return true;
168}
169
170void WebEnginePage::javaScriptConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel level,
171 const QString &message,
172 int lineNumber,
173 const QString &sourceID)
174{
175 Q_UNUSED(level)
176 Q_UNUSED(sourceID)
177 // Don't convert to debug categories
178 qDebug() << "WebEnginePage::javaScriptConsoleMessage lineNumber: " << lineNumber << " message: " << message;
179 Q_EMIT showConsoleMessage(message);
180}
181
182#include "moc_webenginepage.cpp"
The WebEnginePage class.
~WebEnginePage() override
Destructor.
WebEnginePage(QObject *parent=nullptr)
Constructor.
The WebHitTest class.
Definition webhittest.h:23
QString i18nc(const char *context, const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
QString path(const QString &relativePath)
ApplicationPaletteChange
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
virtual bool eventFilter(QObject *watched, QEvent *event)
int x() const const
int y() const const
QString arg(Args &&... args) const const
bool isEmpty() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:33:26 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.