aboutsummaryrefslogtreecommitdiff
path: root/src/webengine
diff options
context:
space:
mode:
Diffstat (limited to 'src/webengine')
-rw-r--r--src/webengine/meson.build27
-rw-r--r--src/webengine/test/form.html10
-rw-r--r--src/webengine/test/icon.svg7
-rw-r--r--src/webengine/test/profile.cpp124
-rw-r--r--src/webengine/test/profilemanager.cpp120
-rw-r--r--src/webengine/test/sample.html7
-rw-r--r--src/webengine/test/testing.profile8
-rw-r--r--src/webengine/test/view.cpp92
-rw-r--r--src/webengine/urlinterceptor.cpp45
-rw-r--r--src/webengine/urlinterceptor.h17
-rw-r--r--src/webengine/webpage.cpp8
-rw-r--r--src/webengine/webpage.h6
-rw-r--r--src/webengine/webprofile.cpp198
-rw-r--r--src/webengine/webprofile.h167
-rw-r--r--src/webengine/webprofilemanager.cpp147
-rw-r--r--src/webengine/webprofilemanager.h102
-rw-r--r--src/webengine/webview.cpp54
-rw-r--r--src/webengine/webview.h20
-rw-r--r--src/webengine/webviewcontextmenu.cpp3
19 files changed, 743 insertions, 419 deletions
diff --git a/src/webengine/meson.build b/src/webengine/meson.build
new file mode 100644
index 0000000..db7bdc5
--- /dev/null
+++ b/src/webengine/meson.build
@@ -0,0 +1,27 @@
+webengine_moc = mod_qt5.preprocess(
+ moc_headers: [ 'webprofile.h', 'webpage.h', 'webview.h' ],
+ dependencies: dep_qt5
+)
+
+dep_webengine = declare_dependency(
+ include_directories: [ '.', smolbote_include ],
+ link_with: static_library('webengine', dependencies: dep_qt5,
+ include_directories: smolbote_include,
+ sources: [ 'webprofile.cpp', 'urlinterceptor.cpp', 'webprofilemanager.cpp', 'webpage.cpp', 'webview.cpp', 'webviewcontextmenu.cpp', webengine_moc ])
+)
+
+poi_sourceset.add(dep_webengine)
+
+test('profile', executable('profile', 'test/profile.cpp', dependencies: [ dep_qt5, dep_webengine, dep_catch ]),
+ env: { 'PROFILE' : meson.current_source_dir()/'test/testing.profile' },
+ suite: 'webengine')
+
+test('profilemanager', executable('profilemanager', 'test/profilemanager.cpp', dependencies: [ dep_qt5, dep_webengine, dep_catch ]),
+ env: { 'PROFILES' : meson.current_source_dir()/'test/testing.profile' },
+ suite: 'webengine')
+
+test('view', executable('view', 'test/view.cpp', dependencies: [ dep_qt5, dep_webengine, dep_catch ]),
+ args: [ '-platform', 'offscreen' ],
+ env: { 'PROFILE' : meson.current_source_dir()/'test/testing.profile',
+ 'URL' : meson.current_source_dir()/'test/sample.html' },
+ suite: 'webengine')
diff --git a/src/webengine/test/form.html b/src/webengine/test/form.html
new file mode 100644
index 0000000..9d8b19e
--- /dev/null
+++ b/src/webengine/test/form.html
@@ -0,0 +1,10 @@
+<html>
+
+<head>
+ <title>Form completion test</title>
+</head>
+
+<body>
+<h2>Form completion test</h2>
+</body>
+</html>
diff --git a/src/webengine/test/icon.svg b/src/webengine/test/icon.svg
new file mode 100644
index 0000000..a348cab
--- /dev/null
+++ b/src/webengine/test/icon.svg
@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300" version="1.1">
+ <circle cx="150" cy="150" r="100" stroke="#000000" stroke-width="6" fill="#e60026"></circle>
+ <circle cx="150" cy="150" r="87" stroke="#000000" stroke-width="4" fill="#e5e4e2"></circle>
+ <path d="M230,150 A80,80 0 0 0 150,70 L150,150 Z" />
+ <path d="M70,150 A80,80 0 0 0 150,230 L150,150 Z" />
+</svg>
+
diff --git a/src/webengine/test/profile.cpp b/src/webengine/test/profile.cpp
new file mode 100644
index 0000000..7351f66
--- /dev/null
+++ b/src/webengine/test/profile.cpp
@@ -0,0 +1,124 @@
+#define CATCH_CONFIG_RUNNER
+
+// clazy:excludeall=non-pod-global-static
+
+#include "webprofilemanager.h"
+#include <QApplication>
+#include <catch2/catch.hpp>
+
+TEST_CASE("loading profile settings")
+{
+ const QString search = GENERATE(as<QString>{}, "https://search.url/t=%1", "https://duckduckgo.com/?q=%1&ia=web", "aaabbbccc");
+ const QUrl homepage = GENERATE(as<QUrl>{}, "https://homepage.net", "about:blank", "aaabbbccc");
+ const QUrl newtab = GENERATE(as<QUrl>{}, "https://newtab.net", "about:blank", "aaabbbccc");
+
+ auto *settings = WebProfile::load(QString(), search, homepage, newtab);
+
+ REQUIRE(settings != nullptr);
+ REQUIRE(settings->value("search").toString() == search);
+ REQUIRE(settings->value("homepage").toUrl() == homepage);
+ REQUIRE(settings->value("newtab").toUrl() == newtab);
+
+ delete settings;
+}
+
+SCENARIO("loading individual profiles")
+{
+ GIVEN("no profile preset")
+ {
+ const QString search = GENERATE(as<QString>{}, "https://search.url/t=%1", "https://duckduckgo.com/?q=%1&ia=web", "aaabbbccc");
+ const QUrl homepage = GENERATE(as<QUrl>{}, "https://homepage.net", "about:blank", "aaabbbccc");
+ const QUrl newtab = GENERATE(as<QUrl>{}, "https://newtab.net", "about:blank", "aaabbbccc");
+
+ const QString id{ "id" };
+ auto *settings = WebProfile::load(QString(), search, homepage, newtab);
+ auto *profile = WebProfile::load(id, settings, true);
+
+ REQUIRE(profile != nullptr);
+ REQUIRE(profile->getId() == id);
+ REQUIRE(profile->property("id").toString() == id);
+ REQUIRE(profile->name() == id);
+ REQUIRE(profile->search() == search);
+ REQUIRE(profile->homepage() == homepage);
+ REQUIRE(profile->newtab() == newtab);
+
+ REQUIRE(profile->isOffTheRecord());
+ delete settings;
+ delete profile;
+ }
+
+ GIVEN("an off-the-record profile preset")
+ {
+ REQUIRE(qEnvironmentVariableIsSet("PROFILE"));
+
+ const QString id{ "id" };
+ auto *settings = WebProfile::load(qgetenv("PROFILE"), QString(), QUrl(), QUrl());
+ auto *profile = WebProfile::load(id, settings, true);
+
+ REQUIRE(profile != nullptr);
+ REQUIRE(profile->getId() == id);
+ REQUIRE(profile->isOffTheRecord());
+
+ WHEN("created")
+ {
+ THEN("uses default values")
+ {
+ REQUIRE(profile->name() == "Test Profile");
+ REQUIRE(profile->search() == "https://duckduckgo.com/?q=%1&ia=web");
+ REQUIRE(profile->homepage() == QUrl("about:blank"));
+ REQUIRE(profile->newtab() == QUrl("about:blank"));
+ }
+ }
+
+ WHEN("changing profile name")
+ {
+ const QString name = GENERATE(as<QString>{}, "a", "bb", "ccc");
+ profile->setName(name);
+ THEN("the name changes")
+ {
+ REQUIRE(profile->name() == name);
+ REQUIRE(settings->value("name").toString() == name);
+ }
+ }
+ WHEN("changing search url")
+ {
+ const QString search = GENERATE(as<QString>{}, "a", "bb", "ccc");
+ profile->setSearch(search);
+ THEN("the search url changes")
+ {
+ REQUIRE(profile->search() == search);
+ REQUIRE(settings->value("search").toString() == search);
+ }
+ }
+ WHEN("changing homepage")
+ {
+ const QUrl url = GENERATE(as<QUrl>{}, "a", "bb", "ccc");
+ profile->setHomepage(url);
+ THEN("homepage changes")
+ {
+ REQUIRE(profile->homepage() == url);
+ REQUIRE(settings->value("homepage").toUrl() == url);
+ }
+ }
+ WHEN("changing newtab")
+ {
+ const QUrl url = GENERATE(as<QUrl>{}, "a", "bb", "ccc");
+ profile->setNewtab(url);
+ THEN("newtab changes")
+ {
+ REQUIRE(profile->newtab() == url);
+ REQUIRE(settings->value("newtab").toUrl() == url);
+ }
+ }
+
+ delete settings;
+ delete profile;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ const auto r = Catch::Session().run(argc, argv);
+ return r;
+}
diff --git a/src/webengine/test/profilemanager.cpp b/src/webengine/test/profilemanager.cpp
new file mode 100644
index 0000000..dc7c903
--- /dev/null
+++ b/src/webengine/test/profilemanager.cpp
@@ -0,0 +1,120 @@
+#define CATCH_CONFIG_RUNNER
+
+// clazy:excludeall=non-pod-global-static
+
+#include "webprofilemanager.h"
+#include <QApplication>
+#include <catch2/catch.hpp>
+
+SCENARIO("WebProfileManager")
+{
+ const QString search{ "https://search.url/t=%1" };
+ const QUrl homepage{ "https://homepage.net" };
+ const QUrl newtab{ "https://newtab.net" };
+ const QString default_id{ "default" };
+
+ GIVEN("an empty profile list")
+ {
+ WebProfileManager<false> profiles({}, default_id, search, homepage, newtab);
+
+ REQUIRE(profiles.idList().count() == 1);
+ REQUIRE(profiles.profile(default_id) == WebProfile::defaultProfile());
+ REQUIRE(profiles.profile("not-in-list") == nullptr);
+
+ WHEN("adding a new profile")
+ {
+ const QString id{ "id" };
+ auto *settings = WebProfile::load(QString(), search, homepage, newtab);
+ auto *profile = WebProfile::load(id, settings, true);
+
+ THEN("doesn't add profile without settings")
+ {
+ profiles.add(id, profile, nullptr);
+ REQUIRE(profiles.idList().count() == 1);
+ }
+
+ THEN("doesn't add settings without profile")
+ {
+ profiles.add(id, nullptr, settings);
+ REQUIRE(profiles.idList().count() == 1);
+ }
+
+ THEN("adds new profile with settings")
+ {
+ profiles.add(id, profile, settings);
+ REQUIRE(profiles.idList().count() == 2);
+ }
+ }
+
+ WHEN("moving")
+ {
+ WebProfileManager<false> other(std::move(profiles));
+ THEN("moved has the same number of profiles")
+ {
+ REQUIRE(other.idList().count() == 1);
+ REQUIRE(other.profile(default_id) == WebProfile::defaultProfile());
+ REQUIRE(other.profile("not-in-list") == nullptr);
+ }
+ }
+ }
+
+ GIVEN("a number of profiles, default undefined")
+ {
+ REQUIRE(qEnvironmentVariableIsSet("PROFILES"));
+
+ WebProfileManager<false> profiles(QString::fromLatin1(qgetenv("PROFILES")).split(';'), default_id, search, homepage, newtab);
+
+ REQUIRE(profiles.idList().count() == 2);
+ REQUIRE(profiles.profile(default_id) == WebProfile::defaultProfile());
+ REQUIRE(profiles.profile("testing") != nullptr);
+ REQUIRE(profiles.profile("not-in-list") == nullptr);
+
+ WHEN("making global")
+ {
+ profiles.make_global();
+ WebProfileManager other;
+
+ THEN("global has the same number of profiles")
+ {
+ REQUIRE(other.idList().count() == 2);
+ REQUIRE(other.profile(default_id) == WebProfile::defaultProfile());
+ REQUIRE(other.profile("testing") != nullptr);
+ REQUIRE(other.profile("not-in-list") == nullptr);
+ }
+
+ THEN("walking has no nullptrs")
+ {
+ other.walk([](const QString &, WebProfile *profile, const QSettings *settings) {
+ REQUIRE(profile != nullptr);
+ REQUIRE(settings != nullptr);
+ });
+ }
+ }
+ }
+
+ GIVEN("a number of profiles, default defined")
+ {
+ REQUIRE(qEnvironmentVariableIsSet("PROFILES"));
+
+ WebProfileManager<false> profiles(QString::fromLatin1(qgetenv("PROFILES")).split(';'), "testing", search, homepage, newtab);
+
+ REQUIRE(profiles.idList().count() == 1);
+ REQUIRE(profiles.profile("testing") == WebProfile::defaultProfile());
+ REQUIRE(profiles.profile("not-in-list") == nullptr);
+
+ WHEN("walking")
+ {
+ profiles.walk([](const QString &, WebProfile *profile, const QSettings *settings) {
+ REQUIRE(profile != nullptr);
+ REQUIRE(settings != nullptr);
+ });
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ const auto r = Catch::Session().run(argc, argv);
+ return r;
+}
diff --git a/src/webengine/test/sample.html b/src/webengine/test/sample.html
new file mode 100644
index 0000000..54746d5
--- /dev/null
+++ b/src/webengine/test/sample.html
@@ -0,0 +1,7 @@
+<html>
+<head><title>sample page</title></head>
+<body>
+ <h2><img src="icon.svg" />This is a sample page</h2>
+ <iframe width="100%" height="80%" src="form.html"></iframe>
+</body>
+</html>
diff --git a/src/webengine/test/testing.profile b/src/webengine/test/testing.profile
new file mode 100644
index 0000000..e345a3e
--- /dev/null
+++ b/src/webengine/test/testing.profile
@@ -0,0 +1,8 @@
+name=Test Profile
+otr=true
+search=https://duckduckgo.com/?q=%1&ia=web
+homepage=about:blank
+newtab=about:blank
+
+[headers]
+Dnt=1
diff --git a/src/webengine/test/view.cpp b/src/webengine/test/view.cpp
new file mode 100644
index 0000000..8aa639a
--- /dev/null
+++ b/src/webengine/test/view.cpp
@@ -0,0 +1,92 @@
+#define CATCH_CONFIG_RUNNER
+
+// clazy:excludeall=non-pod-global-static
+
+#include "webprofile.h"
+#include "webview.h"
+#include <QApplication>
+#include <QMainWindow>
+#include <QTimer>
+#include <QtWebEngine>
+#include <catch2/catch.hpp>
+
+SCENARIO("WebView")
+{
+ const QString profile_id{ "default" };
+ auto *settings = WebProfile::load(qgetenv("PROFILE"), "about:blank", QUrl{ "about:blank" }, QUrl{ "about:blank" });
+ auto *profile = WebProfile::load(profile_id, settings, true);
+
+ QMainWindow window;
+ auto *view = new WebView(profile, nullptr);
+ window.setCentralWidget(view);
+ window.show();
+ window.resize(800, 600);
+
+ WHEN("created")
+ {
+ THEN("using the default profile")
+ {
+ REQUIRE(view->profile() == profile);
+ }
+ THEN("serialized using default profile")
+ {
+ const auto data = view->serialize();
+ REQUIRE(data.profile == profile_id);
+ REQUIRE(data.url.isEmpty());
+ REQUIRE(!data.history.isEmpty());
+ }
+ THEN("loading a url")
+ {
+ // block until a loadFinished signal
+ QEventLoop pause;
+ QObject::connect(view, &WebView::loadFinished, &pause, &QEventLoop::quit);
+ view->load(QUrl{ qgetenv("URL") });
+ pause.exec();
+
+ REQUIRE(view->isLoaded());
+ }
+ }
+
+ WHEN("changing profiles")
+ {
+ const QString swap_profile_id{ "swap_profile" };
+ auto *swap_settings = WebProfile::load(QString(), "about:blank", QUrl{ "about:blank" }, QUrl{ "about:blank" });
+ auto *swap_profile = WebProfile::load(swap_profile_id, swap_settings, true);
+
+ view->setProfile(swap_profile);
+ THEN("using the swap profile")
+ {
+ REQUIRE(view->profile() == swap_profile);
+ }
+ THEN("serialized using swap profile")
+ {
+ const auto data = view->serialize();
+ REQUIRE(data.profile == swap_profile_id);
+ REQUIRE(data.url.isEmpty());
+ REQUIRE(!data.history.isEmpty());
+ }
+
+ view->setProfile(profile);
+ delete swap_settings;
+ delete swap_profile;
+ }
+
+ // cleanup
+ window.close();
+ delete view;
+ delete settings;
+ delete profile;
+}
+
+int main(int argc, char **argv)
+{
+ QtWebEngine::initialize();
+ QApplication app(argc, argv);
+
+ QTimer::singleShot(0, &app, [argc, argv, &app]() {
+ const auto n_failed = Catch::Session().run(argc, argv);
+ app.exit(n_failed);
+ });
+
+ return app.exec();
+}
diff --git a/src/webengine/urlinterceptor.cpp b/src/webengine/urlinterceptor.cpp
index 29cd869..047cad4 100644
--- a/src/webengine/urlinterceptor.cpp
+++ b/src/webengine/urlinterceptor.cpp
@@ -8,59 +8,24 @@
#include "urlinterceptor.h"
#include "webprofile.h"
-#include "urlfilter.h"
// test DNT on https://browserleaks.com/donottrack
-UrlRequestInterceptor::UrlRequestInterceptor(WebProfile* profile, QObject* parent)
- : QWebEngineUrlRequestInterceptor(parent)
+UrlRequestInterceptor::UrlRequestInterceptor(WebProfile* profile)
+ : QWebEngineUrlRequestInterceptor(profile)
{
Q_CHECK_PTR(profile);
m_profile = profile;
}
-void UrlRequestInterceptor::addHttpHeader(const QByteArray &key, const QByteArray &value)
-{
- headers.append(qMakePair(key, value));
-}
-
-void UrlRequestInterceptor::addFilter(UrlFilter *filter)
-{
- if(filter != nullptr)
- filters.append(filter);
-}
-void UrlRequestInterceptor::removeFilter(UrlFilter *filter)
-{
- if(filter != nullptr)
- filters.removeOne(filter);
-}
-
void UrlRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info)
{
- for(const auto *filter : qAsConst(filters)) {
- const auto match = filter->match(info.firstPartyUrl(), info.requestUrl(), info.resourceType());
-
- // skip if no match
- if(match.first == UrlFilter::NotMatched)
- continue;
-
- else {
- if(match.first == UrlFilter::Allow)
- info.block(false);
- else if(match.first == UrlFilter::Block)
- info.block(true);
- else if(match.first == UrlFilter::Redirect)
- info.redirect(QUrl::fromUserInput(match.second));
- // we found a match, skip the rest
- break;
- }
+ for(auto *filter : qAsConst(m_profile->m_filters)) {
+ filter->interceptRequest(info);
}
// set headers
- for(const auto &header : qAsConst(headers)) {
- info.setHttpHeader(header.first, header.second);
- }
- for(auto i = m_profile->headers().constBegin(); i != m_profile->headers().constEnd(); ++i) {
+ for(auto i = m_profile->m_headers.constBegin(); i != m_profile->m_headers.constEnd(); ++i) {
info.setHttpHeader(i.key(), i.value());
}
}
diff --git a/src/webengine/urlinterceptor.h b/src/webengine/urlinterceptor.h
index 4909586..eb3ce67 100644
--- a/src/webengine/urlinterceptor.h
+++ b/src/webengine/urlinterceptor.h
@@ -9,30 +9,23 @@
#ifndef SMOLBOTE_URLREQUESTINTERCEPTOR_H
#define SMOLBOTE_URLREQUESTINTERCEPTOR_H
-#include <QVector>
#include <QWebEngineUrlRequestInterceptor>
-#include <QByteArray>
-class UrlFilter;
class WebProfile;
class UrlRequestInterceptor : public QWebEngineUrlRequestInterceptor
{
- Q_OBJECT
+ friend class WebProfile;
+
public:
- explicit UrlRequestInterceptor(WebProfile *profile, QObject *parent = nullptr);
~UrlRequestInterceptor() override = default;
- void addHttpHeader(const QByteArray &key, const QByteArray &value);
-
- void addFilter(UrlFilter *filter);
- void removeFilter(UrlFilter *filter);
-
void interceptRequest(QWebEngineUrlRequestInfo &info) override;
+protected:
+ explicit UrlRequestInterceptor(WebProfile *profile);
+
private:
WebProfile *m_profile;
- QVector<QPair<QByteArray, QByteArray>> headers;
- QVector<UrlFilter*> filters;
};
#endif // SMOLBOTE_URLREQUESTINTERCEPTOR_H
diff --git a/src/webengine/webpage.cpp b/src/webengine/webpage.cpp
index e79db9d..8c6b8db 100644
--- a/src/webengine/webpage.cpp
+++ b/src/webengine/webpage.cpp
@@ -12,7 +12,6 @@
#include <QTimer>
#include <QWebEngineFullScreenRequest>
#include <QWebEngineCertificateError>
-#include <spdlog/spdlog.h>
QString tr_terminationStatus(QWebEnginePage::RenderProcessTerminationStatus status)
{
@@ -106,17 +105,16 @@ void WebPage::featurePermissionDialog(const QUrl &securityOrigin, QWebEnginePage
messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
messageBox.setDefaultButton(QMessageBox::No);
- if(messageBox.exec() == QMessageBox::Yes)
+ if(messageBox.exec() == QMessageBox::Yes) {
setFeaturePermission(securityOrigin, feature, QWebEnginePage::PermissionGrantedByUser);
- else
+ } else {
setFeaturePermission(securityOrigin, feature, QWebEnginePage::PermissionDeniedByUser);
+ }
}
void WebPage::renderProcessCrashed(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode)
{
if(terminationStatus != QWebEnginePage::NormalTerminationStatus) {
- spdlog::warn("render process terminated: [{}] {}", terminationStatus, exitCode);
-
QString page = "<html><body><h1>This tab has crashed!</h1>%message%</body></html>";
page.replace(QLatin1String("%message%"), QString("<p>%1<br>Exit code is %2.</p>"
"<p>Press <a href='%3'>here</a> to reload this tab.</p>")
diff --git a/src/webengine/webpage.h b/src/webengine/webpage.h
index 48011cb..91ae4f3 100644
--- a/src/webengine/webpage.h
+++ b/src/webengine/webpage.h
@@ -14,13 +14,15 @@
class WebPage : public QWebEnginePage
{
Q_OBJECT
+
public:
- explicit WebPage(QWebEngineProfile *profile, QObject *parent = nullptr);
+ WebPage(QWebEngineProfile *profile, QObject *parent = nullptr);
+ ~WebPage() override = default;
protected:
bool certificateError(const QWebEngineCertificateError &certificateError) override;
-private slots:
+protected slots:
void featurePermissionDialog(const QUrl &securityOrigin, QWebEnginePage::Feature feature);
void renderProcessCrashed(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode);
};
diff --git a/src/webengine/webprofile.cpp b/src/webengine/webprofile.cpp
index 5224189..f0368c9 100644
--- a/src/webengine/webprofile.cpp
+++ b/src/webengine/webprofile.cpp
@@ -11,6 +11,7 @@
#include <QSettings>
#include <QWebEngineCookieStore>
#include <QWebEngineSettings>
+#include "urlinterceptor.h"
static WebProfile *s_profile = nullptr;
@@ -25,11 +26,89 @@ WebProfile *WebProfile::defaultProfile()
return s_profile;
}
-WebProfile::WebProfile(const QString &name, QObject *parent)
- : QWebEngineProfile(parent)
+QSettings *WebProfile::load(const QString &path, const QString &search, const QUrl &homepage, const QUrl &newtab)
+{
+ auto *settings = new QSettings(path, QSettings::IniFormat);
+
+ if(!settings->contains("search")) {
+ settings->setValue("search", search);
+ }
+ if(!settings->contains("homepage")) {
+ settings->setValue("homepage", homepage);
+ }
+ if(!settings->contains("newtab")) {
+ settings->setValue("newtab", newtab);
+ }
+
+ return settings;
+}
+
+WebProfile *WebProfile::load(const QString &id, QSettings *settings, bool isOffTheRecord)
{
- m_name = name;
+ WebProfile *profile = nullptr;
+ if(isOffTheRecord || settings->value("otr", isOffTheRecord).toBool()) {
+ profile = new WebProfile(id, nullptr);
+ } else {
+ profile = new WebProfile(id, id, nullptr);
+ }
+
+ profile->m_name = settings->value("name", id).toString();
+ connect(profile, &WebProfile::nameChanged, profile, [settings](const QString &name) { settings->setValue("name", name); });
+ profile->m_search = settings->value("search", "").toString();
+ connect(profile, &WebProfile::searchChanged, settings, [settings](const QString &url) { settings->setValue("search", url); });
+ profile->m_homepage = settings->value("homepage", "").toUrl();
+ connect(profile, &WebProfile::homepageChanged, settings, [settings](const QUrl &url) { settings->setValue("homepage", url); });
+ profile->m_newtab = settings->value("newtab", "").toUrl();
+ connect(profile, &WebProfile::newtabChanged, settings, [settings](const QUrl &url) { settings->setValue("newtab", url); });
+
+ {
+ settings->beginGroup("properties");
+ const auto keys = settings->childKeys();
+ for(const QString &key : keys) {
+ profile->setProperty(qUtf8Printable(key), settings->value(key));
+ }
+ settings->endGroup(); // properties
+ connect(profile, &WebProfile::propertyChanged, [settings](const QString &property, const QVariant &value) {
+ settings->setValue("properties/" + property, value);
+ });
+ }
+ {
+ settings->beginGroup("attributes");
+ const auto keys = settings->childKeys();
+ auto *s = profile->settings();
+ for(const QString &key : keys) {
+ auto attribute = static_cast<QWebEngineSettings::WebAttribute>(key.toInt());
+ s->setAttribute(attribute, settings->value(key).toBool());
+ }
+ settings->endGroup();
+ connect(profile, &WebProfile::attributeChanged, [settings](const QWebEngineSettings::WebAttribute attr, const bool value) {
+ settings->setValue("attributes/" + QString::number(attr), value);
+ });
+ }
+ {
+ // headers
+ settings->beginGroup("headers");
+ for(const QString &key : settings->childKeys()) {
+ profile->setHttpHeader(key.toLatin1(), settings->value(key).toString().toLatin1());
+ }
+ settings->endGroup();
+ connect(profile, &WebProfile::headerChanged, [settings](const QString &name, const QString &value) {
+ settings->setValue("headers/" + name, value);
+ });
+ connect(profile, &WebProfile::headerRemoved, [settings](const QString &name) {
+ settings->remove("headers/" + name);
+ });
+ }
+ return profile;
+}
+
+// off-the-record constructor
+WebProfile::WebProfile(const QString &id, QObject *parent)
+ : QWebEngineProfile(parent)
+ , m_id(id)
+{
+ QWebEngineProfile::setUrlRequestInterceptor(new UrlRequestInterceptor(this));
connect(this->cookieStore(), &QWebEngineCookieStore::cookieAdded, this, [this](const QNetworkCookie &cookie) {
m_cookies.append(cookie);
});
@@ -38,11 +117,12 @@ WebProfile::WebProfile(const QString &name, QObject *parent)
});
}
-WebProfile::WebProfile(const QString &storageName, const QString &name, QObject *parent)
+// default constructor
+WebProfile::WebProfile(const QString &id, const QString &storageName, QObject *parent)
: QWebEngineProfile(storageName, parent)
+ , m_id(id)
{
- m_name = name;
-
+ QWebEngineProfile::setUrlRequestInterceptor(new UrlRequestInterceptor(this));
connect(this->cookieStore(), &QWebEngineCookieStore::cookieAdded, this, [this](const QNetworkCookie &cookie) {
m_cookies.append(cookie);
});
@@ -50,109 +130,3 @@ WebProfile::WebProfile(const QString &storageName, const QString &name, QObject
m_cookies.removeAll(cookie);
});
}
-
-const QString WebProfile::name() const
-{
- return m_name;
-}
-
-void WebProfile::setName(const QString &name)
-{
- m_name = name;
- emit nameChanged(name);
-}
-
-QString WebProfile::search() const
-{
- return m_search;
-}
-
-void WebProfile::setSearch(const QString &url)
-{
- m_search = url;
- emit searchChanged(m_search);
-}
-
-QUrl WebProfile::homepage() const
-{
- return m_homepage;
-}
-
-void WebProfile::setHomepage(const QUrl &url)
-{
- m_homepage = url;
- emit homepageChanged(m_homepage);
-}
-
-QUrl WebProfile::newtab() const
-{
- return m_newtab;
-}
-
-void WebProfile::setNewtab(const QUrl &url)
-{
- m_newtab = url;
- emit newtabChanged(m_newtab);
-}
-
-void WebProfile::setCachePath(const QString &path)
-{
- QWebEngineProfile::setCachePath(path);
- emit propertyChanged("cachePath", path);
-}
-
-void WebProfile::setPersistentStoragePath(const QString &path)
-{
- QWebEngineProfile::setPersistentStoragePath(path);
- emit propertyChanged("persistentStoragePath", path);
-}
-
-void WebProfile::setPersistentCookiesPolicy(int policy)
-{
- QWebEngineProfile::setPersistentCookiesPolicy(static_cast<QWebEngineProfile::PersistentCookiesPolicy>(policy));
- emit propertyChanged("persistentCookiesPolicy", policy);
-}
-
-void WebProfile::setHttpAcceptLanguage(const QString &httpAcceptLanguage)
-{
- QWebEngineProfile::setHttpAcceptLanguage(httpAcceptLanguage);
- emit propertyChanged("httpAcceptLanguage", httpAcceptLanguage);
-}
-
-void WebProfile::setHttpCacheMaximumSize(int maxSize)
-{
- QWebEngineProfile::setHttpCacheMaximumSize(maxSize);
- emit propertyChanged("httpCacheMaximumSize", maxSize);
-}
-
-void WebProfile::setHttpCacheType(int type)
-{
- QWebEngineProfile::setHttpCacheType(static_cast<QWebEngineProfile::HttpCacheType>(type));
- emit propertyChanged("httpCacheType", type);
-}
-
-void WebProfile::setHttpUserAgent(const QString &userAgent)
-{
- QWebEngineProfile::setHttpUserAgent(userAgent);
- emit propertyChanged("httpUserAgent", userAgent);
-}
-
-void WebProfile::setHttpHeader(const QString &name, const QString &value)
-{
- m_headers[name.toLatin1()] = value.toLatin1();
- emit headerChanged(name, value);
-}
-
-void WebProfile::removeHttpHeader(const QString &name)
-{
- if(m_headers.contains(name.toLatin1())) {
- m_headers.remove(name.toLatin1());
- emit headerRemoved(name);
- }
-}
-
-void WebProfile::setSpellCheckEnabled(bool enable)
-{
- QWebEngineProfile::setSpellCheckEnabled(enable);
- emit propertyChanged("spellCheckEnabed", enable);
-}
diff --git a/src/webengine/webprofile.h b/src/webengine/webprofile.h
index 66154af..180cc9d 100644
--- a/src/webengine/webprofile.h
+++ b/src/webengine/webprofile.h
@@ -9,7 +9,6 @@
#ifndef SMOLBOTE_WEBENGINEPROFILE_H
#define SMOLBOTE_WEBENGINEPROFILE_H
-#include <QHash>
#include <QMap>
#include <QNetworkCookie>
#include <QString>
@@ -17,14 +16,17 @@
#include <QVector>
#include <QWebEngineProfile>
#include <QWebEngineSettings>
+#include <QVariant>
+#include <QSettings>
-class WebProfileManager;
+class UrlRequestInterceptor;
class WebProfile : public QWebEngineProfile
{
- friend class WebProfileManager;
+ friend class UrlRequestInterceptor;
Q_OBJECT
+ Q_PROPERTY(QString id READ getId CONSTANT)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QString search READ search WRITE setSearch NOTIFY searchChanged)
Q_PROPERTY(QUrl homepage READ homepage WRITE setHomepage NOTIFY homepageChanged)
@@ -42,72 +44,153 @@ class WebProfile : public QWebEngineProfile
Q_PROPERTY(bool spellCheckEnabled READ isSpellCheckEnabled WRITE setSpellCheckEnabled NOTIFY propertyChanged)
+signals:
+ void nameChanged(const QString &name);
+ void searchChanged(const QString &url);
+ void homepageChanged(const QUrl &url);
+ void newtabChanged(const QUrl &url);
+
+ void propertyChanged(const QString &name, const QVariant &value);
+ void attributeChanged(QWebEngineSettings::WebAttribute attribute, bool value);
+ void headerChanged(const QString &name, const QString &value);
+ void headerRemoved(const QString &name);
+
public:
+ [[nodiscard]] static QSettings *load(const QString &path, const QString &search = QString(), const QUrl &homepage = QUrl(), const QUrl &newtab = QUrl());
+ [[nodiscard]] static WebProfile *load(const QString &id, QSettings *settings, bool isOffTheRecord = true);
+
+ WebProfile(const WebProfile &) = delete;
+ WebProfile& operator=(const WebProfile &) = delete;
+ WebProfile(WebProfile &&) = delete;
+ WebProfile& operator=(WebProfile &&) = delete;
+
static WebProfile *defaultProfile();
static void setDefaultProfile(WebProfile *profile);
- ~WebProfile() = default;
+ ~WebProfile() override = default;
- const QString name() const;
- void setName(const QString &name);
-
- const QVector<QNetworkCookie> cookies() const
+ [[nodiscard]] QString getId() const
{
- return qAsConst(m_cookies);
+ return m_id;
+ }
+ [[nodiscard]] QString name() const
+ {
+ return m_name;
}
- const QMap<QByteArray, QByteArray> headers() const
+ void setName(const QString &name)
{
- return qAsConst(m_headers);
+ m_name = name;
+ emit nameChanged(name);
}
- // search url
- QString search() const;
- void setSearch(const QString &url);
+ [[nodiscard]] QVector<QNetworkCookie> cookies() const
+ {
+ return qAsConst(m_cookies);
+ }
- // homepage url
- QUrl homepage() const;
- void setHomepage(const QUrl &url);
+ [[nodiscard]] QString search() const
+ {
+ return m_search;
+ }
+ void setSearch(const QString &url)
+ {
+ m_search = url;
+ emit searchChanged(m_search);
+ }
- // new tab url
- QUrl newtab() const;
- void setNewtab(const QUrl &url);
+ [[nodiscard]] QUrl homepage() const
+ {
+ return m_homepage;
+ }
+ void setHomepage(const QUrl &url)
+ {
+ m_homepage = url;
+ emit homepageChanged(m_homepage);
+ }
- void setCachePath(const QString &path);
- void setPersistentStoragePath(const QString &path);
- void setPersistentCookiesPolicy(int policy);
+ [[nodiscard]] QUrl newtab() const
+ {
+ return m_newtab;
+ }
+ void setNewtab(const QUrl &url)
+ {
+ m_newtab = url;
+ emit newtabChanged(m_newtab);
+ }
- void setHttpAcceptLanguage(const QString &httpAcceptLanguage);
- void setHttpCacheMaximumSize(int maxSize);
- void setHttpCacheType(int type);
- void setHttpUserAgent(const QString &userAgent);
- void setHttpHeader(const QString &name, const QString &value);
- void removeHttpHeader(const QString &name);
+ void setCachePath(const QString &path)
+ {
+ QWebEngineProfile::setCachePath(path);
+ emit propertyChanged("cachePath", path);
+ }
+ void setPersistentStoragePath(const QString &path)
+ {
+ QWebEngineProfile::setPersistentStoragePath(path);
+ emit propertyChanged("persistentStoragePath", path);
+ }
+ void setPersistentCookiesPolicy(int policy)
+ {
+ QWebEngineProfile::setPersistentCookiesPolicy(static_cast<QWebEngineProfile::PersistentCookiesPolicy>(policy));
+ emit propertyChanged("persistentCookiesPolicy", policy);
+ }
- void setSpellCheckEnabled(bool enable);
+ void setHttpAcceptLanguage(const QString &httpAcceptLanguage)
+ {
+ QWebEngineProfile::setHttpAcceptLanguage(httpAcceptLanguage);
+ emit propertyChanged("httpAcceptLanguage", httpAcceptLanguage);
+ }
+ void setHttpCacheMaximumSize(int maxSize)
+ {
+ QWebEngineProfile::setHttpCacheMaximumSize(maxSize);
+ emit propertyChanged("httpCacheMaximumSize", maxSize);
+ }
+ void setHttpCacheType(int type)
+ {
+ QWebEngineProfile::setHttpCacheType(static_cast<QWebEngineProfile::HttpCacheType>(type));
+ emit propertyChanged("httpCacheType", type);
+ }
+ void setHttpUserAgent(const QString &userAgent)
+ {
+ QWebEngineProfile::setHttpUserAgent(userAgent);
+ emit propertyChanged("httpUserAgent", userAgent);
+ }
+ void setHttpHeader(const QString &name, const QString &value)
+ {
+ m_headers[name.toLatin1()] = value.toLatin1();
+ emit headerChanged(name, value);
+ }
+ void removeHttpHeader(const QString &name)
+ {
+ if(m_headers.contains(name.toLatin1())) {
+ m_headers.remove(name.toLatin1());
+ emit headerRemoved(name);
+ }
+ }
-signals:
- void nameChanged(const QString &name);
- void searchChanged(const QString &url);
- void homepageChanged(const QUrl &url);
- void newtabChanged(const QUrl &url);
+ void setSpellCheckEnabled(bool enable)
+ {
+ QWebEngineProfile::setSpellCheckEnabled(enable);
+ emit propertyChanged("spellCheckEnabed", enable);
+ }
- void propertyChanged(const QString &name, const QVariant &value);
- void attributeChanged(const QWebEngineSettings::WebAttribute attribute, const bool value);
- void headerChanged(const QString &name, const QString &value);
- void headerRemoved(const QString &name);
+ void setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor)
+ {
+ m_filters.append(interceptor);
+ }
protected:
// off-the-record constructor
- explicit WebProfile(const QString &name, QObject *parent = nullptr);
+ explicit WebProfile(const QString &id, QObject *parent = nullptr);
// default constructor
- explicit WebProfile(const QString &storageName, const QString &name, QObject *parent = nullptr);
+ explicit WebProfile(const QString &id, const QString &storageName, QObject *parent = nullptr);
-private:
+ const QString m_id;
QString m_name;
QString m_search = QString("about:blank");
QUrl m_homepage = QUrl("about:blank");
QUrl m_newtab = QUrl("about:blank");
+ QVector<QWebEngineUrlRequestInterceptor*> m_filters;
QVector<QNetworkCookie> m_cookies;
QMap<QByteArray, QByteArray> m_headers;
};
diff --git a/src/webengine/webprofilemanager.cpp b/src/webengine/webprofilemanager.cpp
index bdd10f0..785251b 100644
--- a/src/webengine/webprofilemanager.cpp
+++ b/src/webengine/webprofilemanager.cpp
@@ -7,28 +7,23 @@
*/
#include "webprofilemanager.h"
-#include "configuration.h"
#include "webprofile.h"
-#include <QFileInfo>
-#include <QWebEngineSettings>
-static WebProfileManager *s_instance = nullptr;
+static WebProfileManager<false> *s_instance = nullptr;
-auto WebProfileManager::instance() -> const WebProfileManager *
+template <>
+void WebProfileManager<false>::make_global()
{
- return s_instance;
-}
-void WebProfileManager::setInstance(WebProfileManager *ptr)
-{
- s_instance = ptr;
+ if(s_instance == nullptr) {
+ s_instance = this;
+ }
}
-WebProfileManager::WebProfileManager(QObject *parent)
- : QObject(parent)
-{
-}
+template <>
+WebProfileManager<true>::~WebProfileManager() = default;
-WebProfileManager::~WebProfileManager()
+template <>
+WebProfileManager<false>::~WebProfileManager()
{
for(Profile p : qAsConst(profiles)) {
if(p.selfDestruct && p.settings != nullptr) {
@@ -48,111 +43,30 @@ WebProfileManager::~WebProfileManager()
}
}
-WebProfile *WebProfileManager::profile(const QString &id) const
+template <>
+WebProfile *WebProfileManager<true>::profile(const QString &id) const
{
- // Check if profile exists
- if(profiles.contains(id)) {
- return profiles.value(id).ptr;
- }
-
- return nullptr;
+ return s_instance->profile(id);
}
-WebProfile *WebProfileManager::add(const QString &id, const QString &path, bool isOffTheRecord)
+template <>
+QStringList WebProfileManager<true>::idList() const
{
- if(profiles.contains(id)) {
- return nullptr;
- }
-
- Configuration conf;
- Profile profile;
-
- if(!path.isEmpty())
- profile.settings = new QSettings(path, QSettings::IniFormat);
- else
- profile.settings = new QSettings;
+ return s_instance->idList();
+}
- // QWebEngineCore cleans up profiles automatically, so no need to set parent
- if(profile.settings->value("otr", isOffTheRecord).toBool()) {
- // name parent
- profile.ptr = new WebProfile(profile.settings->value("name", id).toString(), nullptr);
- } else {
- // storageName name parent
- profile.ptr = new WebProfile(id, profile.settings->value("name", id).toString(), nullptr);
+template <>
+void WebProfileManager<false>::walk(std::function<void(const QString &id, WebProfile *profile, const QSettings *settings)> f) const
+{
+ for(auto iter = profiles.begin(); iter != profiles.end(); ++iter) {
+ f(iter.key(), iter.value().ptr, iter.value().settings);
}
-
- profile.settings->setParent(profile.ptr);
-
- connect(profile.ptr, &WebProfile::nameChanged, profile.settings, [profile](const QString &name) {
- profile.settings->setValue("name", name);
- });
-
- profile.ptr->setSearch(profile.settings->value("search", conf.value<QString>("profile.search").value()).toString());
- connect(profile.ptr, &WebProfile::searchChanged, profile.settings, [profile](const QString &url) {
- profile.settings->setValue("search", url);
- });
-
- profile.ptr->setHomepage(profile.settings->value("homepage", conf.value<QString>("profile.homepage").value()).toUrl());
- connect(profile.ptr, &WebProfile::homepageChanged, profile.settings, [profile](const QUrl &url) {
- profile.settings->setValue("homepage", url);
- });
-
- profile.ptr->setNewtab(profile.settings->value("newtab", conf.value<QString>("profile.newtab").value()).toUrl());
- connect(profile.ptr, &WebProfile::newtabChanged, profile.settings, [profile](const QUrl &url) {
- profile.settings->setValue("newtab", url);
- });
-
- if(profile.settings != nullptr) {
- profile.settings->beginGroup("properties");
- {
- const auto keys = profile.settings->childKeys();
- for(const QString &key : keys) {
- profile.ptr->setProperty(qUtf8Printable(key), profile.settings->value(key));
- }
- }
- profile.settings->endGroup(); // properties
- connect(profile.ptr, &WebProfile::propertyChanged, [profile](const QString &property, const QVariant &value) {
- profile.settings->setValue("properties/" + property, value);
- });
-
- profile.settings->beginGroup("attributes");
- {
- const auto keys = profile.settings->childKeys();
- auto *settings = profile.ptr->settings();
- for(const QString &key : keys) {
- auto attribute = static_cast<QWebEngineSettings::WebAttribute>(key.toInt());
- settings->setAttribute(attribute, profile.settings->value(key).toBool());
- }
- }
- profile.settings->endGroup();
- connect(profile.ptr, &WebProfile::attributeChanged, [profile](const QWebEngineSettings::WebAttribute attr, const bool value) {
- profile.settings->setValue("attributes/" + QString::number(attr), value);
- });
-
- // headers
- profile.settings->beginGroup("headers");
- for(const QString &key : profile.settings->childKeys()) {
- profile.ptr->setHttpHeader(key.toLatin1(), profile.settings->value(key).toString().toLatin1());
- }
- profile.settings->endGroup();
- connect(profile.ptr, &WebProfile::headerChanged, [profile](const QString &name, const QString &value) {
- profile.settings->setValue("headers/" + name, value);
- });
- connect(profile.ptr, &WebProfile::headerRemoved, [profile](const QString &name) {
- profile.settings->remove("headers/" + name);
- });
-
- } // profile.settings != nullptr
-
- profiles[id] = profile;
- return profile.ptr;
}
-void WebProfileManager::deleteProfile(const QString &id)
+template <>
+void WebProfileManager<true>::walk(std::function<void(const QString &id, WebProfile *profile, const QSettings *settings)> f) const
{
- if(profiles.contains(id)) {
- profiles[id].selfDestruct = true;
- }
+ s_instance->walk(f);
}
void profileMenu(QMenu *menu, const std::function<void(WebProfile *)> &callback, WebProfile *current, bool checkable)
@@ -160,13 +74,10 @@ void profileMenu(QMenu *menu, const std::function<void(WebProfile *)> &callback,
auto *group = new QActionGroup(menu);
QObject::connect(menu, &QMenu::aboutToHide, group, &QActionGroup::deleteLater);
- for(const auto &profile : qAsConst(s_instance->profiles)) {
- auto *action = menu->addAction(profile.ptr->name(), profile.ptr, [profile, callback]() {
- callback(profile.ptr);
- });
+ s_instance->walk([=](const QString &, WebProfile *profile, const QSettings *) {
+ auto *action = menu->addAction(profile->name(), profile, [=]() { callback(profile); });
action->setCheckable(checkable);
- if(profile.ptr == current)
- action->setChecked(true);
+ action->setChecked(profile == current);
group->addAction(action);
- }
+ });
}
diff --git a/src/webengine/webprofilemanager.h b/src/webengine/webprofilemanager.h
index 0e18d5f..22fb31c 100644
--- a/src/webengine/webprofilemanager.h
+++ b/src/webengine/webprofilemanager.h
@@ -9,63 +9,97 @@
#ifndef SMOLBOTE_WEBPROFILEMANAGER_H
#define SMOLBOTE_WEBPROFILEMANAGER_H
+#include "singleton.hpp"
#include "webprofile.h"
#include <QDir>
#include <QFile>
+#include <QFileInfo>
#include <QMap>
#include <QMenu>
-#include <QObject>
-#include <QSettings>
#include <functional>
void profileMenu(QMenu *menu, const std::function<void(WebProfile *)> &callback, WebProfile *current = nullptr, bool checkable = false);
-class Browser;
-class WebProfileManager : public QObject
+template <bool use_global = true>
+class consumable(unconsumed) WebProfileManager
{
- Q_OBJECT
-
- friend class Browser;
- friend void profileMenu(QMenu *, const std::function<void(WebProfile *)> &, WebProfile *current, bool);
-
public:
- explicit WebProfileManager(QObject *parent);
- ~WebProfileManager() override;
+ return_typestate(unconsumed) WebProfileManager()
+ {
+ static_assert(use_global);
+ }
+ return_typestate(unconsumed) WebProfileManager(const QStringList &paths, const QString &default_id,
+ const QString &search = QString(), const QUrl &homepage = QUrl(), const QUrl &newtab = QUrl())
+ {
+ static_assert(!use_global);
+ for(const auto &path : paths) {
+ const auto id = QFileInfo(path).baseName();
+ Profile profile;
+ profile.settings = WebProfile::load(path, search, homepage, newtab);
+ profile.ptr = WebProfile::load(id, profile.settings, true);
+ profiles[id] = profile;
+ }
- static auto instance() -> const WebProfileManager *;
- static void setInstance(WebProfileManager *ptr);
+ if(!profiles.contains(default_id)) {
+ Profile profile;
+ profile.settings = WebProfile::load(QString(), search, homepage, newtab);
+ profile.ptr = WebProfile::load(default_id, profile.settings, true);
+ profiles[default_id] = profile;
+ }
+ WebProfile::setDefaultProfile(profiles[default_id].ptr);
+ }
+ ~WebProfileManager();
- /** Create a profile with specified id
- * param id The profile ID
- * return WebProfile* The profile, or nullptr if one could not be created
- */
- WebProfile *profile(const QString &id) const;
+ WebProfileManager(const WebProfileManager &) = delete;
+ WebProfileManager &operator=(const WebProfileManager &) = delete;
- /** Set a profile for deletion
- * param id The profile ID
- * return void
- */
- [[deprecated]] void deleteProfile(const QString &id);
+ return_typestate(unconsumed) WebProfileManager(WebProfileManager<false> && other param_typestate(unconsumed))
+ {
+ static_assert(!use_global);
+ profiles = std::move(other.profiles);
+ other.consume();
+ }
+ WebProfileManager &operator=(WebProfileManager &&) = delete;
- const QStringList idList() const
+ callable_when(unconsumed) [[nodiscard]] WebProfile *profile(const QString &id) const
{
- return profiles.keys();
+ return profiles.value(id).ptr;
+ }
+
+ callable_when(unconsumed) void add(const QString &id, WebProfile *profile, QSettings *settings)
+ {
+ if constexpr(use_global) {
+ return;
+ }
+
+ if(profile != nullptr && settings != nullptr) {
+ profiles[id] = Profile{ profile, settings, false };
+ }
}
- QString id(WebProfile *profile) const
+
+ callable_when(unconsumed) void deleteProfile(const QString &id)
{
- QMapIterator<QString, Profile> i(profiles);
- while(i.hasNext()) {
- i.next();
- if(i.value().ptr == profile)
- return i.key();
+ if constexpr(use_global) {
+ return;
+ }
+
+ if(profiles.contains(id)) {
+ profiles[id].selfDestruct = true;
}
- return QString();
}
-protected:
- WebProfile *add(const QString &id, const QString &path = QString(), bool isOffTheRecord = true);
+ callable_when(unconsumed) [[nodiscard]] QStringList idList() const
+ {
+ return profiles.keys();
+ }
+
+ callable_when(unconsumed) void walk(std::function<void(const QString &id, WebProfile *profile, const QSettings *settings)>) const;
+
+ callable_when(unconsumed) void make_global();
private:
+ set_typestate(consumed) void consume() {}
+
struct Profile {
WebProfile *ptr = nullptr;
QSettings *settings = nullptr;
diff --git a/src/webengine/webview.cpp b/src/webengine/webview.cpp
index c64333e..135f25c 100644
--- a/src/webengine/webview.cpp
+++ b/src/webengine/webview.cpp
@@ -7,20 +7,16 @@
*/
#include "webview.h"
-#include "subwindow/subwindow.h"
#include "webpage.h"
#include "webprofile.h"
#include "webprofilemanager.h"
#include "webviewcontextmenu.h"
#include <QContextMenuEvent>
-#include <QJsonObject>
#include <QWebEngineHistoryItem>
WebView::WebView(QWidget *parent)
: QWebEngineView(parent)
{
- m_parentWindow = qobject_cast<SubWindow *>(parent);
-
// load status and progress
connect(this, &QWebEngineView::loadStarted, this, [this]() {
m_loaded = false;
@@ -37,21 +33,22 @@ WebView::WebView(QWidget *parent)
});
}
-WebView::WebView(WebProfile *profile, QWidget *parent)
+WebView::WebView(WebProfile *profile, cb_createWindow_t cb, QWidget *parent)
: WebView(parent)
{
+ cb_createWindow = cb;
Q_CHECK_PTR(profile);
m_profile = profile;
setPage(new WebPage(profile, this));
}
-WebView::WebView(const Session::WebView &data, QWidget *parent)
+WebView::WebView(const Session::WebView &data, cb_createWindow_t cb, QWidget *parent)
: WebView(parent)
{
- const auto *profileManager = WebProfileManager::instance();
- Q_CHECK_PTR(profileManager);
+ cb_createWindow = cb;
+ WebProfileManager profileManager;
- auto *profile = profileManager->profile(data.profile);
+ auto *profile = profileManager.profile(data.profile);
if(profile != nullptr) {
setProfile(profile);
}
@@ -75,19 +72,11 @@ void WebView::setProfile(WebProfile *profile)
Session::WebView WebView::serialize() const
{
- const auto *profileManager = WebProfileManager::instance();
- Q_CHECK_PTR(profileManager);
-
QByteArray historyData;
QDataStream historyStream(&historyData, QIODevice::WriteOnly);
historyStream << *history();
- return { profileManager->id(profile()), QString(), historyData };
-}
-
-bool WebView::isLoaded() const
-{
- return m_loaded;
+ return { profile()->getId(), QString(), historyData };
}
void WebView::search(const QString &term)
@@ -96,35 +85,6 @@ void WebView::search(const QString &term)
load(searchUrl);
}
-WebView *WebView::createWindow(QWebEnginePage::WebWindowType type)
-{
- Q_CHECK_PTR(m_parentWindow);
-
- // parent Window has been found
- auto index = m_parentWindow->addTab();
- WebView *view = m_parentWindow->view(index);
- switch(type) {
- case QWebEnginePage::WebBrowserWindow:
- // a complete web browser window
- break;
-
- case QWebEnginePage::WebBrowserTab:
- // a web browser tab
- m_parentWindow->setCurrentTab(index);
- break;
-
- case QWebEnginePage::WebDialog:
- // a window without decorations
- break;
-
- case QWebEnginePage::WebBrowserBackgroundTab:
- // a web browser tab, but don't swap to it
- break;
- }
-
- return view;
-}
-
void WebView::contextMenuEvent(QContextMenuEvent *event)
{
auto *menu = new WebViewContextMenu(this);
diff --git a/src/webengine/webview.h b/src/webengine/webview.h
index 5748691..a9c6866 100644
--- a/src/webengine/webview.h
+++ b/src/webengine/webview.h
@@ -11,10 +11,10 @@
#include "webpage.h"
#include <QWebEngineView>
+#include <functional>
#include <session.hpp>
class WebProfile;
-class SubWindow;
class WebViewContextMenu;
class WebView final : public QWebEngineView
{
@@ -25,8 +25,10 @@ class WebView final : public QWebEngineView
explicit WebView(QWidget *parent = nullptr);
public:
- explicit WebView(WebProfile *profile = nullptr, QWidget *parent = nullptr);
- explicit WebView(const Session::WebView &data, QWidget *parent = nullptr);
+ typedef std::function<WebView *(QWebEnginePage::WebWindowType)> cb_createWindow_t;
+
+ WebView(WebProfile *profile, cb_createWindow_t cb, QWidget *parent = nullptr);
+ WebView(const Session::WebView &data, cb_createWindow_t cb, QWidget *parent = nullptr);
~WebView() = default;
[[nodiscard]] WebProfile *profile() const
@@ -37,7 +39,10 @@ public:
[[nodiscard]] Session::WebView serialize() const;
- bool isLoaded() const;
+ bool isLoaded() const
+ {
+ return m_loaded;
+ }
public slots:
void search(const QString &term);
@@ -46,11 +51,14 @@ signals:
void newBookmark(const QString &title, const QUrl &url);
protected:
- WebView *createWindow(QWebEnginePage::WebWindowType type) override;
+ WebView *createWindow(QWebEnginePage::WebWindowType type) override
+ {
+ return cb_createWindow ? cb_createWindow(type) : nullptr;
+ }
void contextMenuEvent(QContextMenuEvent *event) override;
private:
- SubWindow *m_parentWindow = nullptr;
+ cb_createWindow_t cb_createWindow;
WebProfile *m_profile = nullptr;
bool m_loaded = false;
diff --git a/src/webengine/webviewcontextmenu.cpp b/src/webengine/webviewcontextmenu.cpp
index 856ff9c..1f6b337 100644
--- a/src/webengine/webviewcontextmenu.cpp
+++ b/src/webengine/webviewcontextmenu.cpp
@@ -7,7 +7,6 @@
*/
#include "webviewcontextmenu.h"
-#include "wallet/wallet.h"
#include "webprofilemanager.h"
#include "webview.h"
#include <QContextMenuEvent>
@@ -216,6 +215,7 @@ WebViewContextMenu::WebViewContextMenu(WebView *view)
}
#ifndef NDEBUG
+ /*
{
this->addSeparator();
auto *autofillAction = this->addAction(tr("Autofill form"));
@@ -223,5 +223,6 @@ WebViewContextMenu::WebViewContextMenu(WebView *view)
Wallet::autocompleteForm(view);
});
};
+ */
#endif
}